适用于 urllib.request 但不适用于请求

Posted

技术标签:

【中文标题】适用于 urllib.request 但不适用于请求【英文标题】:Works with urrlib.request but doesn't work with requests 【发布时间】:2020-11-23 20:49:30 【问题描述】:

我正在尝试使用 post 方法向 API 发送请求,我的代码如下所示:

import urllib.request
import json

url         = "https://api.cloudflareclient.com/v0a745/reg"
referrer    = "e7b507ed-5256-4bfc-8f17-2652d3f0851f"
body        = "referrer": referrer
data        = json.dumps(body).encode('utf8')
headers     = 'User-Agent': 'okhttp/3.12.1'
req         = urllib.request.Request(url, data, headers)
response    = urllib.request.urlopen(req)
status_code = response.getcode()
print (status_code)

实际上它工作正常,但我想使用“请求”库,因为它更更新,更灵活的代理使用以下代码:

import requests
import json

url         = "https://api.cloudflareclient.com/v0a745/reg"
referrer    = "e7b507ed-5256-4bfc-8f17-2652d3f0851f"
data        = "referrer": referrer
headers     = 'User-Agent': 'okhttp/3.12.1'
req         = requests.post(url, headers=headers, json=data)
status_code = req.status_code
print (status_code)

但它返回403状态码,我该如何解决?

请记住,此 API 对所有人开放,您可以放心运行代码。


EDIT-1:我尝试通过@tomasz-wojcik 的建议从第二个代码中删除json.dumps(body).encode('utf8') 或只是.encode('utf8'),但我仍然得到403,而第一个代码仍然有效!

EDIT-2:我尝试向邮递员发出请求,成功发出请求并返回200 状态码。 postman 生成了以下 python 代码:

import requests

url = "https://api.cloudflareclient.com/v0a745/reg"

payload = "\"referrer\": \"e7b507ed-5256-4bfc-8f17-2652d3f0851f\""
headers = 
  'Content-Type': 'application/x-www-form-urlencoded',
  'User-Agent': 'okhttp/3.12.1',
  'Host': 'api.cloudflareclient.com'


response = requests.request("POST", url, headers=headers, data=payload)

status_code = response.status_code
print (status_code)

如果你在邮递员之外运行代码,它仍然返回 403 状态代码,我有点困惑,我想也许“请求”库不会改变用户代理在第二个代码中。

EDIT-3:我研究了一下,发现它可以在 python 2.7.16 上运行,但在 python 3.8.5 上不起作用!

EDIT-4:一些开发人员报告说第二个代码也适用于 python 3.6,但主要是为什么它适用于其他版本但不适用于 3.8 或 3.7?

返回 403 状态码(第二个代码)的 Python 版本:3.8.5 & 3.7

返回 200 状态代码(第二个代码)的 Python 版本:3.6 和 2.7.16

【问题讨论】:

requests 中的数据与第一个不同 对于请求体,图书馆帮不了你,你必须照顾它 urllib 的状态码是什么?您是否对两个库都使用了相同的 url?如果 od 请求,是否有正确的协议前缀(http:// 或 https://)? urllib代码返回200状态码!它们都分配了相同的 url,并且都在 url 的前缀中有 (https://)! @AndrejZacharevicz Ty 提到这一点,我已经更改了我的代码,但问题仍然存在,我得到 403 状态代码! @bigbounty 【参考方案1】:

问题似乎在于主机如何处理 ssl。较新版本的请求使用证书,在您的情况下,这与主机服务器有问题。我将请求降级到早期版本并且它有效。 (2.1.0)。您可以在 requirements.txt 中修复版本,它应该适用于任何 python 版本。

https://requests.readthedocs.io/en/master/user/advanced/#ca-certificates


Before version 2.16, Requests bundled a set of root CAs that it trusted, sourced from the Mozilla trust store. 
The certificates were only updated once for each Requests version. When certifi was not installed, this led to extremely out-of-date certificate bundles when using significantly older versions of Requests.

For the sake of security we recommend upgrading certifi frequently!

【讨论】:

谢谢,这有效,您的意思是主机拒绝新版本请求中包含的新证书集?【参考方案2】:

如requests docs 中所述,使用

body        = "referrer": referrer
data        = json.dumps(body)  # Please note that .encode() is useless here
req         = requests.post(url, headers=headers, data=data)

body        = "referrer": referrer
req         = requests.post(url, headers=headers, json=body)

但不要同时使用json.dumpsrequests.post()json 属性。选择自己执行序列化,还是让请求为您完成工作,但避免重复。

【讨论】:

谢谢你我已经更改了我的代码,但它没有解决问题抱歉。

以上是关于适用于 urllib.request 但不适用于请求的主要内容,如果未能解决你的问题,请参考以下文章

Materialise Sidenav 不适用于 iOS 或 iPhone,但适用于所有其他设备

标头位置不适用于实时服务器,但适用于 localhost

html 音频不适用于 macbook 和 ios,但适用于 imac - 很奇怪

带有firebase的Flutter HTTP包不适用于删除请求,但适用于发布,补丁和获取?

自动化测试用例适用于 appium 命令行工具,但不适用于桌面客户端

装饰器适用于函数但不适用于类