Python 请求 - 快速知道响应是不是是 json 可解析的
Posted
技术标签:
【中文标题】Python 请求 - 快速知道响应是不是是 json 可解析的【英文标题】:Python requests - quickly know if response is json parsablePython 请求 - 快速知道响应是否是 json 可解析的 【发布时间】:2017-10-16 04:55:44 【问题描述】:我使用 Python 的 requests
库编写了某个 API 包装器。
当它使用requests.get
获得响应时,它会尝试解析为 json 并在它不起作用时获取原始内容:
resp = requests.get(url, ...)
try:
resp_content = resp.json()
except ValueError:
resp_content = resp.content
return resp_content
这对我来说是正确的。问题是当下载的响应是图像文件时需要多长时间,例如,如果它很大,那么从输入try
到json解析失败再输入except
之间需要很长时间。
(我不知道.json()
是否需要很长时间才能出错,或者一旦出错则需要一段时间才能进入except
。)
有没有办法在不尝试使用 .json()
解析的情况下查看 resp
是否是 json 可解析的? resp.is_json
之类的东西,所以我可以立即知道要采用哪个分支(resp.json()
或 resp.content
),而不是等待 30 秒(大文件可能需要几分钟)。
编辑:
如前所述,这种缓慢对于requests
json 解析来说并不典型。这可能与我收到的数据的性质有关(它来自 Salesforce REST API,正在检索附件对象的“正文”字段)。
即使这是一种解决方法,我也会将我的解决方案放在这里,以防该策略对其他人有所帮助。我意识到我在哪里进行调用,我通常知道我是否希望响应是二进制数据,所以我可以将关键字参数传递给我的包装函数,告诉它跳过 json 解析尝试。
def SalesforceWrapper(..., attempt_json=True):
resp = requests.get(url, ...)
try:
if attempt_json:
resp_content = resp.json()
else:
resp_content = resp.content
except ValueError:
resp_content = resp.content
return resp_content
然后当我期望响应是文件数据而不是 lil JSON 响应时,我通过 attempt_json=False
。
【问题讨论】:
除非您尝试实际解析文件,否则无法确定。如果数据在最后几个字节损坏,导致整个 JSON 无效怎么办?或者,您是否在问是否有办法知道响应是否应该包含 JSON 可解析的内容? 更广泛的应用程序只是一次性请求还是多个请求? @juanpa.arrivillaga 应该会好的。偶尔弄错也没关系。 那么我相信@dizzyf 的答案就是你要找的。span> @roganjosh 多个。我将此功能用作一个更大系统的一部分,该系统反复发出此请求。 【参考方案1】:您可以检查内容类型 application/json 是否在响应头中:
'application/json' in response.headers.get('Content-Type')
【讨论】:
如果Content-Type
返回'application/json; charset=utf-8'
,这将失败
@edepe 他正在使用in
运算符检查子字符串匹配,所以'application/json; charset=utf-8'
可以正常工作。【参考方案2】:
(在之前的回复中处理 Daniel Kats 的评论)
您可以检查返回的标头是否包含Content-Type application/json:
response.headers.get('Content-Type').startswith('application/json')
通过使用startswith
,您将考虑到来自https://www.w3.org/Protocols/rfc1341/4_Content-Type.html 的所有允许格式。
这并不能保证它将是有效的 JSON,但至少可以捕获未声明为 JSON 的响应。
【讨论】:
【参考方案3】:如果使用 Session 而不是直接请求。(METHOD)
from requests import Session
from simplejson.errors import JSONDecodeError
class MySession(Session):
def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
def request(self, *args, **kwargs):
res = super().request(*args, **kwargs)
json = res.json
def wrapper():
try:
return json()
except JSONDecodeError:
return None
res.json = wrapper
return res
session = MySession()
res = session.get("https://api64.ipify.org")
if res.json():
print("ok")
【讨论】:
【参考方案4】:根据响应的一致性,你可以检查返回的 headers 是否包含 content-type application/json:
resp.headers.get('content-type') == 'application/json'
【讨论】:
这个答案没有涵盖许多常见情况,包括 content-type == 'application/json; charset=utf-8'【参考方案5】:我会检查前几个 100 字节并计算 json 字符的数量,例如 ":
。或者您可以检查图像签名(JFIF、PNG、GIF89A)..
【讨论】:
以上是关于Python 请求 - 快速知道响应是不是是 json 可解析的的主要内容,如果未能解决你的问题,请参考以下文章
python+requests接口自动化2. 发送get请求与post请求(包含json格式的请求)
python+requests接口自动化2. 发送get请求与post请求(包含json格式的请求)
华为云技术分享Python爬虫偷懒神器 — 快速构造请求头!