ScrapyでURLが既知の複数のページをスクレイピング
Pythonのスクレイピング・クローリングフレームワークScrapyでURLが既知の複数のページをスクレイピングする方法について説明する。
Scrapyの基本的な使い方、ページ内のリンク(事前に分からないURL)をクロールする方法については以下の記事を参照。
ここでは以下の内容について説明する。
- 例: Yahoo! Japanの検索結果をスクレイピング
start_urls
に複数のURLを指定start_requests()
を使用してURLを動的に指定
scrapy crawl
コマンドから引数を渡してURLを制御したり、別のスクリプトからScrapyの処理を呼び出したりしたい場合は以下の記事を参照。
例: Yahoo! Japanの検索結果をスクレイピング
例としてYahoo! Japanの検索結果をスクレイピングする。
まず、単独のページに対してスクレイピングするスパイダーのコードを示す。「python」という検索ワードの1ページ目から各順位のタイトルとURLを抽出している。
# -*- coding: utf-8 -*-
import scrapy
class SearchSingleSpider(scrapy.Spider):
name = 'search_single'
allowed_domains = ['yahoo.co.jp']
start_urls = ['https://search.yahoo.co.jp/search?p=python']
def parse(self, response):
for i, w in enumerate(response.css('div#WS2m div.w')):
d = {}
d['rank'] = i
d['title'] = w.css('h3 a').xpath('string()').extract_first()
d['url'] = 'https://' + w.css('div.a span.u').xpath('string()').extract_first()
yield d
ここではitems.py
は使わずにただの辞書(dict
型オブジェクト)に結果を格納している。enumerate()
でインデックスを取得し検索順位rank
としている(0始まり)。
Scrapyプロジェクトの作成など基本的な部分は以下の記事を参照。
プロジェクトのリポジトリは以下。
start_urlsに複数のURLを指定
start_urls
には複数のURLを指定できる。
例えば複数の検索ワードを一括で処理したい場合は以下のように指定する。
# -*- coding: utf-8 -*-
import scrapy
class SearchMultiSpider(scrapy.Spider):
name = 'search_multi'
allowed_domains = ['yahoo.co.jp']
start_urls = ['https://search.yahoo.co.jp/search?p=python',
'https://search.yahoo.co.jp/search?p=ruby']
# start_urls = ['https://search.yahoo.co.jp/search?p=' + q for q in ['python', 'ruby']]
def parse(self, response):
for i, w in enumerate(response.css('div#WS2m div.w')):
d = {}
d['rank'] = i
d['title'] = w.css('h3 a').xpath('string()').extract_first()
d['url'] = 'https://' + w.css('div.a span.u').xpath('string()').extract_first()
yield d
例ではコメントアウトしているが、リスト内包表記でもOK。
- 関連記事: Pythonリスト内包表記の使い方
連番になったURL(https://example.com/1/
~ https://example.com/9/
など)を一気にスクレイピングしたい場合は以下のような書き方が可能。
start_urls = ['https://example.com/{}/'.format(str(i)) for i in range(1, 10)]
start_requests()を使用してURLを動的に指定
上の例のように、コード中にURLを決め打ちで記述するのではなく、例えば外部ファイルからURLのリストを読み込んでスクレイピングしたい場合などはstart_requests()
を使う。
デフォルト(start_requests()
を定義しない場合)ではscrapy.Request()
にstart_urls
の各URLが渡される。
ここでは検索ワードのリストを以下のようなテキストファイルから読み込んでスクレイピングする例を示す。
python
ruby
テキストファイルから読み込んだ検索ワードをベースとなるURLと連結し、scrapy.Request()
に指定する。
# -*- coding: utf-8 -*-
import scrapy
class SearchMultiRequestsSpider(scrapy.Spider):
name = 'search_multi_requests'
allowed_domains = ['yahoo.co.jp']
def start_requests(self):
with open('list.txt') as f:
for q in f:
yield scrapy.Request('https://search.yahoo.co.jp/search?p=' + q)
def parse(self, response):
for i, w in enumerate(response.css('div#WS2m div.w')):
d = {}
d['rank'] = i
d['title'] = w.css('h3 a').xpath('string()').extract_first()
d['url'] = 'https://' + w.css('div.a span.u').xpath('string()').extract_first()
yield d
この例の場合、テキストファイルlist.txt
はカレントディレクトリであるプロジェクトディレクトリ(scrapy.cfg
があるディレクトリ)に置いておく。別の場所に置く場合は適宜パスを指定する。
テキストファイルの読み込みについては以下の記事を参照。
scrapy crawl
コマンドから引数を渡してURLを制御したり、別のスクリプトからScrapyの処理を呼び出したりしたい場合は以下の記事を参照。