scrapy crawlコマンドでスパイダーに引数を渡す
Pythonのスクレイピング・クローリングフレームワークScrapyで、scrapy crawlコマンドでクローリングを実行する際にスパイダーに引数を渡す方法について、以下の内容を説明する。
scrapy crawlコマンドの書き方- スパイダースクリプトのサンプル
- スパイダースクリプトの書き方・注意点
Scrapyの基本的な使い方は以下の記事を参照。
公式ドキュメントの説明は以下。
scrapy crawlコマンドの書き方
scrapy crawlコマンドから引数を渡すには-aオプションを使う。
以下のように引数名=値の形で指定する。複数指定する場合は-aから繰り返す。
$ scrapy crawl <spider-name> -a <arg1>=<val1> -a <arg2>=<val2>
スパイダースクリプトのサンプル
scrapy crawlコマンドで指定した引数を受け取る側のスパイダースクリプト(spidersディレクトリのスクリプト)のサンプルを示す。
例としてYahoo! Japanの検索結果をスクレイピングする。
プロジェクトの作成など基本的な部分は以下の記事を参照。
プロジェクトのリポジトリは以下。
以下のように、
- 検索ワード
query - 取得する検索順位
rank - 結果に付与する
comment
を引数として渡すものとする。スペースを含む文字列を指定する場合は引用符で囲む。
$ scrapy crawl search_args -a query=python -a rank=4 -a comment="test crawl"
例では引数の説明のため、指定した検索順位(0始まり)のタイトルとURLのみを取得している。ページ内のすべての順位の結果を取得するサンプルは以下の記事を参照。
コードを示す。
# -*- coding: utf-8 -*-
import scrapy
class SearchArgsSpider(scrapy.Spider):
name = 'search_args'
allowed_domains = ['yahoo.co.jp']
def __init__(self, query='', rank=0, *args, **kwargs):
super(SearchArgsSpider, self).__init__(*args, **kwargs)
self.start_urls = ['https://search.yahoo.co.jp/search?p=' + query]
self.rank = int(rank)
def parse(self, response):
w = response.css('div#WS2m div.w')[self.rank]
d = {}
d['rank'] = self.rank
d['comment'] = self.comment
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
スパイダースクリプトの書き方・注意点
コマンドライン引数は__init__()に対するキーワード引数としてアクセスできる。
初期値を指定
初期値を指定したい場合は__init__()でデフォルト引数を定義する。
文字列と数値の扱い
コマンドライン引数はすべて文字列として渡されるので、数値として扱いたい場合はint()やfloat()などで変換する。
例ではrankをint()で整数に変換している。
self.<引数名>に格納、取得
コマンドライン引数をすべて__init__()のキーワード引数として処理する必要はない。例ではcommentは__init__()で処理していないが、self.commentに値が格納される。
*args, **kwargsをデフォルトの__init__()で処理する以下のコードが必要なので注意。
super(SearchArgsSpider, self).__init__(*args, **kwargs)
*args, **kwargsについては以下の記事を参照。
なお、コマンドライン引数として指定されていない場合はself.<引数名>は未定義となる。省略される可能性がある場合は__init__()のキーワード引数として処理しておくほうが無難。例のようにクラス内のメソッドでself.commentを使っているのに、scrawl crawlで-a comment=xxxのような指定がないとエラーになる。
また、__init__()でキーワード引数として処理する場合、クラス内の他のメソッドで使うには明示的にself.<引数名> = <引数名>のように定義しておく必要がある。例ではqueryをself.queryに格納していないので、self.queryは未定義になり、クラスの他のメソッドでは使えない。