LoginSignup
5
7

More than 5 years have passed since last update.

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

Posted at

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もあるなら合わせて見るのがよさげです。

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7