HTTPSサイトからfeedを取得する

自分のブログを SSL/TLS に対応させたらフィードが取得できなくなっていたので,とりあえず応急処置的な方法で修正しました.

feed の取得環境

WordPress の Jetpack に自動パブリサイズ機能はついていますが,あれで Twitter などに投稿すると書き換え前の URL を使われてしまい,これが非常に厄介.Twitter Card が正しく表示されないなどの問題が発生します.そこで自動で feed を取得して Twitter に投稿する BOT を作ってツイートしていました.

Twitter にブログ記事の更新を自動投稿する BOT を作る

ただ,そのことを忘れて SSL/TLS に切り替え,HTTP から HTTPS へのリダイレクトを強制したため,以前のコードでは動かなくなってしまいました.

エラー内容

feed を取得したときのエラーはこのようになっています.

{'feed': {}, 'bozo': 1, 'bozo_exception': URLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:581)'),), 'entries': []}

ソースコードの詳細

簡単に書くと feed 全体をこんな感じで読み込んでいました.

import feedparser

feed = feedparser.parse('https://blog.mktia.com/feed')

HTTP サイトへの接続なら,これで問題ありません.

対策方法

思いつくのは主に二つです.

  • HTTPS に接続しても feed を取得できるようにソースコードを書きかえる
  • HTTPS への強制リダイレクトをやめる

Web サーバ側では 80 番ポートも 443 番ポートも開放しているので,強制リダイレクトをやめれば feed が取得できるようになります.

しかし,一つのブログに対して URL が二つに分かれているのはあまり望ましい状況ではありません.よって,できればソースコードで対応したいところです.

応急処置的な対処

Highly discouraged な方法ですが...

import feedparser
import ssl

if hasattr(ssl, '_create_unverified_context'):
    ssl._create_default_https_context = ssl._create_unverified_context
feed = feedparser.parse('https://blog.mktia.com/feed')

とりあえずこれで取得できるようになります.

参考:Feedparser.parse() 'SSL: CERTIFICATE_VERIFY_FAILED' | Stack Overflow

ところで,このエラー何か見覚えあるような気がしたんですが,HTML 取得の際にも似たようなものが出たことがありました.

urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:645)>

これは User-Agent を指定することによって解決できたのですが,ここから推察するに (概念的に) プログラムではなくユーザーとして接続すれば feed の取得に失敗しないのでは?と.SSL/TLS 適用後も feedly で問題なく取得できていますし.で,Chrome を指定して接続を試みて失敗しました.(あれ...?)

最後に

feedparse に関する記事の少なさ.Qiita でも 5 件,Stack Overflow もほとんどなし.もしかして Python で取得するなら,もっといい方法があるんです?