Страницы

Поиск по вопросам

среда, 5 февраля 2020 г.

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

#python #python_3x #асинхронность


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

import grequests
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)
grequests.map(rs)
print(rs)


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


Ответы

Ответ 1



Библиотека grequests является асинхронной обёрткой над обычной requests. Соответственно когда вы отдали пачку request объектов в grequests.map(), вы получите list объектов response, примерно такого вида [, , , , None, ] И вы уже работаете с ними как с обычными requests.Response. Например, чтобы увидеть результат работы первого request`a в вашем коде, попробуйте сделать так, например: import grequests 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) responses_list = grequests.map(rs) print(responses_list[0].text) print(rs) Если вы уточните, что конкретно вы хотите получить, возможно удастся дать более точные рекомендации EDIT: под капотом эта библиотека использует gevent с пулом задач (подробнее про неё и асинхронность, например тут), он блокирует вызов до конца выполнения всей пачки, но не блокирует выполнение каждой задачи в пачке. Вы можете управлять размером пула. Я написал "первого request`a" выше потому, что не стал заморачиваться с циклом. Могу предложить такое решение: import grequests 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) 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` :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 и закидывает его в ответ. Мы можем поймать его вот таким способом: import grequests def 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 информацию, которую можно использовать для сравнения с одним из этих типов ошибок, и далее раскрутить до статусов. Но учитывая, что все найденные исходники просто игнорируют этот вопрос, то тут только на ваше усмотрение.

Ответ 2



Попробуте такой код выкачки(Я сам его когда-то юзал): import requests from multiprocessing.dummy import Pool pool = Pool(X) #X это количество потоков одновременно #можно поставить много(64 например), но учтите что сеть может не выдержать столько) #поставьте сначала 1 и увеличивайте потихоньку site = 'http://shost-craft.su' params = {'a':'b', 'c':'d'} urls = [] with open("C:\\cruelnetwork\\cruel.need\\wolfs.txt") as f: for row in f: urls.append(row.strip() + site) results = pool.map(lambda url: requests.post(url, data=params), urls) print(results)

Комментариев нет:

Отправить комментарий