Python使用Requests发送HTTP请求并传输二进制数据

6
以下代码只能在curl中运行。如果您能告诉我为什么在使用Requests的Python中无法正常工作,那就太好了。
curl 'http://cdcnepal.com/Modules/HOmeMoviesLists/WebService2.asmx/GetShowsByDate' \
 -H 'Content-Type: application/json; charset=UTF-8' \
 -d '{"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}'

然而,在Python中使用以下代码:
import requests
import json
url = """http://cdcnepal.com/Modules/HOmeMoviesLists/WebService2.asmx/GetShowsByDate"""
headers = {"content-type":["application/json", "charset=UTF-8"]}
payload = {"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}
r = requests.get(url, headers=headers, data=payload)
print r.text

原来的curl请求内容如下,但我意识到可以删除几个内容。不确定这是否导致错误,因为curl请求正在工作中。我从代码中没有得到相同的响应。

这可能有用。从Chrome Dev Tools中提取的Curl请求

curl 'http://cdcnepal.com/Modules/HOmeMoviesLists/WebService2.asmx/GetShowsByDate'
 -H 'Cookie: OriginalReferrer=https://www.google.com/;
     OriginalURL=http://cdcnepal.com/;
     ASP.NET_SessionId=i5lbnql5hpp0wm1ywyqbywtj;
     VisitCount=4' 
 -H 'Origin: http://cdcnepal.com' 
 -H 'Accept-Encoding: gzip,deflate,sdch' 
 -H 'Accept-Language: en-US,en;q=0.8,hi;q=0.6' 
 -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3)
     AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36' 
 -H 'Content-Type: application/json; charset=UTF-8' 
 -H 'Accept: application/json, text/javascript, */*; q=0.01' 
 -H 'Referer:http://cdcnepal.com/Home.aspx' 
 -H 'X-Requested-With: XMLHttpRequest' -H 'Connection: keep-alive' 
 -H 'DNT: 1' 
 --data-binary '{"portalId":"1","showDate":"27/05/2014","flag":0,"size":9}' --compressed
1个回答

15

curl-d 开关会发送一个 POST 请求,但你正在使用 requests.get() 发送一个 GET 请求(其请求体将被忽略)。

使用 requests.post() 将其改为 POST 请求:

import requests
import json

url = "http://cdcnepal.com/Modules/HOmeMoviesLists/WebService2.asmx/GetShowsByDate"
headers = {"content-type": "application/json; charset=UTF-8"}
payload = {"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}
r = requests.post(url, headers=headers, data=json.dumps(payload))
print r.text

你还需要:

  1. 不要为content-type头使用列表,因为不支持单独指定参数。
  2. 将JSON数据编码为JSON字符串;requests不会为您执行此操作。相反,传递给data的字典将被编码为application/x-www-form-urlencoded数据。

您可以使用http://httpbin.org/post更轻松地比较curl命令和requests

$ curl http://httpbin.org/post \
>  -H 'Content-Type: application/json; charset=UTF-8' \
>  -d '{"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}'

{
  "args": {},
  "data": "{\"portalId\":\"1\",\"showDate\":\"26/05/2014\",\"flag\":0,\"size\":9}",
  "files": {},
  "form": {},
  "headers": {
    "Accept": "*/*",
    "Connection": "close",
    "Content-Length": "58",
    "Content-Type": "application/json; charset=UTF-8",
    "Host": "httpbin.org",
    "User-Agent": "curl/7.30.0",
    "X-Request-Id": "78d7bb7d-e29b-482b-908a-48d2395a050f"
  },
  "json": {
    "flag": 0,
    "portalId": "1",
    "showDate": "26/05/2014",
    "size": 9
  },
  "origin": "84.92.98.170",
  "url": "http://httpbin.org/post"
}

>>> import requests
>>> import json
>>> from pprint import pprint
>>> url = 'http://httpbin.org/post'
>>> headers = {"content-type":"application/json; charset=UTF-8"}
>>> payload = {"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}
>>> r = requests.post(url, headers=headers, data=json.dumps(payload))
>>> pprint(r.json())
{u'args': {},
 u'data': u'{"portalId": "1", "flag": 0, "size": 9, "showDate": "26/05/2014"}',
 u'files': {},
 u'form': {},
 u'headers': {u'Accept': u'*/*',
              u'Accept-Encoding': u'gzip, deflate, compress',
              u'Connection': u'close',
              u'Content-Length': u'65',
              u'Content-Type': u'application/json; charset=UTF-8',
              u'Host': u'httpbin.org',
              u'User-Agent': u'python-requests/2.2.1 CPython/2.7.6 Darwin/13.1.0',
              u'X-Request-Id': u'06d6b542-c279-4898-8701-2c0d502aa36e'},
 u'json': {u'flag': 0,
           u'portalId': u'1',
           u'showDate': u'26/05/2014',
           u'size': 9},
 u'origin': u'84.92.98.170',
 u'url': u'http://httpbin.org/post'}

两种情况都显示返回相同的json字典。

如果您使用的是2.4.2或更高版本的requests,您还可以将JSON编码留给库;如果您将要发送的数据作为json关键字参数传递,它还将设置正确的Content-Type头:

import requests

url = "http://cdcnepal.com/Modules/HOmeMoviesLists/WebService2.asmx/GetShowsByDate"
payload = {"portalId":"1","showDate":"26/05/2014","flag":0,"size":9}
r = requests.post(url, json=payload)
print r.text

我尝试了你说的,但是出现了一个错误 [{"Message":"处理请求时发生错误。","StackTrace":"","ExceptionType":""}]。甚至尝试添加cUrl的用户代理也没有用...还有其他什么可以尝试的吗? - ShapNepal
@ShapNepal:对于您的URL,我得到了与CURL响应完全相同的JSON响应。它对我有效。 - Martijn Pieters
@ShapNepal:请确保你的代码与我的回答一致;如果我将回答开头的代码复制粘贴到Python交互式解释器中,它会打印出完整的JSON响应。 - Martijn Pieters
是的!!在iPython中可以工作了,有趣的是,我之前使用Sublime Text 3时出现了错误。谢谢大家! - ShapNepal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接