【问题标题】:Understanding requests versus grequests了解请求与请求
【发布时间】:2018-02-22 15:13:32
【问题描述】:

我正在使用一个基本上如下的流程:

  1. 获取一些网址列表。
  2. 从每个对象中获取一个Response 对象。
  3. 从每个响应的text 创建一个 BeautifulSoup 对象。
  4. 从 BeautifulSoup 对象中提取某个标签的文本。

据我了解,这似乎是grequests 的理想选择:

GRequests 允许您将 Requests 与 Gevent 一起使用以进行异步 HTTP 请求很容易。

但是,这两个进程(一个带有请求,一个带有 grequests)似乎给我带来了不同的结果,grequests 中的一些请求返回 None 而不是响应。

使用请求

import requests

tickers = [
    'A', 'AAL', 'AAP', 'AAPL', 'ABBV', 'ABC', 'ABT', 'ACN', 'ADBE', 'ADI', 
    'ADM',  'ADP', 'ADS', 'ADSK', 'AEE', 'AEP', 'AES', 'AET', 'AFL', 'AGN', 
    'AIG', 'AIV', 'AIZ', 'AJG', 'AKAM', 'ALB', 'ALGN', 'ALK', 'ALL', 'ALLE',
    ]

BASE = 'https://finance.google.com/finance?q={}'

rs = (requests.get(u) for u in [BASE.format(t) for t in tickers])
rs = list(rs)

rs
# [<Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # ...
 # <Response [200]>]

# All are okay (status_code == 200)

使用 grequests

# Restarted my interpreter and redefined `tickers` and `BASE`
import grequests

rs = (grequests.get(u) for u in [BASE.format(t) for t in tickers])
rs = grequests.map(rs)

rs
# [None,
 # <Response [200]>,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # None,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>,
 # <Response [200]>]

为什么结果不同?

更新:我可以按如下方式打印异常类型。相关讨论here,但我不知道发生了什么。

def exception_handler(request, exception):
    print(exception)

rs = grequests.map(rs, exception_handler=exception_handler)

# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)
# ("bad handshake: SysCallError(-1, 'Unexpected EOF')",)

系统/版本信息

  • 请求:2.18.4
  • 请求:0.3.0
  • Python:3.6.3
  • urllib3: 1.22
  • pyopenssl: 17.2.0
  • 全部来自 Anaconda
  • 系统:Mac OSX HS 和 Windows 10 上的相同问题,内部版本 10.0.16299

【问题讨论】:

  • 如果您查看README,它表明失败的请求会导致None。我猜当你一次发出太多未经身份验证的请求时,谷歌会生气。阅读自述文件中的更多内容描述了如何编写一个异常处理程序来告诉你发生了什么。
  • 打印异常,而不是固定字符串
  • 如果是系统问题,您可能需要包含更多信息,例如您的操作系统及其版本、Python 版本/构建,以及请求版本、grequests、urllib3、PyOpenSSL(如果已安装)。听起来更像是一个错误报告......
  • 你可以尝试使用grequests.map(rs, size=2)限制gevent并发
  • 我在github site 上看到了这条评论:“注意:您可能应该改用 requests-threads 或 requests-futures。”此外,最后一次代码更新似乎是在 2 年前。

标签: python python-3.x python-requests httprequest grequests


【解决方案1】:

您只是发送请求太快了。由于grequests 是一个异步库,所有这些请求几乎是同时发送的。他们太多了。

你只需要通过grequests.map(rs, size=your_choice)来限制并发任务,我测试过grequests.map(rs, size=10),效果很好。

【讨论】:

  • “太快”是什么意思?瓶颈在哪里,限制在哪里?它是可测量的还是可以优化的?为什么你认为 size=10 最适合你的机器,你如何在其他机器上找到这个值?
  • “快”是对服务器而言,服务器不想接受来自一个客户端的这么多请求,因为它会使服务器崩溃。您降低速度以表示对服务器的尊重,因此服务器很乐意为您服务。
【解决方案2】:

我不知道观察到.map() 行为的确切原因。但是,在我的几分钟测试中,将 .imap() 函数与 size=1 一起使用总是返回“响应 200”。这是代码片段:

rs = (grequests.get(u) for u in [BASE.format(t) for t in tickers])
rsm_iterator = grequests.imap(rs, exception_handler=exception_handler, size=1)
rsm_list = [r for r in rsm_iterator]
print(rsm_list)

如果您不想等待所有请求完成后再处理他们的答案,您可以这样做:

rs = (grequests.get(u) for u in [BASE.format(t) for t in tickers])
rsm_iterator = grequests.imap(rs, exception_handler=exception_handler, size=1)
for r in rsm_iterator:
    print(r)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-11
    • 2012-12-18
    • 1970-01-01
    • 1970-01-01
    • 2014-04-07
    • 1970-01-01
    相关资源
    最近更新 更多