Как парсить сайт: Полное руководство для начинающих и продвинутых пользователей
Парсинг сайтов (web scraping) — это процесс извлечения данных с веб-страниц с помощью программного кода. Это мощный инструмент для автоматизации сбора информации, анализа данных, мониторинга цен и многого другого. В этом уроке мы подробно разберём, как парсить сайт, от основ до продвинутых техник. Будем используем Python как основной язык, так как он наиболее популярен для этих задач благодаря библиотекам вроде requests, BeautifulSoup и Selenium.
Для примера мы выберем сайт books.toscrape.com — это тестовый сайт, специально созданный для практики веб-скрапинга. Он содержит каталог книг с категориями, страницами, описаниями, ценами и рейтингами. Сайт простой, но позволяет продемонстрировать все аспекты парсинга: статический контент, пагинацию, динамику и обработку ошибок. Важно: всегда проверяйте robots.txt сайта и соблюдайте законы (например, GDPR в ЕС). Не используйте парсинг для вредоносных целей.
1. Введение в веб-парсинг
Веб-парсинг — это автоматизированный способ получения данных из HTML-структуры сайтов. Почему это полезно? Представьте, что вам нужно собрать цены на книги из онлайн-магазина: вручную это займёт часы, а с кодом — минуты. Парсинг применяется в бизнес-аналитике (мониторинг конкурентов), науке (сбор данных для исследований), маркетинге (анализ отзывов) и даже в повседневной жизни (автоматизация уведомлений о скидках).
Основные понятия
- HTML-структура: Сайты построены на HTML-тегах (<div>, <p>, <a>). Парсер находит нужные теги и извлекает текст или атрибуты.
- Статический vs Динамический контент: Статический — загружается сразу (парсим с requests + BeautifulSoup). Динамический — генерируется JavaScript (нужен Selenium для эмуляции браузера).
- API vs Парсинг: Если сайт предоставляет API (например, JSON-эндпоинты), лучше использовать его — это быстрее и легальнее. Но многие сайты API не имеют, поэтому парсинг необходим.
Этика и легальность
Перед парсингом проверьте:
Файл robots.txt
User-agent: *
Disallow: /
User-agent: *
Звёздочка означает «все поисковые роботы» (Googlebot, YandexBot, BingBot и т.д.).
Disallow: /
Запретить сканировать все страницы сайта (слэш / означает корень, т.е. весь сайт).
- robots.txt: Файл на сайте (например, books.toscrape.com/robots.txt), не существует, так что можно парсить. Что не запрещено, то разрешено.
- Terms of Service: Многие сайты запрещают скрейпинг (Amazon, Google). Нарушение может привести к бану IP.
- Rate Limiting: Не перегружайте сервер — добавляйте задержки (time.sleep(1-5 сек)).
- Легальность: В России и США парсинг публичных данных разрешён, но не личных (без согласия). Избегайте сайтов с капчей или аутентификацией.
Необходимые инструменты
Для работы нам понадобятся:
- Python 3.x.
- Библиотеки: requests (для HTTP-запросов), BeautifulSoup (для парсинга HTML), Selenium (для динамики), pandas (для хранения данных).
Установка библиотек:
pip install requests beautifulsoup4 selenium pandas
2. Базовый парсинг статического сайта с requests и BeautifulSoup
Начнём с простого: извлечём список книг с главной страницы books.toscrape.com.
Шаг 1: Получение HTML
Используем requests для загрузки страницы.
import requests
url = 'https://books.toscrape.com/'
response = requests.get(url)
if response.status_code == 200:
html = response.text
print("Страница загружена успешно!")
else:
print(f"Ошибка: {response.status_code}")
Объяснение: requests.get() отправляет GET-запрос. response.text — HTML-код. Проверяем status_code (200 — OK).
Результат:
Шаг 2: Парсинг с BeautifulSoup
BeautifulSoup разбирает HTML в дерево тегов.
import requests
from bs4 import BeautifulSoup
url = 'https://books.toscrape.com/'
response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
if response.status_code == 200:
soup = BeautifulSoup(response.text, 'html.parser')
title = soup.find('title').text
print(f"Заголовок страницы: {title}")
else:
print(f"Ошибка: {response.status_code}")
find() находит первый тег. Для нескольких — find_all().
Результат:
Шаг 3: Извлечение данных
На сайте книги в <article class=»product_pod»>. Внутри: <h3><a> — название, <p class=»price_color»> — цена, <p class=»star-rating»> — рейтинг.
import requests
from bs4 import BeautifulSoup
url = 'https://books.toscrape.com/'
response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
if response.status_code == 200:
response.encoding = 'utf-8' # Устанавливаем кодировку UTF-8
soup = BeautifulSoup(response.text, 'html.parser')
books = soup.find_all('article', class_='product_pod')
for book in books:
name = book.find('h3').find('a')['title']
price = book.find('p', class_='price_color').text
rating = book.find('p', class_='star-rating')['class'][1]
print(f"Книга: {name}, Цена: {price}, Рейтинг: {rating}")
else:
print(f"Ошибка: {response.status_code}")
Это извлекает 20 книг с главной страницы. ['class'][1] — потому что класс «star-rating Three», второй элемент — рейтинг.
Результат:
Обработка пагинации
Сайт имеет 50 страниц. Находим ссылку «next» и циклим.
import requests
from bs4 import BeautifulSoup
import time
from urllib.parse import urljoin
all_books = []
current_url = 'https://books.toscrape.com/'
while current_url:
response = requests.get(current_url, headers={'User-Agent': 'Mozilla/5.0'})
if response.status_code == 200:
response.encoding = 'utf-8' # Устанавливаем кодировку UTF-8
soup = BeautifulSoup(response.text, 'html.parser')
books = soup.find_all('article', class_='product_pod')
for book in books:
name = book.find('h3').find('a')['title']
price = book.find('p', class_='price_color').text
rating = book.find('p', class_='star-rating')['class'][1]
all_books.append({'name': name, 'price': price, 'rating': rating})
next_button = soup.find('li', class_='next')
if next_button:
next_page = next_button.find('a')['href']
current_url = urljoin(current_url, next_page) # Корректное формирование URL
else:
current_url = None
time.sleep(1) # Задержка, чтобы не нагружать сервер
else:
print(f"Ошибка: {response.status_code}")
break
print(f"Всего книг: {len(all_books)}")
Это соберёт все 1000 книг. time.sleep() — этика. Время работы от 1 до 3 минут.
Результат:
Сохранение данных
Используем pandas для CSV.
import requests
from bs4 import BeautifulSoup
import time
from urllib.parse import urljoin
import pandas as pd
all_books = []
current_url = 'https://books.toscrape.com/'
while current_url:
response = requests.get(current_url, headers={'User-Agent': 'Mozilla/5.0'})
if response.status_code == 200:
response.encoding = 'utf-8' # Устанавливаем кодировку UTF-8
soup = BeautifulSoup(response.text, 'html.parser')
books = soup.find_all('article', class_='product_pod')
for book in books:
name = book.find('h3').find('a')['title']
price = book.find('p', class_='price_color').text
rating = book.find('p', class_='star-rating')['class'][1]
all_books.append({'name': name, 'price': price, 'rating': rating})
next_button = soup.find('li', class_='next')
if next_button:
next_page = next_button.find('a')['href']
current_url = urljoin(current_url, next_page) # Корректное формирование URL
else:
current_url = None
time.sleep(1) # Задержка, чтобы не нагружать сервер
else:
print(f"Ошибка: {response.status_code}")
break
df = pd.DataFrame(all_books)
df.to_csv('books.csv', index=False, encoding='utf-8') # Сохранение с UTF-8
print("Данные сохранены в books.csv")
print(f"Всего книг: {len(all_books)}")
Теперь данные в файле. Можно анализировать: средняя цена, топ по рейтингу.
Результат:
Подробно о BeautifulSoup: методы find(), find_all(), select() для CSS-селекторов. Например, soup.select('article.product_pod h3 a') — все ссылки на книги.
Обработка ошибок: Используйте try-except для случаев, когда тег не найден.
requests.headers — для User-Agent, чтобы симулировать браузер.
requests.session() — для сохранения куки при пагинации.
3. Парсинг динамического контента с Selenium
Некоторые сайты загружают данные через JS (например, infinite scroll). Books.toscrape.com статический, но представим динамику. Selenium эмулирует браузер.
Установка и базовый запуск
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get('https://books.toscrape.com/')
print(driver.title)
driver.quit()
webdriver_manager автоматически скачивает драйвер.
Результат:
Извлечение данных
Selenium использует find_element, find_elements.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get('https://books.toscrape.com/')
time.sleep(2) # Задержка для полной загрузки страницы
books = driver.find_elements(By.CLASS_NAME, 'product_pod')
for book in books:
name = book.find_element(By.TAG_NAME, 'h3').find_element(By.TAG_NAME, 'a').get_attribute('title')
price = book.find_element(By.CLASS_NAME, 'price_color').text
rating = book.find_element(By.CSS_SELECTOR, 'p.star-rating').get_attribute('class').split()[1]
print(f"Книга: {name}, Цена: {price}, Рейтинг: {rating}")
driver.quit()
By — селекторы: TAG_NAME, CLASS_NAME, CSS_SELECTOR, XPATH. XPATH для сложных: //article[@class='product_pod']//h3/a/@title.
Результат:
Обработка пагинации с Selenium
Кликаем «next».
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.common.exceptions import NoSuchElementException
import time
all_books = []
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get('https://books.toscrape.com/')
time.sleep(2) # Ждём загрузку страницы
while True:
books = driver.find_elements(By.CLASS_NAME, 'product_pod')
for book in books:
try:
name = book.find_element(By.TAG_NAME, 'h3').find_element(By.TAG_NAME, 'a').get_attribute('title')
price = book.find_element(By.CLASS_NAME, 'price_color').text.encode('utf-8').decode('utf-8')
rating = book.find_element(By.CSS_SELECTOR, 'p.star-rating').get_attribute('class').split()[1]
all_books.append({'name': name, 'price': price, 'rating': rating})
except NoSuchElementException:
print("Ошибка: Не удалось извлечь данные книги")
continue
try:
next_button = driver.find_element(By.CLASS_NAME, 'next').find_element(By.TAG_NAME, 'a')
next_button.click()
time.sleep(2) # Ждём загрузку следующей страницы
except NoSuchElementException:
break
driver.quit()
print(f"Всего книг: {len(all_books)}")
Результат:
time.sleep() — для ожидания JS, но лучше использовать WebDriverWait.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CLASS_NAME, 'product_pod')))
Опции Selenium
Для headless (без окна):
options = webdriver.ChromeOptions()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
Для User-Agent:
options.add_argument('--user-agent=Your UA')
Для прокси:
options.add_argument('--proxy-server=http://ip:port')
Комбинирование с BeautifulSoup
Selenium получает HTML после JS, затем парсим BS. Это полезно для динамики.
soup = BeautifulSoup(driver.page_source, 'html.parser')
Парсинг форм и взаимодействие
Selenium может кликать, вводить текст. Для поиска на сайте:
driver.find_element(By.NAME, 'q').send_keys('python')
driver.find_element(By.NAME, 'q').submit()
Обход анти-бот
- Задержки.
- Рандомные User-Agent.
- Прокси.
- Headless с опциями, чтобы скрыть автоматизацию:
options.add_argument('--disable-blink-features=AutomationControlled')
4. Продвинутые техники
Многопоточность
Для ускорения используйте threading или multiprocessing. Но будьте осторожны с лимитами.
import requests
from bs4 import BeautifulSoup
import threading
from urllib.parse import urljoin
all_books = []
base_url = 'https://books.toscrape.com/'
pages = [f'catalogue/page-{i}.html' for i in range(1, 51)] # 50 страниц
def parse_page(page):
url = urljoin(base_url, page)
response = requests.get(url, headers={'User-Agent': 'Mozilla/5.0'})
if response.status_code == 200:
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'html.parser')
books = soup.find_all('article', class_='product_pod')
for book in books:
name = book.find('h3').find('a')['title']
price = book.find('p', class_='price_color').text
rating = book.find('p', class_='star-rating')['class'][1]
all_books.append({'name': name, 'price': price, 'rating': rating})
threads = []
for page in pages:
t = threading.Thread(target=parse_page, args=(page,))
t.start()
threads.append(t)
for t in threads:
t.join()
print(f"Всего книг: {len(all_books)}")
Обработка JSON/API
Если сайт имеет API, парсите JSON.
response = requests.get('api.url')
data = response.json()
Парсинг с lxml
Альтернатива BS, быстрее.
from lxml import html
tree = html.fromstring(response.text)
names = tree.xpath('//h3/a/@title')
Работа с куки и сессиями
requests.Session() для куки.
session = requests.Session()
session.cookies.set('key', 'value')
Парсинг таблиц
Для таблиц:
df = pd.read_html(url)
Обработка ошибок
try-except для Timeout, NoSuchElement.
from requests.exceptions import RequestException
Хранение в БД
Используйте SQLite или MongoDB.
import sqlite3
conn = sqlite3.connect('books.db')
df.to_sql('books', conn)
Scrapy — фреймворк для больших проектов
Scrapy — для сложных скрейперов с пауками.
pip install scrapy
scrapy startproject myproject
В spider.py:
class BookSpider(scrapy.Spider):
name = 'book'
start_urls = ['https://books.toscrape.com/']
def parse(self, response):
# извлечение
yield {'name': ...}
next_page = response.css('li.next a::attr(href)').get()
if next_page:
yield response.follow(next_page, self.parse)
Запуск:
scrapy crawl book -o books.json
Это автоматизирует пагинацию, обработку.
5. Примеры на других сайтах
Парсинг Wikipedia: Извлечение инфобокса.
soup.find('table', class_='infobox')
Парсинг новостей: RSS или прямой парсинг.
Парсинг e-commerce: Цены, но осторожно с TOS.
6. Проблемы и решения
- Капча: Используйте сервисы вроде 2captcha (платно).
- Блокировка IP: Прокси-пулы (Bright Data).
- Изменение структуры: Регулярные тесты кода.
- JS-heavy: Headless browsers like Puppeteer (JS версия Selenium).
7. Заключение
Парсинг — мощный инструмент, но используйте его ответственно. Начните с простых сайтов, практикуйтесь на books.toscrape.com.
Смотрите примеры и изучайте уроки на https://parsertools.ru
Удачи!
