【问题标题】:Python Extract JSON from HTTP ResponsePython 从 HTTP 响应中提取 JSON
【发布时间】:2014-01-25 22:54:13
【问题描述】:

假设我有以下 HTTP 请求:

GET /4 HTTP/1.1
Host: graph.facebook.com

并且服务器返回以下响应:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Cache-Control: private, no-cache, no-store, must-revalidate
Content-Type: text/javascript; charset=UTF-8
ETag: "539feb8aee5c3d20a2ebacd02db380b27243b255"
Expires: Sat, 01 Jan 2000 00:00:00 GMT
Pragma: no-cache
X-FB-Rev: 1070755
X-FB-Debug: pC4b0ONpdhLwBn6jcabovcZf44bkfKSEguNsVKuSI1I=
Date: Wed, 08 Jan 2014 01:22:36 GMT
Connection: keep-alive
Content-Length: 172

{"id":"4","name":"Mark Zuckerberg","first_name":"Mark","last_name":"Zuckerberg","link":"http:\/\/www.facebook.com\/zuck","username":"zuck","gender":"male","locale":"en_US"}

由于Content-Lengh 标头取决于内容的长度,我不能简单地通过Content-Length: 172 字符串进行拆分。如何分别提取 JSON 和标头?它们对我的程序都很重要。 我正在使用此代码来获取响应:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("graph.facebook.com", 80))
s.send("GET /"+str(id)+"/picture HTTP/1.1\r\nHost: graph.facebook.com\r\n\r\n")
data = s.recv(1024)
s.close()
json_string = (somehow extract this)
userdata = json.loads(json_string)

【问题讨论】:

  • a) 那不是\r\n\r\n b) 我希望在一行中更优雅地完成所有这些操作但感谢您的建议
  • 取决于您的服务器操作系统,但您可以使用| 运算符。快速谷歌搜索显示this
  • 我可能会使用 requests 库并执行 somerequest.json().docs.python-requests.org/en/latest
  • @erewok python 2.7 也支持这个吗?
  • @735Tesla: requests 在 Python 2.7 上受支持,但它是第三方安装。这里绝对不需要它;标准库中的urllib2 将同样方便您使用。

标签: python regex json http http-headers


【解决方案1】:

执行此操作的简单方法是使用 HTTP 库。例如:

import json
import urllib2

r = urllib2.urlopen("http://graph.facebook.com/{}/picture".format(id))
json_string = r.read()
userdata = json.loads(json_string)

如果你真的想自己解析它,HTTP protocol 保证标题和正文用空行分隔,这将是响应中任何位置的第一个空行,所以并不难:

data = s.recv(1024)
header, _, json_string = data.partition('\r\n\r\n')
userdata = json.loads(json_string)

这有一些明显的缺点——如所写,如果响应长于 1K,或者如果内核没有在单个 recv 中给你完整的响应(它是永远不会保证这样做),或者如果服务器在真正响应之前重定向你或给你一个 100 CONTINUE,或者如果服务器决定发回分块或 MIME-multipart 或其他响应而不是扁平体,或者......

【讨论】:

  • header, _, 中的, _, 的用途是什么?
  • @735Tesla:str.partition返回三个值:分隔符之前的部分、分隔符和分隔符之后的部分。通常你不需要中间那个(你知道它只是'\r\n\r\n' 这里......)。将无关值分配给 _ 是 Python 中的一个常见习语——它的可读性足以让您知道那里有一个值,但又足够不显眼,表明该值除了注意到它的存在之外并不重要。
  • 谢谢 我以前从未听说过这样使用_。 +1
  • 这比我的回答要好得多。 +1