Асинхронные запросы с запросами Python

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

http://docs.python-requests.org/en/latest/user/advanced/#asynchronous-requests

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

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

например, просто не работает.

Ответ 1

Примечание

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

Я оставил этот ответ так, чтобы он отражал исходный вопрос, который касался использования запросов < v0.13.0.


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

  • Определите функцию для того, что вы хотите делать с каждым объектом (ваша задача)
  • Добавьте эту функцию как крючок события в свой запрос
  • Вызовите 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)

Ответ 2

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]>]

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

Ответ 3

возможно requests-futures - еще один выбор.

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, это хороший.

Ответ 4

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

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

Ответ 5

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

list_of_requests = ['http://moop.com', 'http://doop.com', ...]

from simple_requests import Requests
for response in Requests().swarm(list_of_requests):
    print response.content

Документы находятся здесь: http://pythonhosted.org/simple-requests/

Ответ 6

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...

Ответ 7

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

Для примера см. код здесь:

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

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

Ответ 8

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

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