pyhabu のpluginsを作ってみる。 常山フィード を1リンクにつき1エントリへ分解する。
まず、XML parserを用意します。 処理速度重視の lxml と、インストールがらくちんな BeautifulSoup を。
lxmlを使ってみる
>>> from lxml import etree
>>> from StringIO import StringIO
>>> parser = etree.HTMLParser()
>>> html = '<html><head><title>test<body><h1>page title<a href="url">TEST</a></h3>'
>>> tree = etree.parse(StringIO(html), parser)
>>> anchor = tree.xpath("//*[@href]")
>>> anchor[0].attrib.get("href")
'url'
>>> anchor[0].text
'TEST'
HTMLParser を使うと多少いい加減なHTMLでもそれなりに解釈します。 tree.xpath("//*[@href]") ではXPath指定で href 属性を持つ要素を抜き出しています。
BeautifulSoupを使ってみる
>>> from BeautifulSoup import BeautifulSoup
>>> html = '<html><head><title>test<body><h1>page title<a href="url">TEST</a></h3>'
>>> anchor = BeautifulSoup(html).findAll("a")
>>> anchor[0].get("href")
u'url'
>>> anchor[0].string
u'TEST'
BeautifulSoupは素でいい加減なHTMLを解釈できます。 いまのところXPathが使えないので findAll で<a>タグを検索します。
ここまででXMLの調理方法はOK :-) 次にpyhabuのレシピを考えます。 付属の habu.cfg をカスタマイズしてベースを作ってみます。
johzan_feed.cfg
global:
timezone: Asia/Tokyo
log: stdout
pipeline:
rss_fetcher:
- module: subscription.config
config:
feed:
- http://d.hatena.ne.jp/johzan/rss2
- module: publisher.rssfeeder
config:
file: "johzan_feed.rss"
余分なものをそぎ落とし subscription.config のソースに http://d.hatena.ne.jp/johzan/rss2 を、 出力のファイル名を johzan_feed.rss にしました。 これで http://d.hatena.ne.jp/johzan/rss2 をダウンロードして johzan_feed.rss というファイル名で保存するレシピの完成です。
http://d.hatena.ne.jp/johzan/rss2 には、いわゆる常山フィードだけでなく、すばらしいエントリも含まれています。 タイトルに「巡回」が含まれているいわゆる常山フィードだけを抜き出すには filter.grep を使います。
johzan_feed.cfg
global:
timezone: Asia/Tokyo
log: stdout
pipeline:
rss_fetcher:
- module: subscription.config
config:
feed:
- http://d.hatena.ne.jp/johzan/rss2
- module: filter.grep
config:
str:
title: 巡回
- module: publisher.rssfeeder
config:
file: "johzan_feed.rss"
さて、ここからが本番。 いわゆる常山フィードからアンカーを抜き出して個別のエントリに仕立てます。 この処理ができるpluginは、pyhabuパッケージに含まれていないので自分で作ります。 エントリからアンカーを抜き出す処理なので filter.select_anchor と命名します。
pluginの要件は現在(pyhabu 0.3)のところ、
を1つのモジュールに納めます。 何もしない最小のpluginは↓になります。
class Main(object):
def __init__(self, config, environ):
pass
def execute(self, context):
return context
def create(*argv, **kwargv):
return Main(*argv, **kwargv)
ということで filter.select_anchor は こんな感じ になりました。 ファイル名を select_anchor.py として filter ディレクトリに入れます。
レシピのYAMLは module: filter.select_anchor を差し込んで、 仕上げにtitleとlinkを追加したfeedを出力するように設定して完成です。 結果は http://michilu.com/feeds/others/johzan_junkai.xml で取得できます。
johzan_feed.cfg
global:
timezone: Asia/Tokyo
log: stdout
pipeline:
rss_fetcher:
- module: subscription.config
config:
feed:
- http://d.hatena.ne.jp/johzan/rss2
- module: filter.grep
config:
str:
title: 巡回
- module: filter.select_anchor
- module: publisher.rssfeeder
config:
title: 常山日記 - 巡回
link: http://d.hatena.ne.jp/johzan/searchdiary?word=%BD%E4%B2%F3
file: "johzan_feed.rss"
こんな感じでpluginが増えていくとバリエーションも増えていきます。 夢が広がりんぐってやつですね。
plugin共有プロジェクト( pyhabu-plugins )を作ったので、ジョインしてがんがんコミットしてくださいまし :-)
