12

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

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

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

GRequests 允许您使用带有 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)

使用请求

# 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
  • 蟒蛇:3.6.3
  • urllib3:1.22
  • pyopenssl:17.2.0
  • 全部通过 Anaconda
  • 系统:Mac OSX HS 和 Windows 10 上的相同问题,构建 10.0.16299
4

2 回答 2

10

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

您只需要将并发任务限制为grequests.map(rs, size=your_choice),我已经测试过grequests.map(rs, size=10)并且效果很好。

于 2017-12-14T08:26:48.300 回答
5

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

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)
于 2017-12-07T19:44:57.803 回答