Pythonでスクレイピング(メモ6:クロールが出来るまで)

Pythonでスクレイピング(メモ5:クロール下準備)

こんばんは。

Pythonでスクレイピングするまでの試行錯誤メモです。

今回は、あるページ内の全てのリンク先でスクレイピングを行う「クロール」奮闘メモです。

<この記事の目次>

クロール実行コードの書き方・・・コードの書き方が分からない

詰まったらprint関数で挙動確認・・・実際にスクレイプで得た値を見てみると良い

リンク先URLを正規の形で渡す・・・URLはhttp(s):〜の形でないと駄目みたい

値をcsvで出力・・・説明不要

出力したcsvのExcelでの開き方・・・普通に開くと文字化けする・同一セル内に値が詰められている

指定のリンク先がない場合の条件分岐・・・リンク先が無くてErrorが返ることも

※動作環境

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ページ以降中心)

以下試行錯誤メモ。

クロール実行コードの書き方

さっぱり分からないのでGoogleで「scrapy クロール」検索。

いろいろ見ましたが

https://note.nkmk.me/python-scrapy-tutorial/

が一番参考になりました。

その中でクロールに関するコードを一部抽出すると以下。

def parse(self, response):
        for文
                        ・・・(略)
            yield scrapy.Request(名前.css(htmlタグ).extract(),
                                 callback=self.parse_detail,
                                 meta={'item': item})

    def parse_detail(self, response):
        リンク先でのスクレイプコード
        yield item

同ページにも説明があり何となくは分かりますが、meta={‘item’ : item}の部分はよく分かりません笑

とりあえずそのまま使わせていただきます。

リンク先でのコードは前回用意できたので、リンク先を含むタグを指定するだけでできそうです。

ソースを確認。

<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>

<td class=”result“>の<a href>にあります。

であればリンク先の部分は以下で良さそう。

yield scrapy.Request(keiba.css('td.result a::attr(href)').extract(),

だがしかし!実行すると以下のエラーが・・・

TypeError: Request url must be str or unicode, got list:

URLが文字列ではなくリストで渡っているらしい。

なぜなのか、調べど調べど原因が分からず・・・

詰まったらprint関数で挙動確認

ある友人のアドバイスでprint関数を使って実際に何を渡しているのか確認することに。

デバッグモード(scrapy shell)にて。

In [1]: page = response.css('td.result a::attr(href)').extract()
In [2]: print(page)

リストの中にリンク先が多数入っているのが返ってくる。

なるほど確かにリストを渡していたわけか。

とりあえず.extract_first()にしてみる。

In [3]: page = response.css('td.result a::attr(href)').extract_first()
In [4]: print(page)
/datafile/seiseki/replay/2018/001.html

リストでは無くなったからとりあえずコードを書き直してクロール実行すると次なるErrorが。

TypeError:Request url must be str or unicode, got NoneType:

始めはリンク先がない(時がある)からErrorが出てると考えてましたが違ったみたいです。

先の結果にhttp://www.jra.go.jpがついてないのが原因でした。

リンク先URLを正規の形で渡す

ソースで得られる文字列に上記のhttp://www.jra.go.jpを追加するには、response.urljoinを使えば良いらしい。

参考:http://toriaezu-engineer.hatenablog.com/?page=1476360360#Parse-%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%81%AB%E3%82%88%E3%82%8B%E3%83%87%E3%83%90%E3%83%83%E3%82%B0

ってことでデバッグしてみると・・・

In [5]: page = response.urljoin(response.css('td.result a::attr(href)').extract_first())
In [6]: print(page)
http://www.jra.go.jp/datafile/seiseki/replay/2018/001.html

ついにこれでクロールコードも完成か・・・

コードを書き換えて実行すると・・・

Errorが出ないで各ページでスクレイピングしている!!

量が多いので時間はかかるがついに成功!!

値をcsvで出力

ようやくコードも出来た所で、得た値をcsvファイルで出力していきます。

scrapy crawl <.pyのファイル名> -o <出力する際のファイルの名前>.csv

はい参考文献通りこれで終わり。

出力したcsvのExcelでの開き方

ところがExcelで開くと文字化けする。ググる。

参考:https://global-wing.com/activity/csv_character_code.html

(Excelにて)
データ > 外部データの取り込み > テキスト ファイルのインポート

その後、Unicode(UTF−8)を選べば文字化けも解消(プレビューで確認できる)。

その他は必要に応じて設定すればOK。

指定のリンク先がない場合の条件分岐

結局関係無かったみたいだがおまけ。

リンク先が取得出来たときのみクロールさせるためには。

参考:https://stackoverflow.com/questions/40105949/scrapy-request-url-must-be-str-or-unicode-got-nonetype

当然if文を使えばいい。存在する時のみurljoinを実行する。

page = keiba.css('td.result a::attr(href)').extract_first()
if page:
   page = response.urljoin(page)
   yield scrapy.Request(page, callback=self.parse_detail, meta={'item': item})

「if page:」と書くだけ。

ようやくクロール出来たので、次は2017年を実行だ!

ということで、start_urlsの2018を2017に変えて実行するだけ。楽ちん。

ところが!

一部しか出力されず・・・挙動見るとクロールは出来ている。

そこで一部ページを確認すると・・・ソースが最近のページと全然違う!!

なんかalignとかいろいろ細かいタグになっている・・・

次回は色々なcssクラスタの書き方についてまとめます。

→次回「Pythonでスクレイピング(メモ7:色々なソースに対応する)」

シェアする

  • このエントリーをはてなブックマークに追加

フォローする