Я столкнулся с той же проблемой в OSX, в то время как мой код был абсолютно нормальным в Linux, и вы дали ответ на свой вопрос!
После проверки файла, на который вы указали /Applications/Python 3.7/Install Certificates.command
, оказалось, что эта команда заменяет корневые сертификаты установки Python по умолчанию на сертификаты, отправленные через пакет certifi
.
certifi
- это набор корневых сертификатов.Каждый сертификат SSL опирается на цепочку доверия: вы доверяете одному конкретному сертификату, потому что доверяете родителю этого сертификата, которому вы доверяете родителю и т. Д. В какой-то момент нет «родителя», а это «корневые» сертификаты.Для них не существует другого решения, кроме объединения обычно доверенных корневых сертификатов (обычно таких крупных доверенных компаний, как, например, «DigiCert»).
Вы можете, например, увидеть корневые сертификаты в настройках безопасности браузера (например, дляFirefox-> Настройки-> Конфиденциальность и безопасность-> Просмотр сертификатов-> Полномочия).
Возвращаясь к первоначальной проблеме, и перед запуском файла .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))
Это означает, что не существует центра сертификации по умолчанию для установки Python в OSX.Возможное значение по умолчанию в точности совпадает с тем, которое предоставляется пакетом 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)
и сделайте запрос к url
от python так:
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)