feedparserはAutodiscoveryしてくれません (たぶん)

いつまで経ってもPython素人、bonlifeです。 feedparser を使うサンプルでid:johzanさんがちょっとだけ勘違いをしているようなので、少し調べた結果をまとめてみました。

rss/atomを直接指定しなくても検索,取得してくれるのはありがたいけど。

いや、そんなありがたいことはしてくれてないっぽいですよ。

In [1]: import feedparser

In [2]: d = feedparser.parse('http://d.hatena.ne.jp/johzan/')

In [3]: d.bozo
Out[3]: 1

In [4]: len(d.entries)
Out[4]: 0

In [5]: d = feedparser.parse('http://d.hatena.ne.jp/johzan/rss')

In [6]: d.bozo
Out[6]: 0

In [7]: len(d.entries)
Out[7]: 16

bozo がポイントです。 well-formed でないXMLを適当にパースしてみた時、 bozo が 1 になります。(ご参考 : Bozo Detection) 最初の例では entries の数が 0 ってなっちゃってます。要するに、id:johzanさんのはてなダイアリーのトップページを無理矢理パースしただけなのです。ちゃんとRSSのURLを指定すると、正しくパースできます。
というわけで、自動的にRSSを見つけてパースした結果を返すために feedparser を軽くラップしたコードを書いてみました。エラー処理書いてませんが、そのあたりは雰囲気で察してくださいませ。

  • auto_feedparser.py
import feedparser

def find_rss(d):
    for i in d.feed.links:
        if i.get('rel') == 'alternate' and i.get('type') == 'application/rss+xml':
            return i.get('href')

def parse(url):
    d = feedparser.parse(url)
    if d.bozo == 0:
        return d
    else:
        return feedparser.parse(find_rss(d))

if __name__ == '__main__':
    d = parse('http://d.hatena.ne.jp/bonlife/')
    for i in d.entries:
        print i.title

そのまま実行するとこんな感じになります。

> python auto_feedparser.py
[IT][勉強][Python] Googleの検索結果数を取得するサンプル
[音楽][PV] APOGEEのPVのあのキャラ達の名前決定
[音楽][DTM] 勢いで「鏡音リン・レン」を注文してみました
[音楽][ALBUM] APOGEEの2ndアルバム『Touch In Light』は1月16日発売
[読書] 「恋空」祭り@Amazon

import して使ったり。

In [1]: from auto_feedparser import parse

In [2]: d = parse('http://d.hatena.ne.jp/johzan/')

In [3]: for i in d.entries:
   ...:     print i.title
   ...:
   ...:
[Django][Python][その他]巡回
[Django][pyspa][Python][jQuery][その他]巡回
[Python]feedparser
[Django][Python][jQuery][senna][その他]巡回
[PC-BSD][KDE]リモートデスクトップとfirefoxアップデート
[Django][Python][Mercurial][jQuery][SQLite3][その他]巡回
[Django][Python][Mercurial][jQuery][senna][CSS][その他]巡回
[Django][Python][Mercurial][jQuery][CSS][その他]巡回
[Django][Python][jQuery][KDE][その他]巡回
[Python]RSS/Atomを読みたくて調べてみた
[Django][Python][jQuery][CSS][その他]巡回
[PC-BSD][KDE]rdesktop
[Django][Python][Mercurial][jQuery][CSS][その他]巡回
[PC-BSD]Update
[Django][Python][Mercurial][その他]巡回
[Django][Python][jQuery][CSS][KDE][その他]巡回

ただ、こういう処理は自分で書かなくても誰かが何かしらの解決策を見つけてるはず!と思って調べてみました。…やっぱりありましたよ。

autorss.py をPython的にパスが通ってるところに置きまして。以下のような簡易スクリプトで動作チェック。

  • autorss_sample.py
import autorss
import feedparser

d = feedparser.parse(autorss.getRSSLink('http://d.hatena.ne.jp/bonlife/'))

for i in d.entries:
    print i.title

結果は以下の通り。

> python autorss_sample.py
[IT][勉強][Python] Googleの検索結果数を取得するサンプル
[音楽][PV] APOGEEのPVのあのキャラ達の名前決定
[音楽][DTM] 勢いで「鏡音リン・レン」を注文してみました
[音楽][ALBUM] APOGEEの2ndアルバム『Touch In Light』は1月16日発売
[読書] 「恋空」祭り@Amazon

こっちの方が動作が軽快っぽいです。最初の例(auto_feedparser.py)では、RSSではないURLが指定された場合、2回 feedparser によるパースが行われてしまいますが、autorss.py を使った方では、最初のパースが軽いみたい。 SGMLParser の setnomoretags で head が終わったところでパースを止めてるからかな。よく分からないけど。
でも、ホントにAutodiscoveryに対応してないのかなぁ。使い方間違ってるのかなぁ…。自信がなくなってきたので、誰かがフォローしてくれることを願いつつ、今日のところはこのあたりで。アディオス!