发送同时请求python(一次全部)

Posted

技术标签:

【中文标题】发送同时请求python(一次全部)【英文标题】:Send Simultaneous Requests python (all at once) 【发布时间】:2016-11-03 00:19:29 【问题描述】:

我正在尝试创建一个脚本,可以同时向一个页面发送超过 1000 个请求。但是请求带有线程(1000)线程的库。似乎在 1 秒内完成了前 50 个左右的请求,而其他 9950 个请求则花费了相当长的时间。我是这样测量的。

def print_to_cmd(strinng):
    queueLock.acquire()
    print strinng
    queueLock.release()

    start = time.time()
    resp = requests.get('http://test.net/', headers=header)
    end = time.time()

    print_to_cmd(str(end-start))

我认为请求库限制了它们的发送速度。

有人知道在 python 中同时发送请求的方法吗?我有一个上传 200mb 的 VPS,所以这不是问题,它与 python 或请求库限制它有关。他们都需要在 1 秒内互相访问网站。

感谢阅读,希望有人能提供帮助。

【问题讨论】:

您是否要让网站超载? 没有人会帮你 DDOS 一个网站。 如果我想对一个网站进行 DDOS,我会使用多个带有 shell 的服务器。 您可以查看BoundedSemaphore(或Python 2)。就并发吞吐量而言,它可能比简单的锁更灵活。 【参考方案1】:

我通常发现最好的解决方案是使用像 tornado 这样的异步库。然而,我发现最简单的解决方案是使用 ThreadPoolExecutor。


import requests
from concurrent.futures import ThreadPoolExecutor

def get_url(url):
    return requests.get(url)
with ThreadPoolExecutor(max_workers=50) as pool:
    print(list(pool.map(get_url,list_of_urls)))

【讨论】:

当然,您可能想使用 max_workers 参数来获得更快的运行时间 是的,我注意到 1k 个请求需要更长的时间。不过还是比之前的好 有错别字,我确实纠正了它:print(list(pool.map(get_url(list_of_urls))) @Enderphan 不,看看map 是如何工作的:docs.python.org/3/library/functions.html#map ThreadPoolExecutor().map() 是同样的想法。 它给了我错误 requests.exceptions.ConnectionError: ('Connection aborted.', RemoteDisconnected('Remote end closed connection without response'))【参考方案2】:

我知道这是一个老问题,但您现在可以使用 asyncioaiohttp 来做到这一点。

import asyncio
import aiohttp
from aiohttp import ClientSession

async def fetch_html(url: str, session: ClientSession, **kwargs) -> str:
    resp = await session.request(method="GET", url=url, **kwargs)
    resp.raise_for_status()
    return await resp.text()

async def make_requests(url: str, **kwargs) -> None:
    async with ClientSession() as session:
        tasks = []
        for i in range(1,1000):
            tasks.append(
                fetch_html(url=url, session=session, **kwargs)
            )
        results = await asyncio.gather(*tasks)
        # do something with results

if __name__ == "__main__":
    asyncio.run(make_requests(url='http://test.net/'))

您可以阅读更多相关信息并查看示例 here。

【讨论】:

asyncio.run 是 Python 3.7 的新增功能。以前的版本可以参考这个discussion【参考方案3】:

假设您知道自己在做什么,我首先建议您实施带有抖动的退避策略,以防止“可预测的雷击囤积”到您的服务器。也就是说,你应该考虑做一些threading

import threading
class FuncThread(threading.Thread):
    def __init__(self, target, *args):
        self._target = target
        self._args = args
        threading.Thread.__init__(self)

    def run(self):
        self._target(*self._args)

这样你就可以做类似的事情

t = FuncThread(doApiCall, url)
t.start()

你的方法 doApiCall 是这样定义的

def doApiCall(self, url):

【讨论】:

您好,感谢您的快速响应。我在之前的尝试中使用了线程,但使用 python 的请求库发送了请求。这个请求不需要使用 urllib 或 requests 吗?

以上是关于发送同时请求python(一次全部)的主要内容,如果未能解决你的问题,请参考以下文章

后台接口总是请求两次

Python学习记录-----批量发送post请求

发送一批 http 请求时的天线使用情况

python实现QQ机器人(自己主动登录,获取群消息,发送群消息)

异步请求(获取json数据)

Ajax(jquery) 同时处理多个异步请求