【问题标题】:python requests POST with header and parameterspython请求带有标头和参数的POST
【发布时间】:2018-12-09 23:50:39
【问题描述】:

我有一个帖子请求,我试图在 python 中使用requests 发送。但我得到一个无效的 403 错误。请求可以通过浏览器正常工作。

POST /ajax-load-system HTTP/1.1
Host: xyz.website.com
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-GB,en;q=0.5
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Referer: http://xyz.website.com/help-me/ZYc5Yn
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 56
Cookie: csrf_cookie_name=a3f8adecbf11e29c006d9817be96e8d4; ci_session=ba92hlh6o0ns7f20t4bsgjt0uqfdmdtl; _ga=GA1.2.1535910352.1530452604; _gid=GA1.2.1416631165.1530452604; _gat_gtag_UA_21820217_30=1
Connection: close

csrf_test_name=a3f8adecbf11e29c006d9817be96e8d4&vID=9999

我在 python 中尝试的是:

import requests
import json

url = 'http://xyz.website.com/ajax-load-system'

payload = {
'Host': 'xyz.website.com',
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Language': 'en-GB,en;q=0.5',
'Referer': 'http://xyz.website.com/help-me/ZYc5Yn',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest',
'Content-Length': '56',
'Cookie': 'csrf_cookie_name=a3f8adecbf11e29c006d9817be96e8d4; ci_session=ba92hlh6o0ns7f20t4bsgjt0uqfdmdtl; _ga=GA1.2.1535910352.1530452604; _gid=GA1.2.1416631165.1530452604; _gat_gtag_UA_21820217_30=1',
'Connection': 'close',
'csrf_test_name': 'a3f8adecbf11e29c006d9817be96e8d4',
'vID': '9999',
}    

headers = {}

r = requests.post(url, headers=headers, data=json.dumps(payload))
print(r.status_code)  

但这是打印403 错误代码。我在这里做错了什么?

我期待一个 json 格式的返回响应:

{"status_message":"Thanks for help.","help_count":"141","status":true}

【问题讨论】:

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


【解决方案1】:

您混淆了标头和有效负载,有效负载不是 JSON 编码的

这些都是标题:

Host: xyz.website.com
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-GB,en;q=0.5
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0
Referer: http://xyz.website.com/help-me/ZYc5Yn
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 56
Cookie: csrf_cookie_name=a3f8adecbf11e29c006d9817be96e8d4; ci_session=ba92hlh6o0ns7f20t4bsgjt0uqfdmdtl; _ga=GA1.2.1535910352.1530452604; _gid=GA1.2.1416631165.1530452604; _gat_gtag_UA_21820217_30=1
Connection: close

其中大部分是自动化的,无需手动设置。 requests 将根据 URL 为您设置 HostAccept 设置为可接受的默认值,Accept-Language 在这些情况下很少需要,Referer,除非使用 HTTPS,通常甚至不设置或过滤出于隐私原因,网站不再依赖于它的设置,Content-Type 必须实际反映您的 POST 的内容(并且不是 JSON!),所以 requests 为您设置它取决于您如何称呼它, Content-Length 必须反映实际的内容长度,所以由 requests 设置,因为它处于计算这个的最佳位置,并且 Connection 绝对应该由库处理,因为你不想阻止它如果可以的话,有效地重用连接。

充其量你可以设置X-Requested-WithUser-Agent,但前提是服务器不会接受请求。 Cookies 标头反映了浏览器保存的 cookie 的值。您的脚本可以通过使用requests Session objectReferer 标头中指定的url(或同一站点上的其他合适的URL)发出初始GET 请求,从服务器获取它们自己的cookie 集,此时服务器应该在响应中设置 cookie,这些 cookie 将存储在会话中,以便在发布请求中重用。使用该机制获取您自己的 CSRF cookie 值。

注意Content-Type 标头:

Content-Type: application/x-www-form-urlencoded; charset=UTF-8

当您将字典传递给requests.post() 函数的data 关键字时,库会为您将数据编码为该内容类型。

实际有效载荷是

csrf_test_name=a3f8adecbf11e29c006d9817be96e8d4&vID=9999

这是csrf_test_namevID 这两个字段,它们需要成为payload 字典的一部分。

请注意,csrf_test_name与 cookie 中的 csrf_cookie_name 值匹配。这就是网站如何保护自己免受Cross-site forgery attacks 的侵害,第三方可能会尝试代表您发布到相同的 URL。这样的第三方将无法访问相同的 cookie,因此将被阻止。 您的代码需要获取一个新的 cookie;正确的 CSRF 实现会限制任何 CSRF cookie 可以重复使用的时间。

那么至少需要什么才能使这一切正常工作,是:

# *optional*, the site may not care about these. If they *do* care, then
# they care about keeping out automated scripts and could in future 
# raise the stakes and require more 'browser-like' markers. Ask yourself
# if you want to anger the site owners and get into an arms race.
headers = {
    'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0',
    'X-Requested-With': 'XMLHttpRequest',
}

payload = {
    'vID': 9999,
}

url = 'http://xyz.website.com/ajax-load-system'
# the URL from the Referer header, but others at the site would probably
# also work
initial_url = 'http://xyz.website.com/help-me/ZYc5Yn'

with requests.Session() as session:
    # obtain CSRF cookie
    initial_response  = session.get(initial_url)
    payload['csrf_test_name'] = session.cookies['csrf_cookie_name']

    # Now actually post with the correct CSRF cookie
    response = session.post(url, headers=headers, data=payload)

如果这仍然导致问题,您需要尝试另外两个标头,AcceptAccept-Language。考虑到这将意味着该网站已经考虑过如何让自动网站抓取工具退出。考虑联系他们并询问他们是否提供 API 选项。

【讨论】:

  • 所以headers = {Host: xyz.website.com Accept: application/json, text/javascript, */*; q=0.01 Accept-Language: en-GB,en;q=0.5 .... etc}payload = { "csrf_test_name": "a3f8adecbf11e29c006d9817be96e8d4", "vID": "9999" }r = requests.post(url, headers=headers, data=json.dumps(payload)) 但这也没有用:(
  • @GauravKhe:一定要清楚没用。我已经告诉过您该网站不使用 JSON。而且这些标头中的大多数都是自动的,由请求处理。
  • 谢谢。谢谢你的精彩解释。我很困惑,但这清除了所有概念:)
  • @Martijn Pieters 我尝试了这种方法,响应为 200。我无法得到这一行,这在我的 cookie 中不存在。可以提供任何帮助吗?
  • @MarxBabu:不知道你在问什么。什么是你无法得到的“这条线”?你得到什么响应体?评论不是提问的好地方,但是,也许您应该发布一个新问题。
猜你喜欢
  • 2015-02-24
  • 2020-12-23
  • 2017-08-31
  • 1970-01-01
  • 1970-01-01
  • 2013-08-03
  • 2020-01-13
  • 2016-02-06
  • 1970-01-01
相关资源
最近更新 更多