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

时间:2015-10-21 16:24:20

标签: python windows urllib2

我得到了一个" WindowsError:[错误5]访问被拒绝"使用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

我已尝试使用管理员权限从命令提示符运行脚本,如建议here,但它无法解决问题。

有关如何解决此错误的任何建议?

2 个答案:

答案 0 :(得分:3)

看起来这是一个Windows证书存储不一致。 httplib - 由urllib2在内部调用 - 最近从无服务器证书验证更改为默认情况下强制执行服务器证书验证。因此,您将在任何基于urllibhttplib并在您的用户个人资料中运行的python脚本中遇到此问题。

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

如果你想进一步调试这个,你也可以尝试manually invoke CA WINAPI:CertOpenSystemStore作为参数并尝试从这一侧调试它,尝试其他windows certstore管理工具和/或致电微软支持asistance。

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

如果您只想在不修复根本原因的情况下使其工作,您可以尝试使用以下解决方法暂时修补LPTCSTR::'CA'以不包括损坏的_windows_cert_stores证书库或完全禁用信任锚加载逻辑。 (所有其他CA调用将在当前进程中进行修补)

注意,这有效地禁用了服务器证书验证。

ssl.SSLContext

我希望这些信息可以帮助您解决问题。祝你好运。

答案 1 :(得分:2)

使用Windows证书存储有几个潜在问题。 (我发现从没有完整用户配置文件的服务帐户运行代码的情况下,这几乎是不可能的)。原因有点复杂,但不值得进一步讨论,因为有一个更容易的解决方案。如前所述,关闭SSL验证是一种解决方法,但如果您关心所提供证书的有效性,则可能不是最好的。

通过使用自包含的证书存储来完全避免这种情况。对于Python,这是certifi包,它保持最新。这可以从python requests包中轻松访问。对于大多数常见的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.