←前回「Pythonでスクレイピング(メモ2:コード作成)」
こんばんは。最近続けているPythonシリーズ(ただのメモ)です。
今回はいよいよ(ようやく笑)スクレイピング実行します。
スクレイプ対象は1ページのみです。
※動作環境
macOS High Sierra 10.13.6
プロセッサ 2.7 GHz Intel Core i5
メモリ 8 GB 1867 MHz DDR3
Python 3.6.0 :: Anaconda custom (x86_64)
コマンド実行は「ターミナル」、.py編集は「Xcode」を使用
※参考文献「Python エンジニア ファーストブック」(142ページ以降中心)
※参考URL
https://note.nkmk.me/python-scrapy-tutorial/
以下試行錯誤メモ。
前回制作した雛形ファイルの中身。
# -*- coding: utf-8 -*- import scrapy class <ファイル名>Spider(scrapy.Spider): name = '<ファイル名>' allowed_domains = ['<ドメイン>'] start_urls = ['<WebサイトのURL(大抵はホーム)>'] def parse(self, response): pass
この中のparseを適当なコードにすることでスクレイピングが可能。
例えばJRA公式HPの2018年の重賞レースの1年間の「日付(date)・開催場所(place)・レース名(race)」をスクレイプする。
スクレイプする前にちゃんとJRA公式HPのrobots.txt(http://www.jra.go.jp/robots.txt)を確認する。
User-agent: * Disallow:
スクレイプしても大丈夫そう。データの利用についての注も探しても特に無い。
この辺が何となく怖いから前回までは伏せていたけど、面倒になった笑
ではスクレイプする準備。
参考文献によれば設定しなくても良いらしいが、items.pyというファイルに先程挙げた3つの項目を書き加える。
# -*- coding: utf-8 -*- # Define here the models for your scraped items # # See documentation in: # https://doc.scrapy.org/en/latest/topics/items.html import scrapy class KeibaScraperItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() date = scrapy.Field() race = scrapy.Field() place = scrapy.Field() pass
イメージとしては、この3項目をこれからスクレイプするという宣言というか、スクレイプした情報を入れるための「箱」のようなものかな。
このファイルを雛形ファイルにimportする必要があるので、3行目に以下を加える。
from keiba_scraper.items import KeibaScraperItem
keiba_scraperというフォルダの中にあるitems.pyをKeibaScraperItemという名前でimportするという意味かな。
ドメインはjra.go.jp、サイトのURLはhttp://www.jra.go.jp/datafile/seiseki/replay/2018/jyusyo.htmlとする。
このページから先の3項目をスクレイプするためには、ページのソース、つまりhtmlのコードを確認せねばならない。
欲しい情報がどのタグ内の箇所にあるかが重要で、繰り返しの場合はそれの最小単位を見出す必要がある。
上記ページのソースの一部が下記。
・・・ <thead> <tr> <th scope="col">月日</th> <th scope="col">レース名</th> <th scope="col">競馬場</th> <th scope="col">性齢</th> <th scope="col">コース</th> <th scope="col">優勝馬</th> <th scope="col">騎手</th> <th scope="col">結果</th> </tr> </thead> <tbody class="td_left"> <tr> <td class="date">1月6日<span class="sat">土曜</span></td> <td class="race"><span class="grade_icon g3">GⅢ</span>中山金杯</td> <td class="place">中山</td> <td class="age">4歳以上</td> <td class="course"><span class="type">芝</span>2,000<span class="unit">メートル</span></td> <td class="winner">セダブリランテス</td> <td class="jockey">戸崎 圭太</td> <td class="result"><a href="/datafile/seiseki/replay/2018/001.html" class="btn-def btn-xs"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i>レース結果</a></td> </tr> <tr> <td class="date">1月6日<span class="sat">土曜</span></td> <td class="race"><span class="grade_icon g3">GⅢ</span>京都金杯</td> <td class="place">京都</td> <td class="age">4歳以上</td> <td class="course"><span class="type">芝</span>1,600<span class="unit">メートル</span></td> <td class="winner">ブラックムーン</td> <td class="jockey">武 豊</td> <td class="result"><a href="/datafile/seiseki/replay/2018/002.html" class="btn-def btn-xs"><i class="fa fa-chevron-circle-right" aria-hidden="true"></i>レース結果</a></td> </tr> <tr> <td class="date">1月7日<span class="sun">日曜</span></td> ・・・
なるほど。
とりあえずレースごとに<tr>タグの繰り返しになっている。
そのタグ内において、日付は<td class=”date“>、開催場所は<td class=”place“>、レース名は<td class=”race“>の中にある。
以上の繰り返し。
繰り返しはforを使えばOK。
あとは参考文献等から見よう見まねでつくるとこうなる。
・・・ class KeibaSpider(scrapy.Spider): name = 'keiba' allowed_domains = ['jra.go.jp'] start_urls = ['http://www.jra.go.jp/datafile/seiseki/replay/2018/jyusyo.html'] def parse(self, response): for keiba in response.css('tr'): item = KeibaScraperItem() item['date'] = keiba.css('td.date::text').extract_first() item['race'] = keiba.css('td.race::text').extract_first() item['place'] = keiba.css('td.place::text').extract_first() yield item
なるほど、for文を使い<tr>タグごとに先程見出した各<td>タグ内のテキスト情報を記録しているのだろう。
このkeiba.pyをターミナルで実行。
scrapy crawl keiba
何事もなく成功。結果の一部が下記。
{'date': None, 'place': None, 'race': None} {'date': '1月6日', 'place': '中山', 'race': '中山金杯'} {'date': '1月6日', 'place': '京都', 'race': '京都金杯'} ・・・
最初は凡例の所なのでそもそも<td>タグが無いので結果はNoneになっている。
と、ここまで順風満帆に見えるが本当はいろいろ試行錯誤した。
例えば上記のタグで本当に上手くいくのかを事前に確認する為の作業とか。
それは次回に譲る。