サラリーマンたるもの、日々の情報収集は欠かせません。
そのため、気になる業界ニュースをチャットに通知するクローラーを実装して使っているのですが、度々未知のエラーが出てしまいます。
叩いたら粉まみれ。PCデポ決算修正の内容とは https://t.co/9HEJywe6Fp pic.twitter.com/ja9YyK96ps
— 株の教科書.com (@kabunokyoukasyo) June 5, 2017
今朝は、こちらのニュースをクローリングしようとして、
from urllib import request request.urlopen('https://xn--u9j460nu9a58aw75c.com')
すると、以下のようなエラーが出てしまっていました。
CertificateError: hostname '株の教科書.com' doesn't match either of 'xn--u9j460nu9a58aw75c.com', 'www.xn--u9j460nu9a58aw75c.com'
利用しているPythonのバージョンは3.6.1です。
$ python3 -V Python 3.6.1
ここで2点可能性があるのですが、
- 証明書の認証に失敗している
- マルチバイト文字のURLの比較で失敗している
requests
ライブラリを利用した場合はエラーが出ないため、2. の可能性が濃厚です。
import requests requests.get('https://xn--u9j460nu9a58aw75c.com')
暫定的な対処
18.2. ssl — ソケットオブジェクトに対する TLS/SSL ラッパー — Python 3.6.1 ドキュメント
ssl.match_hostname(cert, hostname)(原文)
(SSLSocket.getpeercert() が返してきたようなデコードされたフォーマットの) cert が、与えられた hostname に合致するかを検証します。HTTPS サーバの身元をチェックするために適用されるルールは RFC 2818, RFC 6125 で概説されているものです。HTTPS に加え、この関数は他の SSL ベースのプロトコル、例えば FTPS, IMAPS, POPS などのサーバの身元をチェックするのに相応しいはずです。
失敗すれば CertificateError が送出されます。成功すれば、この関数は何も返しません:
今回はアクセスするURLが安全なものだとわかっているので、こちらのページに従い「証明書のチェックを行わない」という設定をして、一時的な対処を行いました。ただし、いろいろとセキュリティの問題が出てきそうなので今後はこの設定は使いたくありません。
import ssl from urllib import request ssl._create_default_https_context = ssl._create_unverified_context request.urlopen('https://xn--u9j460nu9a58aw75c.com')
TODO::
urllib
ライブラリのエラーが出ている箇所のコードをチェックする。- バージョンアップでの対処やイシューが出ているかどうかを調べる。