Posted at

feedparserのエラーハンドリング周り

More than 1 year has passed since last update.


TL;DR



  • feedparser.parse()の結果は返り値のbozoを見るのが一番手っ取り早い。0の時だけパース成功

  • パース成功してなければbozo_execptionを見ておけば良い


動機

>>> import feedparser

>>>
>>> resp1 = feedparser.parse('http://qiita.com/tags/python/feed')
>>> type(resp1)
<class 'feedparser.FeedParserDict'>
>>>
>>> resp2 = feedparser.parse('http://qiita.com/tags/python1/feed')
>>> type(resp2)
<class 'feedparser.FeedParserDict'>

feedparser.parse()は、指定したURLがなんであれfeedparser.FeedParserDictを返します。

それだとちょっと不便なので、ちょっとこの中身を少しみてみることにしました。


調べてみるもの


変数情報

変数名
URL

resp1
http://qiita.com/tags/python/feed
普通のRSSフィード

resp2
http://qiitta.com/tags/python
RSSフィードではない

resp3
http://qiita.com/tags/python1/feed
200以外のステータスコード

resp4
http://qiitta.com/tags/python/feed
存在しないドメイン


対象


  • FeedParserDictのキー


    • 共通するキーは何か?




調べてみる


キーを調べる

>>> resp1.keys()

dict_keys(['bozo', 'encoding', 'status', 'etag', 'href', 'entries', 'version', 'namespaces', 'feed', 'headers'])
>>>
>>> resp2.keys()
dict_keys(['bozo', 'encoding', 'status', 'bozo_exception', 'etag', 'href', 'entries', 'version', 'namespaces', 'feed', 'headers'])
>>>
>>> resp3.keys()
dict_keys(['bozo', 'encoding', 'bozo_exception', 'status', 'href', 'entries', 'version', 'namespaces', 'feed', 'headers'])
>>>
>>> resp4.keys()
dict_keys(['bozo', 'entries', 'feed', 'bozo_exception'])
>>>

思いのほか、保持しているキーがバラバラです。bozo, entriesのみが共通しています。


共通しているキーの中身

>>> resp1.bozo

0
>>> resp1.entries
[{'summary': '<p>第8章ではグラフィカルモデルについて説明されています。グラフィカルモデルとは、確率変数やモデルのパラメータなどの関係を図式的に表現する方法です
# 略
}]
>>>
>>> resp2.bozo
1
>>> resp2.version
''
>>> resp2.entries
[]
>>>
>>> resp3.bozo
1
>>> resp3.version
''
>>> resp3.entries
[]
>>>
>>> resp4.bozo
1
>>> resp4.entries
[]
>>>

この時点で、bozoが0の時のみ、RSSフィードとしてパースに成功したとみることができます。

本来の主目的だけ見ればこれでほぼほぼ完了なのですが、もうちょっと掘り下げます。


パース失敗勢の構造を見る

パースに成功している結果については何も考えずにentriesいじってればいいので、ここから先はパース失敗のエラーハンドリングを目的に、どんな情報が取れるかを見にいこうと思います。


bozo_exception の存在

resp1,resp2を比較すると、どちらもリクエストに成功はしているからか、statusheadersなどのHTTPっぽいキーが見て取れます。

そんな中、resp2のみに存在するキーがありました。それがbozo_exceptionです。

>>> resp2.bozo_exception

SAXParseException('undefined entity',)

そのまんまなメッセージが入っていました。これを見れば概ね問題なさそうです。


resp3,resp4

>>> resp3.bozo_exception

NonXMLContentType('text/html; charset=utf-8 is not an XML media type',)
>>>
>>> resp4.bozo_exception
URLError(gaierror(8, 'nodename nor servname provided, or not known'),)
>>>

他のrespも見るとこんな感じ。中の文字列だけ出すのが面倒なのが欠点。

あと、resp3404 Not Foundにも関わらず、パースしようとしているので、statusもあるなら合わせて見るのがよさげです。