Понимание запросов против греков
Я работаю с процессом, который в основном выглядит следующим образом:
- Возьмите какой-нибудь список URL.
- Получить
Response
объект от каждого. - Создайте объект BeautifulSoup из
text
каждого ответа. - Вытащите текст определенного тега из этого объекта BeautifulSoup.
Насколько я понимаю, это кажется идеальным для греков:
GRequests позволяет вам использовать запросы с Gevent, чтобы легко выполнять асинхронные HTTP-запросы.
Но, тем не менее, два процесса (один с запросами, другой с запросами), похоже, дают разные результаты, при этом некоторые запросы возвращаются 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]>]
Почему разница в результатах?
Обновление: я могу напечатать тип исключения следующим образом. Связанное обсуждение здесь, но я понятия не имею, что происходит.
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
- Все через Анаконду
- Система: та же проблема на Mac OSX HS и Windows 10, сборка 10.0.16299
2 ответа
Вы просто слишком быстро отправляете запросы. Как grequests
это асинхронная библиотека, все эти запросы почти отправляются одновременно. Их слишком много.
Вам просто нужно ограничить количество одновременных задач grequests.map(rs, size=your_choice)
Я проверил grequests.map(rs, size=10)
и это работает хорошо.
Я не знаю точную причину наблюдаемого поведения с .map()
, Однако, используя .imap()
функция с size=1
всегда возвращал 'Response 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)