python

Создаем массу асинхронных запросов при помощи Grequests

  • воскресенье, 6 августа 2017 г. в 03:11:42
https://habrahabr.ru/post/334970/
  • Python


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

Но так как с асинхронностью, у неё хромает, выполнять асинхронные запросы возможно с использованием threading или gevent.

Написал grequests, тот же автор что и написал requests. Только с использованием gevent + requests. Не буду долго мусолить тему, дам вам подробную информацию о данной библиотеки.

Grequestsявляется асинхронной обёрткой над обычной requests.

Сделаем обычный POST-запрос на множество url-адресов:

import grequests 
with open("C:\\path\\urls.txt") as werewolves: 
    array = [row.strip() for row in werewolves]

params = {'a':'b', 'c':'d'}
rs = [grequests.post(u, data=params) for u in array]
for r in grequests.imap(rs, size=16) 
    print(r[0].status_code, r[0].url)

Все довольно просто, импортируется библиотека, открывается файл на чтение, создается список, переменной params присваивается значения a:b, c:d.

Далее создаем переменную rs которая будет отвечать за сам POST-запрос, для переменной r создаем grequests.map([rs], size=является асинхронным значением, чем больше значение тем быстрее будут выполнятся http-запросы, правда больше 16 не имеет смысла ставить).

Теперь так как мы передали все аргументы в переменную r, то есть в grequests.imap() мы можем взаимодействовать с данной переменной как в обычном requests.

И последним шагом нам нужно вывести все status code, url address, также rs выступает списком, это мы делаем для того чтоб не было ошибок индексации по типу:

TypeError: 'Response' object does not support indexing

Если у вас все ровно вылезает traceback с данной ошибкой, предлагаю вариант:

def exception_handlerr(request, exception):
    print("Request failed", request.url) 

import grequests 
with open("C:\\path\\urls.txt") as werewolves: 
    array = [row.strip() for row in werewolves]

params = {'a':'b', 'c':'d'}
rs = [grequests.post(u, data=params) for u in array]
for r in grequests.map([rs], size=16, exception_handler=exception_handlerr) 
    print(r[0].status_code, r[0].url)


Теперь и к переменной r мы будем обращаться как к списку, дабы избежать ошибок индексации.
Основные шаги, мы сделали. Можете «ДУДОСИТЬ» сервера. Хотя, заоблачной асинхронностью данная библиотека не обладает. Это можно приглянуть к Aiohttp.

Ещё хотел бы поговорить о исключениях в grequests. Так как grequests не использует error-классы из requests, а делает следующим образом:

def send(self, **kwargs):
    """
    Prepares request based on parameter passed to constructor and optional      ``kwargs```.
    Then sends request and saves response to :attr:`response`

    :returns: ``Response``
    """
    merged_kwargs = {}
    merged_kwargs.update(self.kwargs)
    merged_kwargs.update(kwargs)
    try:
        self.response = self.session.request(self.method,
                                            self.url, **merged_kwargs)
    except Exception as e:
        self.exception = e
        self.traceback = traceback.format_exc()
    return self

Мы ловим при помощи exception_handler:

def exception_handlerr(request, exception):
    print("Request failed", request.url) 
    # print(str(exception)) 


Полный исходный код:

def exception_handlerr(request, exception):
    print("Request failed", request.url) 

import grequests 
with open("C:\\path\\urls.txt") as werewolves: 
    array = [row.strip() for row in werewolves]

params = {'a':'b', 'c':'d'}
rs = [grequests.post(u, data=params) for u in array]
for r in grequests.map([rs], size=16, exception_handler=exception_handlerr) 
    print(r.status_code, r.url)


Так мы сможем с полной уверенностью отлавливать ошибки.

С GET-запросами все так-же просто как и с POST-запросами:

def exception_handlerr(request, exception):
    print("Request failed", request.url) 

import grequests 
with open("C:\\path\\urls.txt") as werewolves: 
    array = [row.strip() for row in werewolves]

params = {'a':'b', 'c':'d'}
rs = [grequests.get(u) for u in array]
for r in grequests.map([rs], size=16, exception_handler=exception_handlerr) 
    print(r.status_code, r.url)


Исходный код grequests.
Документация по requests.

Удачного вам дня!