我正在用Python 2.7.3编写一个小脚本,其中包含GRequests和lxml,它将允许我从各种网站收集一些可收集的卡价格并进行比较。问题是其中一个网站限制了请求的数量,如果我超过它,就会发回HTTP错误429。
有没有办法在grequests中增加限制请求数,这样我就不会超过我指定的每秒请求数?还有——如果HTTP 429出现,我如何让GRequestes在一段时间后重试?
另一方面,他们的限制低得可笑。大约每15秒8个请求。我多次用我的浏览器违反了它,只是刷新页面等待价格变化。
看起来没有任何简单的机制来处理请求或grequests代码中的此内置代码。似乎唯一的钩子是回应。
这里有一个超级骇人听闻的工作,至少可以证明这是可能的-我修改了grequests,以保留发出请求的时间列表,并HibernateAsyncRequest的创建,直到每秒请求数低于最大值。
class AsyncRequest(object):
def __init__(self, method, url, **kwargs):
print self,'init'
waiting=True
while waiting:
if len([x for x in q if x > time.time()-15]) < 8:
q.append(time.time())
waiting=False
else:
print self,'snoozing'
gevent.sleep(1)
你可以使用grequests。imap()以交互方式观看
import time
import rg
urls = [
'http://www.heroku.com',
'http://python-tablib.org',
'http://httpbin.org',
'http://python-requests.org',
'http://kennethreitz.com',
'http://www.cnn.com',
]
def print_url(r, *args, **kwargs):
print(r.url),time.time()
hook_dict=dict(response=print_url)
rs = (rg.get(u, hooks=hook_dict) for u in urls)
for r in rg.imap(rs):
print r
我希望有一个更优雅的解决方案,但到目前为止我还找不到。在会话和适配器中环顾四周。也许poolManager可以被增强?
另外,我不会将此代码投入生产 - “q”列表永远不会被修剪,最终会变得非常大。另外,我不知道它是否真的像广告上所说的那样工作。当我查看控制台输出时,它看起来就像这样。
啊。只要看一下代码,我就知道现在是凌晨3点。该上床睡觉了。
请看一下自动请求限制:https://pypi.python.org/pypi/RequestsThrottler/0.2.2
您可以设置每个请求之间的固定延迟量,也可以设置在固定秒数内发送的请求数(基本上是一样的):
import requests
from requests_throttler import BaseThrottler
request = requests.Request(method='GET', url='http://www.google.com')
reqs = [request for i in range(0, 5)] # An example list of requests
with BaseThrottler(name='base-throttler', delay=1.5) as bt:
throttled_requests = bt.multi_submit(reqs)
其中函数< code>multi_submit返回一个< code>ThrottledRequest列表(参见文档:末尾的链接)。
然后,您可以访问以下回复:
for tr in throttled_requests:
print tr.response
或者,您也可以通过指定在固定时间内发送的请求数(例如,每60秒发送15个请求)来实现相同的目的:
import requests
from requests_throttler import BaseThrottler
request = requests.Request(method='GET', url='http://www.google.com')
reqs = [request for i in range(0, 5)] # An example list of requests
with BaseThrottler(name='base-throttler', reqs_over_time=(15, 60)) as bt:
throttled_requests = bt.multi_submit(reqs)
这两种解决方案都可以在不使用< code>with语句的情况下实现:
import requests
from requests_throttler import BaseThrottler
request = requests.Request(method='GET', url='http://www.google.com')
reqs = [request for i in range(0, 5)] # An example list of requests
bt = BaseThrottler(name='base-throttler', delay=1.5)
bt.start()
throttled_requests = bt.multi_submit(reqs)
bt.shutdown()
更多详情:http://pythonhosted.org/RequestsThrottler/index.html
我要回答我自己的问题,因为我必须自己解决这个问题,而且关于这个问题的信息似乎很少。
想法如下。与GRequest一起使用的每个请求对象在创建时都可以将会话对象作为参数。另一方面,会话对象可以安装在发出请求时使用的HTTP适配器。通过创建我们自己的适配器,我们可以拦截请求并以最适合应用程序的方式对其进行速率限制。在我的案例中,我最终得到了下面的代码。
用于节流的对象:
DEFAULT_BURST_WINDOW = datetime.timedelta(seconds=5)
DEFAULT_WAIT_WINDOW = datetime.timedelta(seconds=15)
class BurstThrottle(object):
max_hits = None
hits = None
burst_window = None
total_window = None
timestamp = None
def __init__(self, max_hits, burst_window, wait_window):
self.max_hits = max_hits
self.hits = 0
self.burst_window = burst_window
self.total_window = burst_window + wait_window
self.timestamp = datetime.datetime.min
def throttle(self):
now = datetime.datetime.utcnow()
if now < self.timestamp + self.total_window:
if (now < self.timestamp + self.burst_window) and (self.hits < self.max_hits):
self.hits += 1
return datetime.timedelta(0)
else:
return self.timestamp + self.total_window - now
else:
self.timestamp = now
self.hits = 1
return datetime.timedelta(0)
HTTP适配器:
class MyHttpAdapter(requests.adapters.HTTPAdapter):
throttle = None
def __init__(self, pool_connections=requests.adapters.DEFAULT_POOLSIZE,
pool_maxsize=requests.adapters.DEFAULT_POOLSIZE, max_retries=requests.adapters.DEFAULT_RETRIES,
pool_block=requests.adapters.DEFAULT_POOLBLOCK, burst_window=DEFAULT_BURST_WINDOW,
wait_window=DEFAULT_WAIT_WINDOW):
self.throttle = BurstThrottle(pool_maxsize, burst_window, wait_window)
super(MyHttpAdapter, self).__init__(pool_connections=pool_connections, pool_maxsize=pool_maxsize,
max_retries=max_retries, pool_block=pool_block)
def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None):
request_successful = False
response = None
while not request_successful:
wait_time = self.throttle.throttle()
while wait_time > datetime.timedelta(0):
gevent.sleep(wait_time.total_seconds(), ref=True)
wait_time = self.throttle.throttle()
response = super(MyHttpAdapter, self).send(request, stream=stream, timeout=timeout,
verify=verify, cert=cert, proxies=proxies)
if response.status_code != 429:
request_successful = True
return response
设置:
requests_adapter = adapter.MyHttpAdapter(
pool_connections=__CONCURRENT_LIMIT__,
pool_maxsize=__CONCURRENT_LIMIT__,
max_retries=0,
pool_block=False,
burst_window=datetime.timedelta(seconds=5),
wait_window=datetime.timedelta(seconds=20))
requests_session = requests.session()
requests_session.mount('http://', requests_adapter)
requests_session.mount('https://', requests_adapter)
unsent_requests = (grequests.get(url,
hooks={'response': handle_response},
session=requests_session) for url in urls)
grequests.map(unsent_requests, size=__CONCURRENT_LIMIT__)
问题内容: 我正在用GRequests和lxml在Python 2.7.3中编写一个小脚本,这将允许我从各个网站收集一些可收集的卡价格并进行比较。问题是网站之一限制了请求的数量,如果我超过了它,则会发回HTTP错误429。 有没有一种方法可以限制GRequestes中的请求数量,以使我不超过我指定的每秒请求数量?另外-如果发生HTTP 429,如何让GRequestes在一段时间后重试? 附带说明
问题内容: 我是Docker的新手,所以很可能我缺少一些东西。 我正在使用Elasticsearch使用此图像运行容器。 我能够正确设置所有内容。之后,我使用的是一个由同事开发的脚本,用于插入一些数据,基本上是查询MySQL数据库并发出HTTP请求。 问题是,这些请求中的许多请求都会卡住,直到失败。如果我知道了: 有很多要求。在这一点上,我不确定这是否与elasticsearch或泊坞窗有关。如果
问题内容: API通常具有用户必须遵循的速率限制。举个例子,让我们50个请求/秒。连续的请求采取0.5-1秒,因此是来接近极限速度太慢。但是,使用aiohttp的并行请求超出了速率限制。 轮询API尽可能快地允许,需要限速并行调用。 例如,我发现到目前为止装饰,大约像这样: 这非常适用于连续通话。试图并行调用来实现这个按预期不起作用。 下面是一些代码示例: 这里的问题是,它会率限制 排队 的任务。
我正在使用ProjectReactor使用rest从web服务加载数据。这是与多个线程并行完成的。我开始达到web服务的速率限制,因此我希望每秒最多发送10个请求,以避免出现这些错误。用Reactor我该怎么做? 使用zipWith(Mono.delayMillis(100))?还是有更好的办法? 非常感谢。
我的计算图的一个阶段是类型的流。显然,这个阶段应该为每个请求分配一个响应,并在所有请求都被解决后发出seq。 现在,底层API有一个苛刻的速率限制策略,所以我每秒只能激发一个请求。如果我有一个的单个,我可以使用每秒发出单个元素的来这个流(如何限制Akka流每秒只执行和发送一个消息一次?),但在这种情况下我没有看到类似的解决方案。 有什么好的表达方式吗?我想到的想法是使用低层图DSL并在那里使用一秒
我正在写一个网络爬虫,运行并行抓取许多不同的域。我想限制每秒向每个域发出的请求数量,但我不关心打开的连接总数,也不关心跨所有域发出的每秒请求总数。我想最大限度地增加打开连接和每秒请求的总数,同时限制对单个域的每秒请求数。 我可以找到的所有现有示例(1)限制打开连接的数量,或(2)限制在fetch循环中每秒发出的请求总数。例子包括: aiohttp:速率限制并行请求 它们都不做我要求的事情,即限制每