簡體   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