DISTRICT 37

なにか

Scrapyのコツ

Scrapyを作ってていくつかコツをつかんだ気がする。といっても処理側の話なので、xpathをマスターしないことにはScrapyが作れないことには変わりない。

Spiderのコツ

itemをitemクラスに格納する際にはyieldをうまく使うといい。

前回やったRSSのようにデータが繰り返しの構造になっている場合には、forループを回している最中で処理がyieldに到達するとpipelineへと処理が移行する。pipelineの処理が終わると、またSpiderにおいてforループの続きが行われる。

dragstar.hatenablog.com

前回記事ではpipelineに関する処理は省略したが、SpiderとpipelineはSpiderでitemにデータを全部いれてからpipelineでforループを使って処理をしていた

  • 変更前
# your Spider
item['title'] =response.xpath('//item/title/text()').extract()
item['link'] =response.xpath('//item/link/text()').extract()
yield item
# your pipeline
title = item['title']
link = item['link']
for (t, l) in zip(title, link):
  print("title", t)
  print("link", l)

これをSpiderでforループを回して途中でyieldするようにして、pipelineではforループを書かないように変更した。

  • 変更後
# your Spider
rss = response.xpath('//item')
for sel in rss:
  item = HatenaHotentryItem()
  item['title'] = sel.xpath('title/text()').extract()[0]
  item['link'] = sel.xpath('title/text()').extract()[0]
  yield item
# your pipeline
title = item['title']
link = item['link']
print("title", title)
print("link", link)

これでforループの途中でpipelineに処理が移行し、pipelineがitemを使って何かしらの処理ができるようになる。どっちでforループを書くのかってだけといえばそのとおり。

pipelineのコツ

コツってほどでもないけど、上のSpiderに合わせて変更をする。pipelineではSpiderのライフサイクルに合わせて処理の定義ができる。

Item Pipeline — Scrapy 1.3.0 documentation

具体的にはSpider開始時、処理中と終了時の処理を定義できる。たとえば、Spider開始時にRDBとのコネクションを張って、Spider終了時にコネクションを切るといった事もできる。

class YourPipeline(object):

  def __init__(self):
    # いわゆるinit。pipelineがインスタンス化されたときに呼び出される
    # pipeline特有のものではなくpython標準なので、特に解説するようなことはない

  def open_spider(self, spider):
    # スパイダーが起動したときに呼び出される
    # DBへのコネクションを張ったりとか

  def process_item(self, item, spider):
    # スパイダーがyieldした時に呼び出される
    # itemを使って具体的に処理をする

  def close_spider(self, spider):
    # スパイダーが終了したときに呼び出される
    # トランザクションをcommitしたりDBをcloseしたりとか

処理を変えるとoutputするjsonのデータ構造も変わるので、好きなほうに変えるといいと思う。jsonがどういった構造のほうが扱いやすいかで決めたらいい。