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爬虫偷懒神器 — 快速构造请求头!

Python 是不是有用于解析 HTTP 请求和响应的模块?

axios和ajax区别

Koa.js 服务端请求性能优化