忘れないようにメモっとく

機械学習とかプログラミングとか。

pythonのフレームワークでサクッとクローラをつくる。"Python Framework Scrapy"

そうだクローラつくろう

 研究テーマを探しつつ、なんとなくネットワークが面白そうと思っていた今日この頃。
研究で扱うのは、通信技術のネットワークではなくて、ノードとリンクに一般化したやつ。

 「スモールワールド(small world phenomenon)」や「六次の隔たり(six degrees of separation)」など、一般的に知られてる部分もあって、経済現象とか感染症の拡散の理論にも適用できる(と言われている)ので、関連する分野がめちゃくちゃ広い。

 ただ、実際のデータを無料で手っ取り早く集めるとなると、web上のドキュメントを解析するのが楽そう。ということで、クローラをつくってみる。
 集めたデータをどう扱うかはまだ決めてない(!!)けど、とりあえず非リンク数とかの解析から始めようかと考えております。

Scrapy(すくれぴー)

 pythonフレームワークにもいろいろあるみたいだけど、stackoverflowなどを参考に、Scrapyを使ってみることに。
 
 チュートリアルを読みながら、まずはインストールから。

$ sudo pip install Scrapy

 以上。ここで、Scrapyのサイトでは、dmoz/spidersとかのディレクトリ下にファイルを作成〜とか書いてるけど、この辺りが微妙に間違っていて、json吐き出すところもこっちのサイトの方が良さそう。

 というわけで、次のコマンドでfirst_projプロジェクトを作成。first_projディレクトリへ移動して、first_proj/items.pyを編集する。

$ scrapy startproject first_proj
$ cd first_proj
$ vim first_proj/item.py


first_proj/item.py

from scrapy.item import Item, Field                                                                                                                                            

class FirstProjItem(Item):
    title = Field()
    link = Field()
    content = Field()


 こんな感じで、サイトから引っ張ってくるデータ用に変数を定義しておく。
 次に、first_proj/spider/FooSpider.pyを作成。

first_proj/spider/FooSpider.py

from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from scrapy.http.request import Request
from first_proj.items import FirstProjItem

class FooSpider(BaseSpider):
    name = "foo"
    allowed_domains = ["foo.org"]
    start_urls = ["http://blog.scrapy.org/"]

    def parse(self, response):
        hxs = HtmlXPathSelector(response)

        next_page = hxs.select("//div[@class='pagination']/a[@class='next_page']/@href").extract()
        if not not next_page:
            yield Request(next_page[0], self.parse)

        posts = hxs.select("//div[@class='post']")
        items = []
        for post in posts:
            item = FirstProjItem()
            item["title"] = post.select("div[@class='bodytext']/h2/a/text()").extract()
            item["link"] = post.select("div[@class='bodytext']/h2/a/@href").extract()
            item["content"] = post.select("div[@class='bodytext']/p/text()").extract()
            items.append(item)
        for item in items:
            yield item

 start_urlsでurlを指定して、htmlをパースしたデータを、さっき作ったitemに追加していく。

 このデータはjsonにするので、実行コマンドは以下。

$ scrapy crawl foo -o bar.json -t json

 ロボットが頑張って働いてくれます。
 今回使ったプロジェクトはこちら



追記(9/19/2013):URLのリンク先にページが見つからなくなっているので、こちらを参考にコードを変更。

first_proj/spiders/FooSpider.py

from scrapy.spider import BaseSpider
from scrapy.selector import HtmlXPathSelector
from scrapy.http.request import Request
from first_proj.items import FirstProjItem

class FooSpider(BaseSpider):
    name = "foo"
    allowed_domains = ["foo.org"]
    start_urls = ["http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", 
                "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"]

    def parse(self, response):
        hxs = HtmlXPathSelector(response)

        sites = hxs.select("//ul/li")
        items = []        #for post in posts:
        for site in sites:
            item = FirstProjItem()
            item["title"] = site.select('a/text()').extract()
            item["link"] = site.select('a/@href').extract()
            item["content"] = site.select('text()').extract()
            items.append(item)
        for item in items:
            yield item