Python-Aiohttp/Asyncio API 请求返回 ContentTypeError - JSON 具有意外的 mimetype,但并非总是如此

Python-Aiohttp/Asyncio API request returning ContentTypeError - JSON with unexpected mimetype, but not always

我正在尝试发出 API 请求,提取响应的特定块并最终将其保存到文件中以供以后处理。我还首先要提及的是,在我开始提取更大的数据集之前,该脚本可以正常工作。 当我将参数打开到更大的日期范围时,我收到: 内容类型错误( aiohttp.client_exceptions.ContentTypeError: 0, 消息='Attempt to decode JSON with unexpected mimetype: text/html'

async def get_dataset(session, url):
async with session.get(url=url, headers=headers, params=params) as resp:
    dataset = await resp.json()
    return dataset['time_entries']


async def main():
    tasks = []
    async with aiohttp.ClientSession() as session:
        for page in range(1, total_pages):
            url = "https://api.harvestapp.com/v2/time_entries?page=" + str(page)
            tasks.append(asyncio.ensure_future(get_dataset(session, url)))

        dataset = await asyncio.gather(*tasks)

如果我保持我的参数足够小,那么它可以正常工作。但是日期范围太大会弹出错误,我上面分享的代码段之后的任何内容都不会 运行 更多供参考:

url_address = "https://api.harvestapp.com/v2/time_entries/"
headers = {
    "Content-Type": 'application/json',
    "Authorization": authToken,
    "Harvest-Account-ID": accountID
}
params = {
    "from": StartDate,
    "to": EndDate
}

关于什么会导致它在某些数据大小上起作用但在更大的数据集上失败的任何想法?我假设 JSON 在某些时候变得畸形,但我不确定如何检查 and/or 以防止它发生,因为我能够从 API 中提取多个页面并成功附加到较小的数据拉取上。

OP:感谢其他给出答案的人。我发现了问题并实施了解决方案。一位朋友指出,如果响应是错误页面而不是预期的 json 内容,即 html 页面给出 429 HTTP 太多请求,aiohttp 可以 return 该错误消息。我查看了 API 限制,发现他们确实将其设置为每 15 秒 100 个请求。

我的解决方案是实现 asyncio-throttle 模块,它允许我直接限制请求和时间段。你可以在开发者 GitHub

上找到这个

这是我更新后的实现代码,非常简单!对于我的实例,我需要将我的请求限制为每 15 秒 100 个,您也可以在下面看到。

async def get_dataset(session, url, throttler):
    while True:
        async with throttler:
            async with session.get(url=url, headers=headers, params=params) as resp:
                dataset = await resp.json()
                return dataset['time_entries']


async def main():
    tasks = []
    throttler = Throttler(rate_limit=100, period=15)
    async with aiohttp.ClientSession() as session:
        try:
            for page in range(1, total_pages):
                url = "https://api.harvestapp.com/v2/time_entries?page=" + str(page)
                tasks.append(asyncio.ensure_future(get_dataset(session, url, throttler)))

            dataset = await asyncio.gather(*tasks)