«WindowsError: Доступ запрещен», используя urllib2

Я получаю сообщение «WindowsError: [Error 5] Access is denied» при чтении веб-сайта с urllib2.

from urllib2 import urlopen, Request from bs4 import BeautifulSoup hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11'} req = Request('https://' + url, headers=hdr) soup = BeautifulSoup( urlopen( req ).read() ) 

Полное отслеживание:

 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\Python27\lib\urllib2.py", line 154, in urlopen return opener.open(url, data, timeout) File "C:\Python27\lib\urllib2.py", line 431, in open response = self._open(req, data) File "C:\Python27\lib\urllib2.py", line 449, in _open '_open', req) File "C:\Python27\lib\urllib2.py", line 409, in _call_chain result = func(*args) File "C:\Python27\lib\urllib2.py", line 1240, in https_open context=self._context) File "C:\Python27\lib\urllib2.py", line 1166, in do_open h = http_class(host, timeout=req.timeout, **http_conn_args) File "C:\Python27\lib\httplib.py", line 1258, in __init__ context = ssl._create_default_https_context() File "C:\Python27\lib\ssl.py", line 440, in create_default_context context.load_default_certs(purpose) File "C:\Python27\lib\ssl.py", line 391, in load_default_certs self._load_windows_store_certs(storename, purpose) File "C:\Python27\lib\ssl.py", line 378, in _load_windows_store_certs for cert, encoding, trust in enum_certificates(storename): WindowsError: [Error 5] Access is denied 

Я попытался запустить сценарий из командной строки с правами администратора, как это предлагается здесь , но это не устраняет проблему.

Любые предложения по устранению этой ошибки?

Похоже, что это несоответствие хранилища сертификатов Windows. httplib – который внутренне urllib2 – недавно был изменен без проверки сертификата сервера, чтобы по умолчанию проверять сертификат сервера. Поэтому вы столкнетесь с этой проблемой в любом скрипте python, который основан на urllib , httplib и работает в вашем профиле пользователя.

Тем не менее, что-то кажется очень неправильным в вашем хранилище сертификатов Windows. httplib терпит неудачу для вас, пытаясь перечислить сертификаты для указанного центра CA certification authority CA (отображается в качестве Intermediate Certification Authorities certmgr.msc Intermediate Certification Authorities в certmgr.msc ), но для ROOT который является обычным доверенным корневым хранилищем сертификатов (см. комментарии к вопросу), преуспевает. Поэтому я предлагаю проверить все сертификаты в certmgr:intermediate certificate authorities для недавно добавленных сертификатов и / или журнала Windows для общих ошибок. Что происходит в вашем случае, так это то, что urllib2 внутренне вызывает httplib который затем пытается настроить контекст ssl по умолчанию с принудительной проверкой сертификата, и в качестве части этого он перечисляет доверенные сертификатные привязки вашей системы, вызывая ssl.enum_certificates . Эта функция реализована в C как _ssl_enum_certificates_impl и внутренне вызывает WINAPIs CertOpenSystemStore и CertEnumCertificatesInStore . Для центра CA хранилища CA он просто терпит неудачу в одном из двух вызовов winapi с отказом доступа.

Если вы хотите дополнительно отладить это, вы также можете попытаться вручную вызвать WINAPI:CertOpenSystemStore с помощью LPTCSTR::'CA' в качестве аргумента и попытаться отладить его с этой стороны, попробовать другие инструменты управления сертификатами Windows и / или вызвать поддержку Microsoft для asistance.

Есть также признаки того, что у других были подобные проблемы при взаимодействии с этим вызовом api, см. Google: доступ запрещен CertOpenSystemStore

Если вы просто хотите, чтобы он работал без исправления основной причины, вы могли бы просто попытаться использовать следующее обходное решение, которое временно исправляет _windows_cert_stores чтобы не включать поврежденный CA certstore или полностью отключить логику загрузки доверия-якоря. (все остальные вызовы ssl.SSLContext будут исправлены в текущем процессе)

Обратите внимание, что это фактически отключает проверку сертификата сервера.

 ssl.SSLContext._windows_cert_stores = ("ROOT",) # patch windows_cert_stores default to only include "ROOT" as "CA" is broken for you. #ssl.SSLContext.load_default_certs = lambda s,x:None # alternative, fully NOP load_default_certs to do nothing instead. ctx = ssl.create_default_context() # create new sslcontext, not veryfing any certificates, hostnames. ctx.check_hostname = False ctx.verify_mode = ssl.CERT_NONE hdr = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11'} req = Request('https://' + url, headers=hdr) x = urlopen( req , context=ctx).read() ssl.SSLContext._windows_cert_stores = ("ROOT","CA") # UNDO PATCH 

Надеюсь, эта информация поможет вам решить проблему. удачи.

Существует несколько потенциальных проблем с использованием хранилища сертификатов Windows. (Я нашел для случая, когда вы запускаете свой код из учетной записи службы без полного профиля пользователя, это почти невозможно). Причины несколько сложны, но их не стоит обсуждать, потому что есть более легкое решение. Отключение проверки SSL, как уже было предложено, является обходным решением, но, вероятно, не лучшим, если вы заботитесь о действительности представленных сертификатов.

Просто избегайте этого, используя автономный магазин сертификатов. Для Python это пакет certifi , который обновляется. Это легко получить из пакета запросов python. Оба должны быть легко доступны для большинства распространенных дистрибутивов python

 import requests from bs4 import BeautifulSoup url = "www.google.com" hdr = { 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11'} r = requests.get('https://' + url, headers=hdr, verify=True) soup = BeautifulSoup(r.text) 

Обратите внимание, что request.get () будет генерировать исключение на недопустимых адресах, недоступных сайтах и ​​неудачной проверке сертификата. Поэтому вы хотите быть готовыми поймать их. Когда сайт был успешно связан и сертификат был проверен, но страница не была найдена (например, ошибка 404), вы не получите исключение. Таким образом, вы также должны проверить, чтобы r.status_code == 200 после запроса. (30-кратные переадресации обрабатываются автоматически, поэтому вы не увидите их как коды статуса, если вы не сообщите ему, чтобы они не следовали им.) Эта проверка для ясности этого кода исключена.

Также обратите внимание, что вы здесь явно не ссылаетесь на модуль certifi . запросы будут использоваться, если они установлены. Если они не установлены, запросы будут использовать более ограниченный набор корневых ЦС.