Асинхронные запросы с запросами Python - PullRequest
118 голосов
/ 02 февраля 2012

Я попробовал образец, предоставленный в документации библиотеки запросов для python.

С async.map(rs) я получаю коды ответов, но хочу получить содержимое каждой запрашиваемой страницы. Это, например, не работает:

out = async.map(rs)
print out[0].content

Ответы [ 9 ]

135 голосов
/ 08 февраля 2012

Примечание

Ответ ниже не применим к запросам v0.13.0 +. После написания этого вопроса асинхронная функциональность была перемещена в grequests . Однако вы можете просто заменить requests на grequests ниже, и это должно сработать.

Я оставил этот ответ, чтобы отразить исходный вопрос, касающийся использования запросов


Чтобы выполнить несколько задач с async.map асинхронно , вам необходимо:

  1. Определите функцию для того, что вы хотите сделать с каждым объектом (ваша задача)
  2. Добавьте эту функцию в качестве обработчика событий в вашем запросе
  3. Звоните async.map по списку всех запросов / действий

Пример: * * тысяча двадцать-восемь

from requests import async
# If using requests > v0.13.0, use
# from grequests import async

urls = [
    'http://python-requests.org',
    'http://httpbin.org',
    'http://python-guide.org',
    'http://kennethreitz.com'
]

# A simple task to do to each response object
def do_something(response):
    print response.url

# A list to hold our things to do via async
async_list = []

for u in urls:
    # The "hooks = {..." part is where you define what you want to do
    # 
    # Note the lack of parentheses following do_something, this is
    # because the response will be used as the first argument automatically
    action_item = async.get(u, hooks = {'response' : do_something})

    # Add the task to our list of things to do via async
    async_list.append(action_item)

# Do our list of things to do via async
async.map(async_list)
70 голосов
/ 14 августа 2012

async теперь является независимым модулем: grequests.

Смотрите здесь: https://github.com/kennethreitz/grequests

А там: Идеальный способ отправки нескольких HTTP-запросов через Python?

установка:

$ pip install grequests

использование:

сборка стека:

import grequests

urls = [
    'http://www.heroku.com',
    'http://tablib.org',
    'http://httpbin.org',
    'http://python-requests.org',
    'http://kennethreitz.com'
]

rs = (grequests.get(u) for u in urls)

отправить в стек

grequests.map(rs)

результат выглядит как

[<Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>, <Response [200]>]

Запросы не устанавливают ограничения для одновременных запросов, то есть когда несколько запросов отправляются на один и тот же сервер.

40 голосов
/ 18 ноября 2015

Я протестировал оба запросов-фьючерса и grequests . Grequests быстрее, но приносит исправления обезьян и дополнительные проблемы с зависимостями. Фьючерсы на запросы в несколько раз медленнее, чем греки. Я решил написать свои собственные и просто упакованные запросы в ThreadPollExecutor, и это было почти так же быстро, как запросы, но без внешних зависимостей.

import requests
import concurrent.futures

def get_urls():
    return ["url1","url2"]

def load_url(url, timeout):
    return requests.get(url, timeout = timeout)

with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:

    future_to_url = {executor.submit(load_url, url, 10): url for url in     get_urls()}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            resp_err = resp_err + 1
        else:
            resp_ok = resp_ok + 1
26 голосов
/ 28 мая 2014

возможно запросов-фьючерсов - это другой выбор.

from requests_futures.sessions import FuturesSession

session = FuturesSession()
# first request is started in background
future_one = session.get('http://httpbin.org/get')
# second requests is started immediately
future_two = session.get('http://httpbin.org/get?foo=bar')
# wait for the first request to complete, if it hasn't already
response_one = future_one.result()
print('response one status: {0}'.format(response_one.status_code))
print(response_one.content)
# wait for the second request to complete, if it hasn't already
response_two = future_two.result()
print('response two status: {0}'.format(response_two.status_code))
print(response_two.content)

Рекомендуется также в офисный документ . Если вы не хотите вовлекать Gevent, это хорошо.

7 голосов
/ 21 октября 2013

Я знаю, что это было закрыто некоторое время, но я подумал, что было бы полезно продвинуть другое асинхронное решение, построенное на библиотеке запросов.*

5 голосов
/ 17 января 2013
threads=list()

for requestURI in requests:
    t = Thread(target=self.openURL, args=(requestURI,))
    t.start()
    threads.append(t)

for thread in threads:
    thread.join()

...

def openURL(self, requestURI):
    o = urllib2.urlopen(requestURI, timeout = 600)
    o...
2 голосов
/ 23 февраля 2012

Я уже некоторое время использую запросы Python для асинхронных вызовов к gist API github.

Например, см. Код здесь:

https://github.com/davidthewatson/flasgist/blob/master/views.py#L60-72

Этот стиль Python может быть не самым ярким примером, но я могу заверить вас, что код работает,Дайте мне знать, если это вас смущает, и я это запишу.

1 голос
/ 27 марта 2019

Если вы хотите использовать asyncio, тогда requests-async предоставляет функции асинхронного ожидания / ожидания для requests - https://github.com/encode/requests-async

0 голосов
/ 02 февраля 2012

Я также пробовал некоторые вещи, используя асинхронные методы в Python, но мне повезло гораздо больше, используя витую для асинхронного программирования.У него меньше проблем и он хорошо документирован.Вот ссылка на что-то похожее на то, что вы пытаетесь изобразить.

http://pythonquirks.blogspot.com/2011/04/twisted-asynchronous-http-request.html

...