Scrapyのカスタマイズとして、dupefilterからSpiderにアクセスする拡張を加えました。
実装にあたって検索した時は、日本語の記事が見当たらなかったので、後の人のために書き残しておきます。
「もっと楽な方法あるよ!」って方がいたらこっそり教えて下さい…
課題
Scrapyでクロールする際、重複したアイテムを除外するため、RFPDupeFilter
を継承した独自フィルタを作ることがあります。
参考 : Scrapyドキュメント
ですが、RFPDupeFilter
からはSpiderにアクセスすることができません。
つまり、スパイダーしか知り得ない情報を元に重複除外したい場合に対応できないことになります。
対応
ScrapyのGitHub Issueに類似の記載がありました。
今回はこちらのIssue内容の通りに実装しています。
やったこと
- Schedulerを継承して
from_crawler
メソッドをオーバライド - 独自スケジューラをsettings.pyの
SCHEDULER
に登録 - dupefilter側で
self.spider
を好きにする
Schedulerを継承
dupefilterにspiderを差し込む部分以外は、元コードをまんまコピペしてます。
class CustomScheduler(Scheduler):
@classmethod
def from_crawler(cls, crawler):
settings = crawler.settings
dupefilter_cls = load_object(settings['DUPEFILTER_CLASS'])
dupefilter = create_instance(dupefilter_cls, settings, crawler)
dupefilter.spider = crawler.spider ### ここだけ追加 ###
pqclass = load_object(settings['SCHEDULER_PRIORITY_QUEUE'])
if pqclass is PriorityQueue:
warnings.warn("SCHEDULER_PRIORITY_QUEUE='queuelib.PriorityQueue'"
" is no longer supported because of API changes; "
"please use 'scrapy.pqueues.ScrapyPriorityQueue'",
ScrapyDeprecationWarning)
from scrapy.pqueues import ScrapyPriorityQueue
pqclass = ScrapyPriorityQueue
dqclass = load_object(settings['SCHEDULER_DISK_QUEUE'])
mqclass = load_object(settings['SCHEDULER_MEMORY_QUEUE'])
logunser = settings.getbool('SCHEDULER_DEBUG')
return cls(dupefilter, jobdir=job_dir(settings), logunser=logunser,
stats=crawler.stats, pqclass=pqclass, dqclass=dqclass,
mqclass=mqclass, crawler=crawler)
独自スケジューラを登録
settings.pyに独自スケジューラを登録します。
特定スパイダー限定にしたい場合は、スパイダークラスのcustom_settings
に書きます。
settings.py
SCHEDULER = 'crawling.scheduler.CustomScheduler'
dupefilter側でspiderを使う
あとは独自のdupefilter内でself.spider
を触れますので、好きに情報抜き取ります。
以上!