Время прочтения: 3 мин.
В этой статье я расскажу, как значительно ускорить парсинг сайта. Те, кто изучил парсинг и начал применять его на практике приходят к такому моменту как ожидание окончания работы парсера, в особенности, когда объем данных высок. На скорость работы влияет множество параметров, один из них — это время ответа сервера, т.к. серверу нужно время чтобы обработать информацию.
В статье я опишу один из способов борьбы с этой проблемой.
Использоваться будет библиотека «concurrent.futures». Использовать «concurrent» нужно умеренно, не стоит устраивать «DDoS» атаку на сайт.
Для создания многопотока ничего мудрёного делать не придётся, код очень прост и понятен. После установки импортируем библиотеки. Добавлены 2 дополнительные библиотеки, это «tqdm» индикатор процесса и «pandas» для создания датафрейма.
import requests
import pandas as pd
from tqdm import tqdm
import concurrent.futures
Прописываем «headers» в request запросы, создаем сессию, объявляем функцию отправки запросов
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.146 Safari/537.36'
}
TIMEOUT = 10
session = requests.Session()
session.headers = headers
def load_url(url):
answer = requests.get(url, headers=headers, timeout=TIMEOUT)
return [url, answer.text]
Создаем датафрейм со списком «url» из файла «test.xlsx». Для тестирования берем только первые 2000 записей
df = pd.read_excel('test.xlsx')
df.head()
| Index | source.objectHrefTerm |
| 0 | https://test.ru/PurchaseView/43/0/0/705675 |
| 1 | https://test.ru/PurchaseView/30/0/0/705663 |
| 2 | https://test.ru/PurchaseView/43/0/0/705661 |
| 3 | https://test.ru/PurchaseView/30/0/0/705653 |
| 4 | https://test.ru/PurchaseView/20/0/0/705300 |
urls = list(df['source.objectHrefTerm'])[:2000]Вначале протестируем время выгрузки одним потоком
out = []
for url in tqdm(urls):
out.append(load_url(url))

Прогресс-бар показывает скорость выполнения — 2 минуты и 21 секунду. Среднее количество запросов в секунду — 14.15.
Теперь сделаем те же 2000 запросов, используя concurrent.futures и 2 потока. Изменяется только параметр CONNECTIONS
out = []
CONNECTIONS = 2
with concurrent.futures.ThreadPoolExecutor(max_workers=CONNECTIONS) as executor:
future_to_url = (executor.submit(load_url, url) for url in urls)
for future in tqdm(concurrent.futures.as_completed(future_to_url), total=len(urls)):
try:
data = future.result()
except Exception as exc:
data = str(type(exc))
finally:
out.append(data)

Прогресс-бар показал скорость выполнения 1 минута и 16 секунд. В среднем 26.06 запроса в секунду.
Наблюдается уже значительное увеличение скорости. Попробуем использовать 5 потоков.
out = []
CONNECTIONS = 5

Скорость парсера увеличилась почти в 5 раз.
При использовании большего количества потоков не на все запросы приходили ответы либо на время блокировался ip адрес.
Многопоточный парсинг позволяет нам выполнять работу быстрее, в нашем случае ускорение работы достигло 4,85 раз, что дает существенную экономию времени в больших пулах запросов.
/img/star (2).png.webp)





/img/news (2).png.webp)
/img/event.png.webp)
