аватар question@mail.ru · 01.01.1970 03:00

Асинхронные HTTP-вызовы grequests

Всегда использовал библиотеку requests. Но как мне не изменяет память там можно посылать запрос всего на 1 http url и только потом на другой, по очереди. Grequests же как написано можно послать одновременно хоть на 10 URL тоесть асинхронность. Но как это сделать я не знаю, я уже пробовал . В файле примерно 150 url. Код:

import grequestssimplesite = 'http://shost-craft.su'with open(""C:\\cruelnetwork\\cruel.need\\wolfs.txt"") as werewolves:        array = [row.strip()+simplesite for row in werewolves]params = {'a':'b', 'c':'d'}rs = (grequests.post(u, data=params) for u in array)grequests.map(rs)print(rs)

Ждал где-то минуту Я так понял, это очень долго. И вот не знаю как решить данную проблему. Или все же это как раз таки быстро? В конце было выведено на экран: <generator object <genexpr> at 0x0000029AD8D29A98> Я хочу чтобы сразу же отослался запрос на 10 URL-адресов, не по очереди, а сразу же на 10 адресов. Или же нельзя реализовать с помощью данной библиотеки?

аватар answer@mail.ru · 01.01.1970 03:00

Библиотека grequests является асинхронной обёрткой над обычной requests. Соответственно когда вы отдали пачку request объектов в grequests.map(), вы получите list объектов response, примерно такого вида

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

И вы уже работаете с ними как с обычными requests.Response.

Например, чтобы увидеть результат работы первого request`a в вашем коде, попробуйте сделать так, например:

import grequestssimplesite = 'http://shost-craft.su'with open(""C:\\cruelnetwork\\cruel.need\\wolfs.txt"") as werewolves:    array = [row.strip()+simplesite for row in werewolves]params = {'a':'b', 'c':'d'}rs = (grequests.post(u, data=params) for u in array)responses_list = grequests.map(rs)print(responses_list[0].text)print(rs)

Если вы уточните, что конкретно вы хотите получить, возможно удастся дать более точные рекомендации

EDIT: под капотом эта библиотека использует gevent с пулом задач (подробнее про неё и асинхронность, например ), он блокирует вызов до конца выполнения всей пачки, но не блокирует выполнение каждой задачи в пачке. Вы можете управлять размером пула. Я написал ""первого request`a"" выше потому, что не стал заморачиваться с циклом. Могу предложить такое решение:

import grequestssimplesite = 'http://shost-craft.su'with open(""C:\\cruelnetwork\\cruel.need\\wolfs.txt"") as werewolves:    array = [row.strip()+simplesite 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=10)     print(r.status_code, r.url)print(rs)

size=10 - означает закидывать, например, по десять задач в пачке, как только выполниться одна из них докинуть ещё одну (на случай проблем с производительностью)

imap в цикле позволит вам увидеть результаты, сразу после выполнения каждой из задач

Если же вам нужны прям чистые параллельные потоки то да, только множить треды или форкать или ещё что-то, вариантов масса.

EDIT2: приношу извинения за свою некомпетентность по вопросу respons-статусов. Значит ситуация следующая. Учитывая, что автор 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`    :retus: `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()    retu self

т.е. ловит Exception и закидывает его в ответ. Мы можем поймать его вот таким способом:

import grequestsdef exception_handler(request, exception):    print(""Request failed"", request.url) # Сообщить о невалиднсоти и выести url    # print(str(exception)) # если хочется подробностейsimplesite = 'http://shost-craft.su'with open(""C:\\cruelnetwork\\cruel.need\\wolfs.txt"") as werewolves:    array = [row.strip()+simplesite 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=10, exception_handler=exception_handler)     print(r.status_code, r.url)

Теперь если запрос по какой-то причине не выполнился мы, об этом узнаем. Можно получить только статуc_коды запросов которые завершились без Exception`а. Т.е. 404 и др��гие ошибки клиента или сети не вернуться в итоговый list. Правда остаётся вопрос как же разобрать статус. Могу сделать предположение, что можно попытаться вытащить из exception информацию, которую можно использовать для сравнения с одним из типов ошибок, и далее раскрутить до статусов. Но учитывая, что все найденные исходники просто игнорируют этот вопрос, то тут только на ваше усмотрение.

Последние

Похожие