我有一个 Python 爬虫,它请求在以下位置找到的 JSON 的内容:
https://www.saltybet.com/state.json
代码:
import requests
import time
class SaltyJson():
def __init__(self):
self.url = "https://www.saltybet.com/state.json"
self.session = requests.Session()
def get_json(self):
try:
self.response = self.session.get(self.url,
headers={"User-Agent": "Mozilla/5.0", "Accept": "application/json"})
if self.response.status_code != 200:
time.sleep(1)
self.get_json()
else:
return self.response.json()
except requests.exceptions.ConnectionError:
time.sleep(1)
self.get_json()
except requests.exceptions.JSONDecodeError:
time.sleep(1)
self.get_json()
GET 请求最初有效,但通常在几个小时后,我会收到
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
错误。看来我收到的是空响应(即 self.response.json()
返回 None
)。即使返回 200 服务器状态代码也会发生这种情况。
这个问题一直具有挑战性,因为它本质上是零星的,而且我在 SO 上看到的处理此错误的大多数情况都是由于 JSON 无效,User-Agent / Accept 标头丢失,服务器提供错误状态代码。就我而言,我的请求在 99% 的时间内都有效,但我偶尔会收到此空白响应,即使返回的服务器状态代码指示成功响应 (200)。
我查过 JSONDecodeError,我的理解是,如果它在
char 0
上出错,那么整个 JSON 无效或者是空白响应。如果我使用 except 子句处理 JSONDecodeError,JSON 似乎返回 None。尝试从 JSON 字典访问值 self.json_dict["remaining"]
,返回 TypeError: 'NoneType' object is not subscriptable
。我的调试器说 json_dict 是{NoneType}
,我将其解释为整个字典为 None,这不是空键/值的问题。
我试过的东西:
添加指数退避以防这是服务器速率限制的一种形式
添加服务器状态代码 200 的检查
检查 json 键的数量是否与预期输出匹配 (
len(list(self.response.json().keys())) == 8
)
我注意到关于 URL 的一件事是内容类型标头是 text/html,而不是 application/json。即使我的 GET 请求具有
"Accept":"application/json"
标头,响应的内容类型似乎仍然是 text/html
。查看网站的javascript代码,内容类型指定为application/json ...
url: "../state.json" + "?t=" + ms,
contentType: "application/json; charset=utf-8",
我的两个问题:
我的 GET 请求是否有问题,可能是传递的标头有问题,导致偶尔出现空白响应?这个问题是否可能与内容类型是
text/html
有关,即使内容应该只是有效的JSON?
假设这是一个空白/空的响应,除了检查服务器状态代码之外,我是否需要在我的代码中添加额外的检查?我在 try-catch 块中处理 JSONDecodeError,但在收到此空白响应时重试时遇到问题,程序似乎没有再次请求会话并获取新的 JSON 数据,它只是反复尝试使用空白失败JSON字典。