Python + requests + splinter:制作多个并发'get'请求的最快/最好方法是什么?

时间:2017-05-05 16:26:08

标签: python python-2.7 browser python-requests splinter

目前正在与其他学生一起参加网络抓取课程,我们应该向虚拟网站提出“获取”请求,解析并访问其他网站。

问题是,虚拟网站的内容只会持续几分钟而消失,内容会以一定的间隔恢复。在内容可用的时间内,每个人都试图发出“获取”请求,因此我只是挂起,直到每个人都清除,内容最终消失。所以我最终无法成功发出'get'请求:

import requests
from splinter import Browser    

browser = Browser('chrome')

# Hangs here
requests.get('http://dummysite.ca').text
# Even if get is successful hangs here as well
browser.visit(parsed_url)

所以我的问题是,在得到回复之前,最快/最好的方法是做出无休止的并发“获取”请求?

5 个答案:

答案 0 :(得分:1)

  1. 决定使用requestssplinter

      

    了解Requests: HTTP for Humans
      阅读Splinter

  2. 相关

      

    了解keep-alive
      阅读blocking-or-non-blocking
      阅读timeouts
      阅读errors-and-exceptions

  3. 如果您能够未挂起请求,您可以考虑重复请求,例如:

    while True:
        requests.get(...
        if request is succesfull:
            break
    
        time.sleep(1)
    

答案 1 :(得分:1)

Gevent提供了运行异步网络请求的框架。

它可以修补Python的标准库,以便requestssplinter等现有库可以开箱即用。

以下是基于上述代码生成10个并发请求并获得响应的简短示例。

from gevent import monkey
monkey.patch_all()
import gevent.pool
import requests

pool = gevent.pool.Pool(size=10)
greenlets = [pool.spawn(requests.get, 'http://dummysite.ca')
             for _ in range(10)]
# Wait for all requests to complete
pool.join()
for greenlet in greenlets:
    # This will raise any exceptions raised by the request
    # Need to catch errors, or check if an exception was
    # thrown by checking `greenlet.exception`
    response = greenlet.get()
    text_response = response.text

还可以使用map和响应处理函数代替get

有关详细信息,请参阅gevent documentation

答案 2 :(得分:1)

在这种情况下,并发性将无济于事,因为服务器似乎是限制因素。一种解决方案是发送具有超时间隔的请求,如果超过间隔,则在几秒钟后再次尝试请求。然后逐渐增加重试之间的时间,直到获得所需的数据。例如,您的代码可能如下所示:

import time
import requests

def get_content(url, timeout):
    # raise Timeout exception if more than x sends have passed
    resp = requests.get(url, timeout=timeout)
    # raise generic exception if request is unsuccessful
    if resp.status_code != 200:
        raise LookupError('status is not 200')
    return resp.content


timeout = 5 # seconds
retry_interval = 0
max_retry_interval = 120
while True:
    try:
        response = get_content('https://example.com', timeout=timeout)
        retry_interval = 0        # reset retry interval after success
        break
    except (LookupError, requests.exceptions.Timeout):
        retry_interval += 10
        if retry_interval > max_retry_interval:
            retry_interval = max_retry_interval
        time.sleep(retry_interval)

# process response

如果需要并发,请考虑Scrapy项目。它使用Twisted框架。在Scrapy中,您可以将time.sleep替换为reactor.callLater(fn, *args, **kw),或使用数百个中间件插件中的一个。

答案 3 :(得分:0)

来自documentation for requests

  

如果远程服务器速度很慢,您可以告诉请求等待   永远为响应,通过传递None作为超时值然后   拿起一杯咖啡。

import requests

#Wait potentially forever
r = requests.get('http://dummysite.ca', timeout=None)

#Check the status code to see how the server is handling the request
print r.status_code
从2开始的

Status codes意味着收到,理解和接受了请求。 200表示请求成功并返回信息。但503表示服务器过载或正在进行维护。

请求用于包含一个名为async的模块,该模块可以发送并发请求。它现在是一个名为grequests的独立模块 您可以使用它来无休止地发出并发请求,直到200响应:

import grequests

urls = [
'http://python-requests.org', #Just include one url if you want
'http://httpbin.org',
'http://python-guide.org',
'http://kennethreitz.com'
]

def keep_going():
    rs = (grequests.get(u) for u in urls) #Make a set of unsent Requests
    out = grequests.map(rs) #Send them all at the same time
    for i in out:
        if i.status_code == 200:
            print i.text
            del urls[out.index(i)] #If we have the content, delete the URL
            return

while urls:
    keep_going() 

答案 4 :(得分:-1)

使用lxml解析器

\d{4,}

以上代码抓取gmail页面并通过添加元刷新来修改html内容。元刷新将在5秒后重定向到www.google.com。