我得到了一个" 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,但它无法解决问题。
有关如何解决此错误的任何建议?
答案 0 :(得分:3)
看起来这是一个Windows证书存储不一致。 httplib
- 由urllib2
在内部调用 - 最近从无服务器证书验证更改为默认情况下强制执行服务器证书验证。因此,您将在任何基于urllib
,httplib
并在您的用户个人资料中运行的python脚本中遇到此问题。
那就是说,你的Windows证书商店似乎有些问题。尝试枚举指定证书存储区httplib
CA
的证书时certification authority
失败(在Intermediate Certification Authorities
中显示为certmgr.msc
)但{{1}成功这是正常的受信任根证书存储区(请参阅提问的注释)。因此,我建议检查ROOT
中最近添加的证书和/或Windows日志中的所有证书是否存在一般错误。
在您的情况下发生的是certmgr:intermediate certificate authorities
内部调用urllib2
然后尝试设置默认的ssl上下文并强制执行证书验证,并且作为其中的一部分,它枚举系统的可信证书锚点。致电httplib
。 ssl.enum_certificates
中的此is implemented函数为C
,内部调用WINAPI _ssl_enum_certificates_impl
和CertOpenSystemStore
。对于证书存储位置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.