如何使用 asyncio 和 aiohttp 异步通过 api 响应进行分页

Posted

技术标签:

【中文标题】如何使用 asyncio 和 aiohttp 异步通过 api 响应进行分页【英文标题】:How paginate through api response asynchronously with asyncio and aiohttp 【发布时间】:2019-05-22 02:49:58 【问题描述】:

我正在尝试使用 python 异步进行 api 调用。我在一个列表中有多个端点,每个端点都会返回分页结果。我可以设置异步通过多个端点,但是无法返回每个端点的分页结果。

通过调试,我发现fetch_more() 函数运行while 循环,但实际上并没有通过session.get() 的异步。所以基本上。函数 fetch_more() 旨在从每个端点的 api 调用中获取剩余结果,但是我发现无论是否使用 fetch_more() 函数都会返回相同数量的结果。我尝试寻找使用 asyncio 进行分页的示例,但运气不佳。

据我了解,我不应该在 while 循环内发出请求,但是,我不确定是否有办法绕过它以获得分页结果。

if __name__ == 'main':

    starter_fun(url, header, endpoints):

starter_func(url, header, endpoints):

    loop = asyncio.get_event_loop() #event loop
    future = asyncio.ensure_future(fetch_all(url, header, endpoints))
    loop.run_until_complete(future) #loop until done

async def fetch_all(url, header, endpoints):

    async with ClientSession() as session:
        for endpoint in endpoints:
           task = asyncio.ensure_future(fetch(url, header, endpoint))
           tasks.append(task)
        res = await asyncio.gather(*tasks) # gather task responses
        return res

async def fetch(url, header, endpoint): 

    total_tasks = []
    async with session.get(url, headers=header, params=params, ssl=False) as response:
        response_json = await response.json()
        data = response_json['key']
       tasks = asyncio.ensure_future(fetch_more(response_json, data, params, header, url, endpoint, session)) //this is where I am getting stuck
        total_tasks.append(tasks)
    return data


//function to get paginated results of api endpoint
async def fetch_more(response_json, data, params, header, url, endpoint, session): //this is where I am getting stuck

    while len(response_json['key']) >= params['limit']:
        params['offset'] = response_json['offset'] + len(response_json['key'])
        async with session.get(url, headers=header, params=params, ssl=False) as response_continued:
            resp_continued_json = await response_continued.json()
            data.extend(resp_continued_json[kebab_to_camel(endpoint)])
   return data

目前,无论是否使用 fetch_more 函数,我都会得到 1000 个结果,但是使用 fetch_more 应该会更多。关于如何处理异步分页的任何想法?

【问题讨论】:

【参考方案1】:
from aiohttp import web

 async def fetch(self size: int = 10):

    data = "some code to fetch data here"

    def paginate(_data, _size):
        import itertools

        while True:
            i1, i2 = itertools.tee(_data)
            _data, page = (itertools.islice(i1, _size, None),
                              list(itertools.islice(i2, _size)))
            if len(page) == 0:
                break
            yield page

    return web.json_response(list(paginate(_data=data, _size=size)))

【讨论】:

以上是关于如何使用 asyncio 和 aiohttp 异步通过 api 响应进行分页的主要内容,如果未能解决你的问题,请参考以下文章

python 使用Python的aiohttp和asyncio进行多个异步HTTP GET请求

Python学习---IO的异步[asyncio +aiohttp模块]

Python使用asyncio+aiohttp异步爬取猫眼电影专业版

多任务异步协程,asyncio及aiohttp

Python有了asyncio和aiohttp在爬虫这类型IO任务中多线程/多进程还有存在的必要吗?

使用 flask-aiohttp 的异步子进程