2014年8月14日木曜日

Scrapyでスクレイピングする話@ Pytexas2013


スクレイピングをPythonでやるのに、
urllib2とかrequestとかbeautifulsoup組み合わせて実装するの面倒ですよね。
スクレイピーはそういったタスクを全部やってくれて、おまけにクローリングのスケジューリングとかもできてしまうフレームワークがあります、それがScrapy。

Githubに講演者がGithubにレポジトリあげてくれていた。
https://github.com/dmclain/scrapy-pytexas-2013




/spiders/talkspider_basic - parse a single page and yield a series of items

単純に1ページをスクレイプするscrapyのデモ。

PytexasItemは収集する要素のクラス。
データモデルを定義しています。

class PytexasItem(Item):
# define the fields for your item here like:
# name = Field()
title = Field()
time = Field()
speaker = Field()
description = Field()



TalkspiderBasicSpiderはクロールする際のスパイダーを実装します。
name, allowed_domains, start_url はクラスの要素で、
その名の通りスパイダーがクロールするドメインとかURLを指定します。
name is used for internally keeping track of なので内部的に利用されるクラスの要素です。



class TalkspiderBasicSpider(BaseSpider):
name = "talkspider_basic"
allowed_domains = ["www2.pytexas.org"]
start_urls = ['http://www.pytexas.org/2013/schedule/']
def parse(self, response):
hxs = HtmlXPathSelector(response)
dls = hxs.select('///dl')
for dl in dls:
times = dl.select('dt/text()').extract()
titles = dl.select('dd/a/text()').extract()
for time, title in zip(times, titles):
title = title.strip()
yield PytexasItem(title=title, time=time)



HtmlXPathSelector()で選択したHTMLのDOMを解析してXPath表記の要素をextractします。




scrapyはデフォルトではstart_urlに書かれたサイト全体をクロールする。
スパイダーのコンストラクタが呼ばれるとクロールするタスクをキューに貯める。
全部クロールするのは面倒ですし無駄が多いので、クロールするURLを指定したいところ。
そこで出てくるのがTalkspiderCrawlSpider()



(15:00くらいから~)
「XPathなんぞ」という方は、Google Chromeをお使い下さい。
XPathが知りたい部分をカーソルで選択して右クリック。
「要素を検証 or Inspect Element」 選択するとDeveloper Toolが下に表示されます。
Chrome上で、 「 Ctrl+Shift+i 」するとDeveloperToolが表示されるアレです。
Developer Consoleに出てる項目を右クリックしてCopy XPathすればよいです。
とても快適です。



(20:00くらいから)


def parse(self, response):
hxs = HtmlXPathSelector(response)
dls = hxs.select('///dl')
for dl in dls:
times = dl.select('dt/text()').extract()
titles = dl.select('dd/a/text()').extract()
hrefs = dl.select('dd/a/@href').extract()
for time, title, href in zip(times, titles, hrefs):
title = title.strip()
yield Request(
url=''.join(('http://www.pytexas.org', href)),
callback=self.parse_item,
meta={'time': time, 'title': title}
)


yield時にitem返すんじゃなくてrequestを返してるのがポイント。


- Being Good citizen
  スクレイプするときはrobot.txtに従いましょうね、ダウンロードにはディレイを入れて負荷かけ内容にしましょうね



0 件のコメント:

コメントを投稿