繁体   English   中英

“WindowsError:[错误5]访问被拒绝”使用urllib2

[英]“WindowsError: [Error 5] Access is denied” using urllib2

在使用urllib2阅读网站时,我收到“WindowsError:[错误5]访问被拒绝”消息。

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内部调用 - 最近urllib2服务器证书验证更改为默认强制执行服务器证书验证。 因此,您将在任何基于urllibhttplib并在用户配置文件中运行的python脚本中遇到此问题。

也就是说,你的Windows证书商店似乎有些问题。 在尝试枚举指定证书存储CA certification authority (在certmgr.msc显示为Intermediate Certification Authorities )时, httplib失败,但对于正常的受信任根证书存储区ROOT会成功(请参阅要提问的注释)。 因此,我建议检查certmgr:intermediate certificate authorities所有证书certmgr:intermediate certificate authorities最近添加的证书的certmgr:intermediate certificate authorities和/或Windows日志中的一般错误。 在你的情况下发生的是urllib2内部调用httplib然后尝试设置默认的ssl上下文并强制执行证书验证,并且作为其中的一部分,它通过调用ssl.enum_certificates枚举系统的可信证书锚点。 此函数在C 实现_ssl_enum_certificates_impl并在内部调用WINAPIs CertOpenSystemStoreCertEnumCertificatesInStore 对于证书存储位置CA它只是在两个winapi调用之一中失败,拒绝访问。

如果你想进一步调试这个,你也可以尝试用LPTCSTR::'CA'作为参数手动调用 WINAPI:CertOpenSystemStore并尝试从这一侧进行调试,尝试其他windows certstore管理工具和/或调用microsoft support for asistance。

还有迹象表明其他人在接口api电话时遇到类似问题,请参阅google: access denied CertOpenSystemStore

如果您只想在不修复根本原因的情况下使其工作,您可以尝试使用以下解决方法临时修补_windows_cert_stores以不包括损坏的CA证书库或完全禁用信任锚加载逻辑。 (所有其他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)

请注意,requests.get()将在无效地址,无法访问的站点和证书验证失败时抛出异常。 所以你想准备抓住这些。 成功联系站点并验证证书后,但未找到该页面(例如404错误),您将不会收到异常。 因此,您还应该在发出请求后检查r.status_code == 200。 (30x重定向会自动处理,因此您不会将其视为状态代码,除非您告诉它不遵循它们。)为清楚起见,示例代码中省略了此检查。

另请注意,此处未明确引用certifi模块。 如果安装, 请求将使用它。 如果未安装, 请求将使用更有限的内置根CA.

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM