1. Необходимые библиотеки
bash
pip install requests beautifulsoup4 selenium scrapy lxml
2. Простой парсинг с requests + BeautifulSoup
python
import requests
from bs4 import BeautifulSoup
import time
# Базовый парсинг с заголовками
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
try:
response = requests.get('https://example.com', headers=headers, timeout=10)
response.raise_for_status() # Проверка на ошибки
soup = BeautifulSoup(response.text, 'html.parser')
# Поиск элементов
titles = soup.find_all('h1')
links = soup.find_all('a', class_='some-class')
text = soup.find('div', id='content').text.strip()
# CSS селекторы
items = soup.select('.item-class')
except requests.exceptions.RequestException as e:
print(f'Ошибка запроса: {e}')
3. Работа с динамическим контентом (Selenium)
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
# Настройка headless режима
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-dev-shm-usage')
driver = webdriver.Chrome(options=chrome_options)
try:
driver.get('https://example.com')
# Ожидание загрузки элемента
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CLASS_NAME, "content"))
)
# Клик по кнопке
button = driver.find_element(By.ID, "load-more")
button.click()
# Парсинг динамического контента
items = driver.find_elements(By.CSS_SELECTOR, ".item")
for item in items:
title = item.find_element(By.TAG_NAME, "h2").text
print(title)
finally:
driver.quit()
4. Полный пример парсинга новостей
python
import requests
from bs4 import BeautifulSoup
import csv
import time
from urllib.parse import urljoin
class NewsParser:
def __init__(self, base_url):
self.base_url = base_url
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
def parse_article(self, url):
"""Парсинг отдельной статьи"""
try:
response = requests.get(url, headers=self.headers, timeout=10)
soup = BeautifulSoup(response.text, 'html.parser')
title = soup.find('h1').text.strip()
content = soup.find('div', class_='article-content').text.strip()
date = soup.find('time', class_='date').text.strip()
return {
'title': title,
'content': content,
'date': date,
'url': url
}
except Exception as e:
print(f'Ошибка при парсинге {url}: {e}')
return None
def parse_listing(self, page=1):
"""Парсинг списка статей"""
url = f'{self.base_url}/page/{page}'
try:
response = requests.get(url, headers=self.headers)
soup = BeautifulSoup(response.text, 'html.parser')
articles = []
for link in soup.select('.article-link'):
article_url = urljoin(self.base_url, link.get('href'))
articles.append(article_url)
return articles
except Exception as e:
print(f'Ошибка при парсинге списка: {e}')
return []
def save_to_csv(self, data, filename='articles.csv'):
"""Сохранение данных в CSV"""
keys = data[0].keys() if data else []
with open(filename, 'w', newline='', encoding='utf-8') as f:
writer = csv.DictWriter(f, fieldnames=keys)
writer.writeheader()
writer.writerows(data)
# Использование
parser = NewsParser('https://example-news.com')
all_articles = []
for page in range(1, 4): # Парсинг 3 страниц
print(f'Парсинг страницы {page}...')
articles_urls = parser.parse_listing(page)
for url in articles_urls:
print(f'Парсинг: {url}')
article_data = parser.parse_article(url)
if article_data:
all_articles.append(article_data)
time.sleep(1) # Задержка между запросами
time.sleep(2) # Задержка между страницами
# Сохранение результатов
parser.save_to_csv(all_articles)
print(f'Сохранено {len(all_articles)} статей')
5. Продвинутый парсинг с пагинацией и прокси
python
import requests
from bs4 import BeautifulSoup
import random
import time
from fake_useragent import UserAgent
class AdvancedParser:
def __init__(self):
self.session = requests.Session()
self.ua = UserAgent()
self.proxies = [
'http://proxy1:port',
'http://proxy2:port',
]
def get_random_headers(self):
return {
'User-Agent': self.ua.random,
'Accept-Language': 'ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Referer': 'https://www.google.com/',
}
def make_request(self, url, retries=3):
for attempt in range(retries):
try:
proxy = {'http': random.choice(self.proxies)} if self.proxies else None
response = self.session.get(
url,
headers=self.get_random_headers(),
proxies=proxy,
timeout=15
)
response.raise_for_status()
return response
except Exception as e:
print(f'Попытка {attempt + 1} не удалась: {e}')
if attempt < retries - 1:
time.sleep(2 ** attempt) # Экспоненциальная задержка
return None
def parse_with_pagination(self, base_url, max_pages=10):
all_data = []
for page in range(1, max_pages + 1):
url = f'{base_url}?page={page}'
print(f'Парсинг страницы {page}...')
response = self.make_request(url)
if not response:
break
soup = BeautifulSoup(response.text, 'html.parser')
# Проверка на последнюю страницу
if not soup.find_all('div', class_='item'):
break
# Парсинг данных страницы
page_data = self.parse_page(soup)
all_data.extend(page_data)
# Случайная задержка между запросами
time.sleep(random.uniform(1, 3))
return all_data
def parse_page(self, soup):
data = []
# Ваша логика парсинга страницы
return data
6. Использование Scrapy (фреймворк)
python
# items.py
import scrapy
class ArticleItem(scrapy.Item):
title = scrapy.Field()
content = scrapy.Field()
url = scrapy.Field()
date = scrapy.Field()
# spiders/news_spider.py
import scrapy
from ..items import ArticleItem
class NewsSpider(scrapy.Spider):
name = 'news'
start_urls = ['https://example-news.com/']
def parse(self, response):
for article in response.css('div.article'):
item = ArticleItem()
item['title'] = article.css('h2::text').get()
item['url'] = article.css('a::attr(href)').get()
item['date'] = article.css('span.date::text').get()
yield response.follow(item['url'], self.parse_article, meta={'item': item})
# Пагинация
next_page = response.css('a.next::attr(href)').get()
if next_page:
yield response.follow(next_page, self.parse)
def parse_article(self, response):
item = response.meta['item']
item['content'] = response.css('div.content::text').get()
yield item
7. Обработка ошибок и best practices
python
import logging
import time
from functools import wraps
def retry(max_attempts=3, delay=1):
"""Декоратор для повторных попыток"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise
logging.warning(f'Попытка {attempt + 1} не удалась: {e}')
time.sleep(delay * (2 ** attempt))
return None
return wrapper
return decorator
class SafeParser:
def __init__(self):
logging.basicConfig(level=logging.INFO)
@retry(max_attempts=3)
def safe_request(self, url):
response = requests.get(url, timeout=10)
response.raise_for_status()
return response
def safe_extract(self, soup, selector, default=''):
try:
element = soup.select_one(selector)
return element.text.strip() if element else default
except Exception as e:
logging.error(f'Ошибка при извлечении {selector}: {e}')
return default
Важные советы:
- Соблюдайте robots.txt - проверяйте разрешения на парсинг
- Добавляйте задержки между запросами (time.sleep)
- Используйте User-Agent для имитации браузера
- Обрабатывайте исключения для устойчивости
- Сохраняйте промежуточные результаты для отладки
- Учитывайте изменения структуры сайта - используйте CSS селекторы
- Применяйте многопоточность с осторожностью для массового парсинга
Выберите подход в зависимости от ваших задач: BeautifulSoup для статичных сайтов, Selenium для динамических, Scrapy для масштабных проектов.