【问题标题】:Why can I manually iterate this JSON Data but I'm getting errors when I try to do the same thing with a for loop?为什么我可以手动迭代这个 JSON 数据,但是当我尝试用 for 循环做同样的事情时却出错了?
【发布时间】:2021-09-17 17:56:26
【问题描述】:

asyncio 的新手,使用它来尝试更快地发出大量 API 请求,并将每个请求返回的数据存储在 dict 中。我想我已经大致了解了使用 asyncio 和 aiohttp 的语法,因为我正在获取返回的数据,但我很难获取这些数据并将其存储在一个字典中。


search_ids = [1,2,3,4,5,6,7,8,9,10]

stats = {"Date":[],"Instance ID":[],"Result":[],"Display Name":[]}


async def main():
    async with aiohttp.ClientSession() as session:
        tasks = []
        for search_id in search_ids:
            task = asyncio.ensure_future(get_data(session, search_id))
            tasks.append(task)

        responses = await asyncio.gather(*tasks)
                      
        for y in responses['entries']:
            stats['Display Name'].append(y['player']['UserInfo']['displayName'])


async def get_data(session, search_id):
    url = f'https://www.myapi.com/{search_id}'

    async with session.get(url, headers=HEADERS, ssl=False) as response:
        results = await response.json()
        
        return results['Response']

asyncio.run(main())

所以当我运行这个时,我得到一个错误:TypeError: list indices must be integers or slices, not str

这让我觉得返回的数据是不可迭代的。但是,我查看了返回的内容,这正是我所期望的。如此之多,以至于如果我将代码更改为如下所示,它可以正常工作:


search_ids = [1,2,3,4,5,6,7,8,9,10]

stats = {"Date":[],"Instance ID":[],"Result":[],"Display Name":[]}


async def main():
    async with aiohttp.ClientSession() as session:
        tasks = []
        for search_id in search_ids:
            task = asyncio.ensure_future(get_data(session, search_id))
            tasks.append(task)

        responses = await asyncio.gather(*tasks)
                      
        for y in responses:
            stats['Display Name'].append(y['entries'][0]['player']['UserInfo']['displayName'])
            stats['Display Name'].append(y['entries'][1]['player']['UserInfo']['displayName'])
            stats['Display Name'].append(y['entries'][2]['player']['UserInfo']['displayName'])
            stats['Display Name'].append(y['entries'][3]['player']['UserInfo']['displayName'])
            stats['Display Name'].append(y['entries'][4]['player']['UserInfo']['displayName'])
            stats['Display Name'].append(y['entries'][5]['player']['UserInfo']['displayName'])


async def get_data(session, search_id):
    url = f'https://www.myapi.com/{search_id}'

    async with session.get(url, headers=HEADERS, ssl=False) as response:
        results = await response.json()
        
        return results['Response']

asyncio.run(main())

我基本上不是在这里手动做同样的事情,我试图在顶部 sn-p 上使用 For 循环吗?除了我计划从每个响应中提取更多数据并且一遍又一遍地手动执行此操作之外,我会采用这种解决方法。

显然,这让我怀疑我是否正确理解了异步,这是否给了我这样一个简单的错误。

感谢任何帮助。

【问题讨论】:

  • "另外,显然这让我怀疑我是否正确理解了异步,如果这给了我这么简单的错误。"请阅读stackoverflow.com/help/minimal-reproducible-example。如果您想知道问题是否与您是否正确理解异步有关,那么您应该从尝试编写没有异步的代码开始。在这种情况下,您会发现问题仍然存在,因为困难在于您如何理解数据结构。同样,您不需要导致问题的网络连接代码,只需硬编码数据即可。
  • 我已经让这段代码在没有异步的情况下工作,现在只是试图将相同的代码移动到异步,JSON 似乎解析方式不同,目前还不清楚原因。在来这里询问之前,我已经搜索了许多其他地方的答案。

标签: python python-asyncio aiohttp


【解决方案1】:

你在迭代两个不同的东西。在第一个中,您迭代 responses[“entries”]。在第二个你使用responsesresponses 是一个列表(字典),不是字典,所以只能通过索引访问,不能通过键访问。

当您同步运行代码时,您所要做的就是遍历响应中的条目。现在您正在处理列表中的多个响应,您需要遍历响应和每个响应中的条目。为此,您需要使用两个单独的 for 循环。

responses = await asyncio.gather(
    *[get_data(session, search_id) for search_id in search_ids]
)

for response in responses:
    for entry in response["entries"]:
        stats["Display Name"].append(
            entry["player"]["UserInfo"]["displayName"]
        )

【讨论】:

  • 我按照你说的做,但我不知道如何通过索引访问。这里还有其他一些建议提到了类似的过程,但对我不起作用。当我在另一个(同步)的时候解析 JSON 结构对我来说从来都不是问题,但是由于响应返回异步,所以很难获得相同的结果,这是我猜的主要问题。
  • @terribleatthis 我添加了一些代码来展示如何迭代这两个东西。
【解决方案2】:

这可能会有所帮助

for index, y in enumerate(responses['entries']):
    stats['Display Name'].append(y['entries'][index]['player']['UserInfo']['displayName'])

【讨论】:

    【解决方案3】:

    错误是因为数据类型中的键。请根据您的第二个代码尝试此代码

    search_ids = [1,2,3,4,5,6,7,8,9,10]
    
    stats = {"Date":[],"Instance ID":[],"Result":[],"Display Name":[]}
    
    
    async def main():
        async with aiohttp.ClientSession() as session:
            tasks = []
            for search_id in search_ids:
                task = asyncio.ensure_future(get_data(session, search_id))
                tasks.append(task)
    
            responses = await asyncio.gather(
                        *[get_data(session, search_id) for search_id in search_ids])
                          
            for response in responses:
                for entry in response["entries"]:
                    stats["Display Name"].append(
                         entry["player"]["UserInfo"]["displayName"]
                         )
    
    
    async def get_data(session, carnage_id):
        url = f'https://www.myapi.com/{search_id}'
    
        async with session.get(url, headers=HEADERS, ssl=False) as response:
            results = await response.json()
            
            return results['Response']
    
    asyncio.run(main())
    

    【讨论】:

    • 您好,谢谢您的建议。我已经尝试过了,现在我收到以下错误:“IndexError: list index out of range”
    • 您好,我已经用嵌套的 forloop 更新了 for 循环。如果您可以共享响应变量的整个数据结构,那将非常有帮助。 打印(响应)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    • 1970-01-01
    相关资源
    最近更新 更多