あったらしくるえるはてなくしょん

id:kskmeuk あったらしく

http://b.hatena.ne.jp/entrylist を収穫して削りだすときにつかったソース

ここのところの
はてブのメタデータの価値が恐ろしいので、twitter で人気のはてブランキングを可視化してみたら想像以上だった。(重要な追記と修正があります!!) - くるえるはてなくしょん
さらに、はてブユーザに人気のcookpad レシピを整理してみた。鶏肉編、豚肉編、魚編。 - くるえるはてなくしょん
をするのにつかったプログラムです。

http://b.hatena.ne.jp/entrylist?sort=count&url=http://twitter.com&of=0 とかを追っかけて見に行くのが単純に楽しかったというのもあって、はてブという龍脈を確認して計算リソースと等価交換で一覧を引き出すための錬成陣.... じゃなかったソースを以下に。

ここでは、BeautifulSoup という Python で html とかを良きに計らってくれる賢者の石... じゃなかった、えっと、そういうのが必要です。あれがあると、パンっとやるだけで、錬成できて楽です。もうこの際、オブジェクト志向とか全部鋼の錬金術師っぽく解説する教科書書いたらみんなわかるんじゃないのかしらね。

で、スクレイピングというかハーヴェスティングというか、そういう感じ動かします。20件ずつじゃなくて、100件までざっと見たいとか集計する場合は使えると思います。はてブそのものとかユーザとか元サイトとかPython とかそういう諸々に感謝して使いましょう。

Python 上手な人だったら、絶対にもっときれいに書けると思います。作った時は何回も使うと思ってなかったのであちょーって書いたんですけど、概してそういう時に限って何回も使ったりして...あちゃーってなるよね...orz

というわけで、HatebuScraper.py

# -*- coding: utf-8 -*-
from BeautifulSoup import BeautifulSoup
import urllib2, cookielib
import time

class Recipe:
    def __init__(self):
        self.href = ""
        self.title = ""
        self.image = ""
        self.users = 0
        self.tags = []

    def show(self,count):
        print "|*"+str(count)+"|["+self.image+":image]|["+self.href+":title:bookmark]|"

class HatebuScraper:
    _count = 0
    _limit = 100
    _url = "http://cookpad.com/recipe/"

    def __init__(self, url, count,limit):
        if url: self._url = url
        if count: self._count = count
        if limit: self._limit = limit

    def parseURL(self):
        cj = cookielib.CookieJar()
        opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))

        i = 1
        while self._count < self._limit:
            time.sleep(3)
            html = opener.open('http://b.hatena.ne.jp/entrylist?sort=count&url='+self._url+'&of='+str(self._count))
            response = html.read()

            html = BeautifulSoup(response)
            if html.find("a",{"class":"pager-next"}):
                self._count = int(html.find("a",{"class":"pager-next"})["href"].split("of=")[1])
            for div in html.findAll("div",{"class":"entry-body"}):
                recipe = Recipe()
                for a in div.findAll("a",{"class":"entry-link"}):
                    if a.has_key("title"):
                        recipe.href = a["href"]
                        recipe.title = a["title"]
                for li in div.findAll("li",{"class":"tags"}):
                    for a in li.findAll("a"):
                        recipe.tags.append( a.string )
                if div.find("li",{"class":"users"}).strong:
                    recipe.users = div.find("li",{"class":"users"}).strong.a.string.replace(" users","")
                else:
                    recipe.users = div.find("li",{"class":"users"}).a.string.replace(" users","")
                if div.find("img",{"class":"entry-image"}):
                    recipe.image = div.find("img",{"class":"entry-image"})["src"]

                recipe.show(i)
                i += 1

if __name__ == '__main__':
    hp = HatebuScraper("http://cookpad.com/recipe/",0,40)
    hp.parseURL()

「次の20件」をずんずんたどって、はてブのエントリーの中身の欲しいところを削ってくるという、そのままですね。

BeautifulSoup と ちゃんとした html は組み合わせがわかりやすくって、タグの構造をそのままに子についてはクラスのメンバに、属性については辞書に入ってくれるので、それを使っています。
はてぶのentrylist の中身の html は、ありがたいことにかなり読みやすく書いてあるので、ソースの表示とつき合わせて見たら、おおよその見当はつくのではないかなと思います。

あとはやっぱり、Perl/Ruby/PythonCPANRubyGemsPyPI の仕組みって偉大だなというか有り難いなと思いますね、毎度毎度。