[Scrapy]特定タグ内の要素を取得するための練習
Pythonで使えるスクレイピングフレームワークのScrapy。
このScrapyを使って特定タグ内のリンクやテキストを取得する方法をまとめました。
下準備
まずはscrapyを使うための下準備です。なお、スクレイピングは行儀よく行いましょう。
pip install scrapy scrapy version => scrapy x.x.x
scrapyでシンタックスエラーが発生した時はこちらの記事を参照してください。
[Python]Scrapyを動かした時にSyntaxError: invalid syntaxとエラーが出る場合の対処法
2018 年9月現在、Python3.7には対応していないようです。Python3.6で使いました。
scrapy shellの起動
スクリプトを組んで実行→検証を繰り返してもよいですが、shellの方がサッと確認できます。
今回はYahooニュースを使ってスクレイピングしていきます。
scrapy shell https://news.yahoo.co.jp/ [s] Available Scrapy objects: [s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc) [s] crawler <scrapy.crawler.Crawler object at 0x10b7fba90> [s] item {} [s] request <GET https://news.yahoo.co.jp/> [s] response <200 https://news.yahoo.co.jp/> [s] settings <scrapy.settings.Settings object at 0x10c3ce780> [s] spider <DefaultSpider 'default' at 0x10c671b70> [s] Useful shortcuts: [s] fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed) [s] fetch(req) Fetch a scrapy.Request and update local objects [s] shelp() Shell help (print this help) [s] view(response) View response in a browser In [1]:
こんな感じでshellが起動します。
titleを抜き出す
まず、手始めにYahooニュースのtitleを抜き出してみます。
In [1]: response.css('title') Out[1]: [<Selector xpath='descendant-or-self::title' data='<title>Yahoo!ニュース</title>'>]
次にextract()関数を使い、タグを含む文字列を抽出してみます。
In [2]: response.css('title').extract() Out[2]: ['<title>Yahoo!ニュース</title>']
タグも消去して、中のテキストだけを抜き出します。その場合は、titleタグの後ろに::textと書きます。
In [3]: response.css('title::text').extract() Out[3]: ['Yahoo!ニュース']
ニュース一覧のタイトルをテキストで抜き出す
次にニュース一覧のタイトルを取得していきます。
一覧のタイトル部分がどういったタグで囲まれているのかChrome→右クリック→検証で調べて行きます。ctrl + Fでタイトルを入れて検索すると目的のタグを探しやすいです。
In [4]: response.css('ul.topics a::text').extract() Out[4]: ['強制不妊「57年苦しんだ」', '台風 沖縄に特別警報級の雨か', '終値 323円高の2万4120円', '排ガス不正 アウディでも発覚', 'フェイクファーは死語 新潮流', '阪神Wヘッダー?ぼやく関係者', 'いしだ壱成&飯村貴子に第1子', '志水さん死去 山西惇が悼む', 'もっと見る', '全カテゴリのトピックス一覧']
ulタグのtopicsクラスの場合は、(‘ul.topics’)とします。ここではaタグ内のテキストを取得するのでa::textとしました。
ニュース一覧のリンクを抜き出す
上記の発展形で、今度はニュース一覧のタイトルではなく、リンクURLを抜き出します。
In [5]: response.css('ul.topics a::attr("href")').extract() Out[5]: ['https://news.yahoo.co.jp/pickup/6298311', 'https://news.yahoo.co.jp/pickup/6298323', 'https://news.yahoo.co.jp/pickup/6298317', 'https://news.yahoo.co.jp/pickup/6298305', 'https://news.yahoo.co.jp/pickup/6298313', 'https://news.yahoo.co.jp/pickup/6298315', 'https://news.yahoo.co.jp/pickup/6298319', 'https://news.yahoo.co.jp/pickup/6298324', 'https://news.yahoo.co.jp/list/', 'https://news.yahoo.co.jp/topics']
a::attr()に注目してください。先ほどはテキストの抽出だったのでa::textとしました。
まとめ
scrapyを使えば簡単にスクレイピングを行うことができます。
さらにshellコマンドを使えば、すぐに結果を確認できるのでまずはタグを読み込んで結果をすぐに確認したい時には便利です。