【问题标题】:Can't access one website by Requests (Python Library) but working under PostMan(Chrome App)无法通过请求(Python 库)访问一个网站,但在 PostMan(Chrome 应用程序)下工作
【发布时间】:2018-02-05 23:43:55
【问题描述】:

我尝试通过 Python Requests 访问一个使用 IIS 托管的网站,该网站启用了基本身份验证并禁用了其他身份验证方法。

以下是我的代码:

import requests
from requests.auth import HTTPBasicAuth
from requests_ntlm import HttpNtlmAuth

xxx_headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
               'Upgrade-Insecure-Requests':'1',
               'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
               'Accept-Encoding':'gzip, deflate, br',
               'Connection':'keep-alive',
               'Cache-Control':'no-cache'}
response = requests.get('http://test:180/test.ashx', headers=xxx_headers, auth=HTTPBasicAuth('wsguest', 'xxxx'))

print ('------------finished---------------')
if(response.ok):
    print('success')
else:
    response.raise_for_status()

下面是输出:

------------finished---------------
Traceback (most recent call last):
  File "C:\Users\jianc\Desktop\test\test_print.py", line 25, in <module>
    response.raise_for_status()
  File "C:\Users\jianc\AppData\Local\Programs\Python\Python36-32\lib\site-packages\requests\models.py", line 935, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: http://test:180/test.aspx

#Partial Response Text:
<div id="content">
<p>The following error was encountered while trying to retrieve the URL: <a href="http://test:180/test.aspx">http://test:180/test.aspx</a></p>

<blockquote id="error">
<p><b>Access Denied.</b></p>
</blockquote>

<p>Access control configuration prevents your request from being allowed at this time. Please contact your service provider if you feel this is incorrect.</p>

<p>Your cache administrator is <a href="mailto:webmaster?subject=CacheErrorInfo>webmaster</a>.</p>
<br>
</div>

<hr>
<div id="footer">
<p>Generated Mon, 05 Feb 2018 23:14:44 GMT by proxy.test.com (squid/3.5.12)</p>
<!-- ERR_ACCESS_DENIED -->
</div>
</body></html>

如果我将 URL 更改为 'https://www.google.com'、'http://www.baidu.com' 或其他,它可以工作(返回的 http 状态代码=200)。

我还在 PostMan(Chrome 应用程序)中模拟了一个具有相同身份验证的 Post/Get 到相同 URL,它仍然有效。

但是如果运行 PostMan 生成的代码,它会失败并出现同样的错误。

我怀疑是脚本在CUI而不是GUI下运行引起的,GUI会在OS的代理环境下运行,而CUI可能不会。但是为什么还是能成功访问google.com呢?如果代理服务器上的身份验证失败,它应该拒绝所有请求,包括对“谷歌和其他网站”的请求。

已经尝试了许多解决方案(例如添加带/不带基本身份验证的代理),但没有运气。

如果有人能提供任何提示,非常感谢。

谢谢。

【问题讨论】:

    标签: python python-3.x python-requests


    【解决方案1】:

    我终于找到了根本原因。

    Httplib2 不捕获并应用操作系统代理设置。

    Requests 会自动捕获并应用操作系统代理设置。

    这就是使用 Python 请求时 HTTP 请求被拒绝(NTLM Auth Failed in Proxy)的原因。

    所以解决方案很简单,忽略代码中的操作系统代理(对于 Python 请求库)。

    另一种方法是实现Proxy NTLM Auth,但是会很复杂,至少我在网上没有找到任何相关代码。

    以下代码有效:

    import httplib2
    
    h = httplib2.Http(".cache")
    
    h.add_credentials('xxx', 'xxxx') # Basic authentication
    
    resp, content = h.request("http://test:180/test.aspx", "GET", body="")
    print (content)
    

    以下代码由 PostMan 生成,如果忽略默认操作系统代理(两个解决方案:禁用全局代理设置或改用空代理),它将起作用。

    import requests
    url = "http://test:180/test.aspx"
    session = requests.Session()
    session.trust_env = False #disable OS proxy
    headers = {
        'authorization': "Basic d3NndWVzdDpzbWMxxjMhQA==",
        'cache-control': "no-cache",
        'postman-token': "157e52fa-95f5-5287-9ee0-xxxxxxxx"
    }
    
    response = session.get(url, headers=headers)
    print(response.text)
    
    #use empty proxy instead
    proxies = {
      "http": None,
      "https": None,
    }
    response = requests.get(url, auth=HTTPBasicAuth('test', 'test'), proxies=proxies)
    print (response)
    

    【讨论】:

    • 使用wireshark检查两个框架有什么区别。
    • 很明显,Postman/httplib2 和使用 auth=HTTPBasicAuth('wsguest', 'xxxx') 参数生成的请求之间的授权标头不同。尝试将授权标头添加到请求标头参数并删除身份验证。如果可行,我会将 auth 参数创建的授权标头与您硬编码的授权标头进行比较。
    • @William 我确实尝试过这种方式,但没有运气。头部看起来有些特殊,导致请求被 Squid 代理阻止。我会在手头完成紧急项目后将其挖掘出来(必须使用wireshark或fiddler来比较http数据包)。
    • @eyllanesc,更新了答案。我通过使用wireshark找出差异。 Python Requests 生成的 HTTP 请求被重定向到 ip.dst=[proxy server],但 Httplib2 没有。感谢您的建议。
    • 因为我的 IIS 网站在内部网络中。所以请求不应该被代理重定向。
    猜你喜欢
    • 2016-07-03
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 2022-07-28
    • 1970-01-01
    • 2019-08-21
    • 2019-02-02
    • 2017-10-12
    相关资源
    最近更新 更多