У меня есть python 3.4, и я установил запросы и несколько других необходимых программ для очистки веб-страниц. Моя проблема в том, что я хотел бы очистить около 7000 страниц (только html/текст), и не хочу делать это все сразу, я хотел бы иметь какую-то задержку, чтобы я не попал на серверы со слишком большим количеством запросов и потенциально могут быть забанены. Я слышал о grequests, но, видимо, у них его нет для python 3.4 (фактическая ошибка говорит, что он не может найти vcvarsall.bat, но в документации я не видел поддержки для 3.4). Кто-нибудь знает альтернативную программу, которая могла бы управлять запросами URL? Другими словами, я не стремлюсь схватить все как можно быстрее, а скорее медленно и стабильно.
Парсинг путем отправки одновременных запросов с помощью python
Ответы (1)
Я предлагаю запустить собственную многопоточную программу для выполнения запросов. Я обнаружил, что concurrent.futures
это самый простой способ многопоточного выполнения таких запросов, в частности, с помощью ThreadPoolExecutor
. У них даже есть пример простого многопоточного запроса URL в документации.
Что касается второй части вопроса, это действительно зависит от того, насколько/как вы хотите ограничить свои запросы. Для меня установка достаточно низкого аргумента max_workers
и, возможно, включение ожидания time.sleep
в мою функцию было достаточно, чтобы избежать каких-либо проблем даже при очистке десятков тысяч страниц, но это, очевидно, намного больше зависит от сайта, который вы пытаетесь очистить. Тем не менее, не должно быть сложно реализовать какую-то пакетную обработку или ожидание.
Следующий код не тестировался, но, надеюсь, он может стать отправной точкой. Отсюда вы, вероятно, захотите изменить get_url_data
(или любую другую функцию, которую вы используете) с тем, что вам нужно сделать (например, синтаксический анализ, сохранение).
import concurrent.futures as futures
import requests
from requests.exceptions import HTTPError
urllist = ...
def get_url_data(url, session):
try:
r = session.get(url, timeout=10)
r.raise_for_status()
except HTTPError:
return None
return r.text
s = requests.Session()
try:
with futures.ThreadPoolExecutor(max_workers=5) as ex:
future_to_url = {ex.submit(get_url_data, url, s): url
for url in urlist}
results = {future_to_url[future]: future.result()
for future in futures.as_completed(future_to_url)}
finally:
s.close()
requests
. Я посмотрю, смогу ли я найти старый код, который я использовал, и отредактировать его в ответе.
- person Roger Fan; 14.08.2014
get_url_data
, и в этом случае вам может вообще не понадобиться возвращать results
dict.
- person Roger Fan; 14.08.2014
time.sleep
. Если бы я хотел, мог бы я просто добавить sleep(1)
в конец функции get_url_data
?
- person thatandrey; 14.08.2014
time.sleep
выпускает GIL, поэтому он позволит другим потокам работать в это время. В качестве альтернативы, если вы хотите реализовать периодические паузы, вы можете разделить URL-адреса на пакеты и выполнять их по одному пакету за раз с паузами между ними.
- person Roger Fan; 14.08.2014