Pythonを使用してWebからデータを取得しようとしています。 urllib.requestパッケージをインポートしましたが、実行中にエラーが発生します。
certificate verify failed: unable to get local issuer certificate (_ssl.c:1045)
URLを「http」に変更すると、データを取得できます。しかし、これによりSSL証明書のチェックが回避されると思います。
それで、私はインターネットでチェックして、1つの解決策を見つけました:/Applications/Python\ 3.7/Install\ Certificates.command
を実行します
これで私の問題が解決しました。しかし、私はSSLなどについて知識がありません。私の問題を解決するために実際にそれが何をしたかを理解してもらえますか.
可能であれば、セキュリティと証明書について学ぶための適切なリソースをお勧めします。これは初めてです。
ありがとう!
注:リンクを確認しました- openssl、python要求エラー:「証明書の検証に失敗しました」
私の質問はリンクの質問とは異なります。なぜなら、certifi
パッケージをインストールしたとき、またはInstall\ Certificates.command
を実行してエラーを修正したときに実際に何が起こるかを知りたいからです。証券の理解が不十分です。
私はOSXで同じ問題にぶつかりましたが、Linuxでは私のコードはまったく問題ありませんでした。
/Applications/Python 3.7/Install Certificates.command
をポイントしたファイルを調べたところ、このコマンドがデフォルトのPythonインストールのルート証明書をcertifi
パッケージを介して出荷されたものに置き換えることがわかりました。
certifi
はルート証明書のセットです。各SSL証明書は信頼のチェーンに依存します。親を信頼するなど、その証明書の親を信頼するため、特定の証明書を信頼します。ある時点で、「親」はなく、それらは「ルート」証明書です。これらの場合、一般に信頼されているルート証明書(通常、「DigiCert」などの大規模な信頼会社)をバンドルする以外に解決策はありません。
たとえば、ブラウザのセキュリティ設定でルート証明書を確認できます(たとえば、Firefox-> Preference-> Privacy and security-> view certificate-> Authorities)。
最初の問題に戻って、.command
ファイルを実行する前に、これを実行すると、クリーンインストールで空のリストが返されます。
import os
import ssl
openssl_dir, openssl_cafile = os.path.split(
ssl.get_default_verify_paths().openssl_cafile)
# no content in this folder
os.listdir(openssl_dir)
# non existent file
print(os.path.exists(openssl_cafile))
これは、OSX上のPythonインストールにデフォルトの認証局がないことを意味します。可能なデフォルトは、certifi
パッケージで提供されるものです。
その後、次のように適切なデフォルトを持つSSLコンテキストを作成できます(certifi.where()
は認証局の場所を示します)。
import platform
# ...
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS)
ssl_context.verify_mode = ssl.CERT_REQUIRED
ssl_context.check_hostname = True
ssl_context.load_default_certs()
if platform.system().lower() == 'darwin':
import certifi
ssl_context.load_verify_locations(
cafile=os.path.relpath(certifi.where()),
capath=None,
cadata=None)
次のようにpythonからurl
にリクエストします:
import urllib
# previous context
https_handler = urllib.request.HTTPSHandler(context=ssl_context)
opener = urllib.request.build_opener(https_handler)
ret = opener.open(url, timeout=2)
Linuxのcondaでエラーが発生しました。私の解決策は簡単でした。
conda install -c conda-forge certifi
デフォルトの証明書には問題があるように見えるので、conda forgeを使用する必要がありました。