Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何降低异步API调用的速度以符合API限制?_Python_Python 3.x_Asynchronous_Api Design_Grequests - Fatal编程技术网

Python 如何降低异步API调用的速度以符合API限制?

Python 如何降低异步API调用的速度以符合API限制?,python,python-3.x,asynchronous,api-design,grequests,Python,Python 3.x,Asynchronous,Api Design,Grequests,我有一个约300K URL的列表,用于我需要从中获取数据的API API限制为每秒100次调用 我已经为异步开发了一个类,但是这个类的速度太快了,我在API上遇到了一个错误 如何降低异步进程的速度,以便每秒可以进行100次调用 import grequests lst = ['url.com','url2.com'] class Test: def __init__(self): self.urls = lst def exception(self, req

我有一个约300K URL的列表,用于我需要从中获取数据的API

API限制为每秒100次调用

我已经为异步开发了一个类,但是这个类的速度太快了,我在API上遇到了一个错误

如何降低异步进程的速度,以便每秒可以进行100次调用

import grequests

lst = ['url.com','url2.com']

class Test:
    def __init__(self):
        self.urls = lst

    def exception(self, request, exception):
        print ("Problem: {}: {}".format(request.url, exception))

    def async(self):
        return grequests.map((grequests.get(u) for u in self.urls), exception_handler=self.exception, size=5)



    def collate_responses(self, results):
        return [x.text for x in results]

test = Test()
#here we collect the results returned by the async function
results = test.async()
response_text = test.collate_responses(results)

SO中的另一个问题正好说明了如何做到这一点。顺便说一句,您需要的通常称为节流。

您只需跟踪时间的流逝,并决定是否要执行更多请求

这将每秒打印100个数字,例如:

from datetime import datetime
import time

start = datetime.now()
time.sleep(1);
counter = 0
while (True):
    end = datetime.now()
    s = (end-start).seconds
    if (counter >= 100):
        if (s <= 1):
            time.sleep(1) # You can keep track of the time and sleep less, actually
            start = datetime.now()
            counter = 0
    print(counter)
    counter += 1
从日期时间导入日期时间
导入时间
start=datetime.now()
睡眠时间(1);
计数器=0
虽然(正确):
end=datetime.now()
s=(结束-开始)。秒
如果(计数器>=100):

如果(s我采取的第一步是创建一个对象,该对象可以每毫秒最多分发n个硬币

import time

class CoinsDistribution:
    """Object that distribute a maximum of maxCoins every timeLimit ms"""
    def __init__(self, maxCoins, timeLimit):
        self.maxCoins = maxCoins
        self.timeLimit = timeLimit
        self.coin = maxCoins
        self.time = time.perf_counter()


    def getCoin(self):
        if self.coin <= 0 and not self.restock():
            return False

        self.coin -= 1
        return True

    def restock(self):
        t = time.perf_counter()
        if (t - self.time) * 1000 < self.timeLimit:
            return False
        self.coin = self.maxCoins
        self.time = t
        return True
但有时,多个函数调用请求同一服务器,因此我们希望它们从同一CoinsDistribution对象获取硬币。 因此,装饰器的另一个用途是提供CoinsDistribution对象:

server_2_limit = CoinsDistribution(3, 1000)

@limitCalls(server_2_limit)
def sendRequestToServer2():
    return 'it worked !!'

@limitCalls(server_2_limit)
def sendAnOtherRequestToServer2():
    return 'it worked too !!'
我们现在必须创建decorator,它可以获取CoinsDistribution对象或足够的数据来创建一个新对象

import functools

def limitCalls(obj=None, *, callLimit=100, timeLimit=1000):
    if obj is None:
        obj = CoinsDistribution(callLimit, timeLimit)

    def limit_decorator(func):
        @functools.wraps(func)
        def limit_wrapper(*args, **kwargs):
            if obj.getCoin():
                return func(*args, **kwargs)
            return 'limit reached, please wait'
        return limit_wrapper
    return limit_decorator
完成了!现在您可以限制所使用的任何API的调用数量,并且如果您必须管理大量的CoinsDistribution对象(到不同的API端点或到不同的API),您可以构建一个字典来跟踪它们


注意:在这里,如果没有可用硬币,我选择返回一条错误消息。您应该根据自己的需要调整此行为。

尝试睡眠(),但我建议您可以使用iProxy模块,减速不是必要的选择。@Henryyuan感谢您的建议。当我阅读iProxy时,我应该在哪里应用睡眠()在代码中?以及睡眠多长时间()?通过单独的异步调用每秒发送100个请求。您还可以限制活动请求的最大数量(您可以在发送请求时添加请求,在返回请求时删除请求,以便知道有多少个请求处于活动状态)。这两件事应该解决。@E.Serra我不知道如何在另一个异步调用中实现每秒100次。请用代码向我展示您的建议。如果有类似于
节流
模块的东西导致每秒API限制调用,您可以调用use Ipproxy模块,通过使用代理向sk发送请求ip这个问题。据我所知,你想要实现一个爬虫。我不理解实现。需要将其解码到我的代码中。谢谢你的建议。我希望有人能给我一个更简单的解决方案。实现的解决方案在错误429处停止,我不需要,我只需要每秒批处理100个URL。好吧,如果你是e使用请求而不是grequests,这就像睡觉一样简单。但我想你还有其他一些要求让你使用grequests。请求能在相对较短的时间内处理大约250K个呼叫吗?因为当我尝试请求时需要很长时间。老实说,我不知道。但是如果你不得不这样做的话放慢速度到每秒100次,我想谁更快没什么大不了的。至少需要41分钟。谢谢你的回答,我不知道如何利用时间来批量处理我打过的电话。你能告诉我我的代码如何适应你的代码吗。
import functools

def limitCalls(obj=None, *, callLimit=100, timeLimit=1000):
    if obj is None:
        obj = CoinsDistribution(callLimit, timeLimit)

    def limit_decorator(func):
        @functools.wraps(func)
        def limit_wrapper(*args, **kwargs):
            if obj.getCoin():
                return func(*args, **kwargs)
            return 'limit reached, please wait'
        return limit_wrapper
    return limit_decorator