【问题标题】: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 多个。我将此功能用作一个更大系统的一部分,该系统反复发出此请求。

标签: python json python-requests


【解决方案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)..

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-08
        • 2023-03-20
        相关资源
        最近更新 更多