Прискорте вебскрапінг завдяки конкурентному виконанню в Python

Прискорте вебскрапінг завдяки конкурентному виконанню в Python

У цьому посібнику я покажу, як використовувати asyncio and aiohttp у Python, щоб зробити ваш вебскрапінг швидше й ефективніше. Я розберу це крок за кроком, щоб ви могли підвищити продуктивність своїх скриптів для вебскрапінгу та швидко отримати потрібні дані. Почнімо!

Що таке конкурентність?

Concurrency це здатність виконувати кілька завдань одночасно або не в строгому порядку. Коли йдеться про вебскрапінг, це означає надсилати кілька запитів одночасно замість того, щоб чекати завершення кожного перед початком наступного. У традиційному сценарії вебскрапінгу кожен запит займає час, особливо якщо сервер повільний або має багато сторінок для скрапінгу. За допомогою паралельного вебскрапінгу ви можете надсилати кілька запитів одночасно. Поки один запит чекає на відповідь, ви можете працювати з іншими. Це зменшує час очікування і прискорює ваш вебскрапер.

Найкраща альтернатива вебскрапінгу на Python

Вебскрапери Bright Data забезпечує повноцінне рішення корпоративного рівня для ваших потреб у вилученні даних. Завдяки доступу до масштабної проксі-мережі та розширених засобів захисту від ботів, Bright Data робить масштабування ваших проєктів вебскрапінгу простішим і надійнішим. Незалежно від того, чи збираєте ви дані для маркетингових досліджень, чи автоматизуєте великомасштабні завдання скрапінгу, їхня потужна інфраструктура дає змогу зосередитися на вилученні якісних даних без зайвих клопотів.

Якщо вам також цікаво дізнатися про інші інструменти, відвідайте мій список найкращих інструментів для вебскрапінгу.

Послідовний вебскрапінг: повільний спосіб

Let’s first look at how a typical scraping script works without concurrency. Imagine you need to scrape a website with 12 pages, each taking about 2 seconds to load. A sequential approach means:

  1. Ви надсилаєте запит до першої сторінки.
  2. Зачекайте 2 секунди, поки сервер відповість.
  3. Обробіть дані.
  4. Переходите до наступної сторінки та повторюєте процес.

Якщо на кожну сторінку йде 2 секунди, загальний час послідовного скрапінгу всіх 12 сторінок становив би 24 секунди.

Ось приклад того, як ви можете реалізувати це в Python за допомогою бібліотеки requests:

import requests
from bs4 import BeautifulSoup
import csv
base_url = "https://example.com/products/page"
pages = range(1, 13) # Scrape 12 pages
def extract_data(page):
url = f"{base_url}/{page}/"
response = requests.get(url)
soup = BeautifulSoup(response.text, "html.parser")
# Extract data here (e.g., product name, price)
products = []
for product in soup.select(".product"):
products.append({
"name": product.find("h2").text.strip(),
"price": product.find(class_="price").text.strip(),
"url": product.find("a").get("href")
})
return products
def store_results(products):
with open("products.csv", "w") as file:
writer = csv.DictWriter(file, fieldnames=products[0].keys())
writer.writeheader()
writer.writerows(products)
all_products = []
for page in pages:
all_products.extend(extract_data(page))
store_results(all_products)

Запуск наведеного коду

Коли ви запустите скрипт, програма працюватиме приблизно 24 секунди (по 2 секунди на кожну з 12 сторінок). Хоча для невеликих сайтів це нормально, це стає проблемою, коли потрібно скрапити велику кількість сторінок.

Проблема послідовного вебскрапінгу

Хоча наведений вище підхід працює, він неефективний. Як бачите, є багато простою в очікуванні відповіді сервера. Якщо ви скрапите багато сторінок, цей простій швидко накопичується. Ефективніший спосіб упоратися з цим — надсилати запити до кількох сторінок одночасно.

Конкурентність: прискорення вебскрапінгу за допомогою asyncio та aiohttp

Щоб подолати неефективність послідовного вебскрапінгу, ми можемо використати конкурентність. Це дає змогу надсилати кілька запитів одночасно та обробляти відповіді в міру їх надходження. Ми використаємо asyncio та aiohttp, які створені для асинхронного програмування в Python.

Що таке Aiohttp?

Aiohttp — це асинхронна бібліотека HTTP-клієнта/сервера для Python. Вона чудово працює з asyncio, даючи змогу надсилати HTTP-запити без блокування основного потоку. На відміну від бібліотеки requests, яка є синхронною, aiohttp підтримує асинхронні операції.

Вебскрапінг за допомогою Asyncio та Aiohttp

Тепер змінімо наведений вище скрипт, щоб використовувати asyncio та aiohttp для паралельності.

Крок 1: Встановіть потрібні бібліотеки

Перш ніж почнемо, нам потрібно встановити aiohttp і beautifulsoup4:

pip install aiohttp beautifulsoup4

Крок 2: Реалізація конкурентності

Ось як можна переписати скрипт, щоб використовувати паралельність:

import aiohttp
import asyncio
from bs4 import BeautifulSoup
import csv
base_url = "https://example.com/products/page"
pages = range(1, 13) # Scrape 12 pages
async def extract_data(page, session):
url = f"{base_url}/{page}/"
async with session.get(url) as response:
soup = BeautifulSoup(await response.text(), "html.parser")
products = []
for product in soup.select(".product"):
products.append({
"name": product.find("h2").text.strip(),
"price": product.find(class_="price").text.strip(),
"url": product.find("a").get("href")
})
return products
async def main():
async with aiohttp.ClientSession() as session:
tasks = [extract_data(page, session) for page in pages]
results = await asyncio.gather(*tasks)
all_products = [item for sublist in results for item in sublist] # Flatten the list
store_results(all_products)
def store_results(products):
with open("products.csv", "w") as file:
writer = csv.DictWriter(file, fieldnames=products[0].keys())
writer.writeheader()
writer.writerows(products)
# Run the asyncio event loop
asyncio.run(main())

Ключові зміни в коді

  1. Asynchronous Requests: Ми замінили requests.get() with session.get() from aiohttp. The async with statement ensures that the request is handled asynchronously.
  2. Async Function: The extract_data function is now asynchronous, denoted by async def. The await keyword is used to wait for the response from the server without blocking the entire program.
  3. Concurrent Tasks: We use asyncio.gather() to execute multiple tasks concurrently. Each task is responsible for scraping one page.
  4. Flattening Results: Після одночасного вебскрапінгу всіх сторінок результати зберігаються в results. Оскільки asyncio.gather() повертає список списків, тож нам потрібно його сплющити, щоб отримати один список усіх продуктів.

Крок 3: Запуск коду

Тепер, коли ви запустите оновлений скрипт, він одночасно зчитає всі 12 сторінок. Це займе значно менше часу, ніж послідовна версія. Точний приріст швидкості залежатиме від вашої мережі та часу відповіді сервера, але зазвичай ви побачите помітне покращення.

Performance Comparison

  • Sequential Scraping: Як уже згадувалося, вебскрапінг 12 сторінок послідовно зайняв би близько 24 секунд.
  • Паралельний вебскрапінг з asyncio: У версії з паралельним виконанням скрипт може завершити те саме завдання приблизно за 5-10 секунд, залежно від затримки мережі.

Обмеження конкурентності, щоб не перевантажувати сервер

Хоча паралельність прискорює вебскрапінг, надсилання надто багатьох запитів одночасно може перевантажити сервер або заблокувати вашу IP-адресу. Щоб цього уникнути, можна обмежити кількість одночасних запитів за допомогою семафора в asyncio.

Приклад із семафором

max_concurrency = 5 # Limit concurrent requests
sem = asyncio.Semaphore(max_concurrency)
async def extract_data(page, session):
async with sem: # This limits the number of concurrent requests
url = f"{base_url}/{page}/"
async with session.get(url) as response:
soup = BeautifulSoup(await response.text(), "html.parser")
products = []
for product in soup.select(".product"):
products.append({
"name": product.find("h2").text.strip(),
"price": product.find(class_="price").text.strip(),
"url": product.find("a").get("href")
})
return products

Conclusion

Обмежуючи рівень паралельності, ми гарантуємо, що одночасно надсилатиметься лише певна кількість запитів. Це знижує ризик перевантажити сервер або отримати блокування.

Отже, ось і все: ми навчилися пришвидшувати вебскрапінг завдяки конкурентності з asyncio та aiohttp у Python. Надсилаючи кілька запитів одночасно, можна суттєво скоротити час, потрібний для вебскрапінгу сайту, особливо коли йдеться про велику кількість сторінок. Пам’ятайте про умови використання сайту і не перевантажуйте сервери надмірною кількістю запитів. Успішного вебскрапінгу!

Схожі записи