Что такое Pyppeteer и зачем он нужен
Pyppeteer — это мощная Python-библиотека, представляющая собой асинхронный порт популярной JavaScript-библиотеки Puppeteer от Google. Она предоставляет разработчикам полный контроль над браузером Chromium/Chrome через Python-код, что делает её незаменимым инструментом для автоматизации веб-задач.
В отличие от традиционных инструментов веб-скрапинга, Pyppeteer работает с полноценным браузером, что позволяет выполнять JavaScript-код, взаимодействовать с динамическим содержимым и обрабатывать современные веб-приложения, построенные на React, Vue, Angular и других фреймворках.
Основные возможности и преимущества
Асинхронная архитектура
Pyppeteer построен на основе asyncio, что обеспечивает высокую производительность при работе с множественными задачами. Это особенно важно при массовом парсинге данных или автоматизации большого количества веб-страниц.
Полная поддержка JavaScript
Библиотека позволяет выполнять любой JavaScript-код прямо в браузере, получать результаты выполнения и манипулировать DOM-элементами в реальном времени.
Headless и GUI режимы
Pyppeteer может работать как в скрытом режиме (headless) для автоматизации, так и в обычном режиме с графическим интерфейсом для отладки и демонстрации.
Генерация документов
Встроенная поддержка создания скриншотов и PDF-файлов делает библиотеку идеальной для генерации отчетов и документации.
Детальное сравнение с популярными инструментами
| Критерий | Pyppeteer | Selenium | Puppeteer (JS) | Playwright |
|---|---|---|---|---|
| Язык программирования | Python | Python/Java/C# | JavaScript | Python/JS/Java/C# |
| Асинхронность | Да (asyncio) | Частично | Да | Да |
| Управление JavaScript | Полное | Ограниченное | Полное | Полное |
| Скорость выполнения | Высокая | Средняя | Высокая | Очень высокая |
| Поддержка headless | Да | Да | Да | Да |
| Совместимость браузеров | Только Chromium/Chrome | Все браузеры | Chromium/Chrome | Chrome/Firefox/Safari |
| Размер сообщества | Средний | Большой | Большой | Растущий |
| Активность развития | Замедлена | Активная | Активная | Очень активная |
Установка и настройка рабочего окружения
Базовая установка
pip install pyppeteer
Установка с дополнительными зависимостями
pip install pyppeteer[dev]
Ручная установка Chromium
При первом запуске Chromium загружается автоматически, но можно установить его заранее:
import pyppeteer
import asyncio
async def install_chromium():
await pyppeteer.install()
asyncio.run(install_chromium())
Настройка пути к браузеру
browser = await launch(
executablePath='/path/to/chrome',
headless=True
)
Подробное руководство по использованию
Асинхронный запуск и конфигурация браузера
import asyncio
from pyppeteer import launch
async def main():
# Запуск с базовыми настройками
browser = await launch(
headless=True,
args=[
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu'
]
)
# Создание новой страницы
page = await browser.newPage()
# Настройка viewport
await page.setViewport({
'width': 1920,
'height': 1080
})
# Переход на страницу
await page.goto('https://example.com')
# Закрытие браузера
await browser.close()
asyncio.run(main())
Продвинутые стратегии навигации
# Различные стратегии ожидания загрузки
await page.goto('https://example.com', {
'waitUntil': 'networkidle2', # Ожидание, пока сеть не станет неактивной
'timeout': 30000 # Таймаут в миллисекундах
})
# Ожидание конкретного элемента
await page.waitForSelector('h1', {'timeout': 5000})
# Ожидание по XPath
await page.waitForXPath('//div[@class="content"]')
# Ожидание выполнения JavaScript
await page.waitForFunction('document.readyState === "complete"')
Работа с элементами страницы
# Поиск одного элемента
element = await page.querySelector('input[name="username"]')
# Поиск всех элементов
elements = await page.querySelectorAll('a')
# Получение атрибутов элемента
href = await page.evaluate('element => element.href', element)
# Получение текста элемента
text = await page.evaluate('element => element.textContent', element)
# Проверка видимости элемента
is_visible = await page.evaluate('element => element.offsetParent !== null', element)
Взаимодействие с формами и элементами управления
# Ввод текста с имитацией человеческой скорости
await page.type('#email', 'user@example.com', {'delay': 100})
# Очистка поля перед вводом
await page.click('#password', {'clickCount': 3})
await page.type('#password', 'newpassword')
# Работа с выпадающими списками
await page.select('select#country', 'Russia')
# Работа с чекбоксами
await page.click('input[type="checkbox"]')
# Загрузка файлов
file_input = await page.querySelector('input[type="file"]')
await file_input.uploadFile('/path/to/file.pdf')
Выполнение JavaScript в контексте страницы
# Получение данных из страницы
data = await page.evaluate('''() => {
return {
title: document.title,
url: window.location.href,
links: Array.from(document.querySelectorAll('a')).map(a => a.href)
};
}''')
# Выполнение скрипта с аргументами
result = await page.evaluate('''(selector) => {
const element = document.querySelector(selector);
return element ? element.textContent : null;
}''', 'h1')
# Добавление JavaScript в страницу
await page.addScriptTag({'content': 'window.myVar = "test";'})
Создание скриншотов и PDF
# Полноэкранный скриншот
await page.screenshot({
'path': 'fullpage.png',
'fullPage': True,
'type': 'png'
})
# Скриншот конкретного элемента
element = await page.querySelector('.chart')
await element.screenshot({'path': 'chart.png'})
# Создание PDF с настройками
await page.pdf({
'path': 'document.pdf',
'format': 'A4',
'printBackground': True,
'margin': {
'top': '20px',
'right': '20px',
'bottom': '20px',
'left': '20px'
}
})
Управление cookies и localStorage
# Работа с cookies
cookies = await page.cookies()
await page.setCookie({
'name': 'session_id',
'value': 'abc123',
'domain': 'example.com',
'path': '/',
'httpOnly': True,
'secure': True
})
# Очистка cookies
await page.deleteCookie({'name': 'session_id'})
# Работа с localStorage
await page.evaluate('''() => {
localStorage.setItem('user_preferences', JSON.stringify({
theme: 'dark',
language: 'ru'
}));
}''')
# Получение данных из localStorage
storage_data = await page.evaluate('localStorage.getItem("user_preferences")')
Обход защиты от ботов
# Настройка user-agent
await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36')
# Установка заголовков
await page.setExtraHTTPHeaders({
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8'
})
# Эмуляция геолокации
await page.setGeolocation({'latitude': 55.7558, 'longitude': 37.6173})
# Отключение изображений для ускорения
await page.setRequestInterception(True)
page.on('request', lambda req: asyncio.ensure_future(
req.abort() if req.resourceType == 'image' else req.continue_()
))
Таблица методов и функций Pyppeteer
Основные методы Browser
| Метод | Описание | Пример использования |
|---|---|---|
launch() |
Запуск браузера | browser = await launch(headless=True) |
newPage() |
Создание новой страницы | page = await browser.newPage() |
pages() |
Получение всех страниц | pages = await browser.pages() |
close() |
Закрытие браузера | await browser.close() |
version() |
Версия браузера | version = await browser.version() |
userAgent() |
User-agent браузера | ua = await browser.userAgent() |
Методы навигации Page
| Метод | Описание | Пример использования |
|---|---|---|
goto() |
Переход на URL | await page.goto('https://example.com') |
goBack() |
Назад в истории | await page.goBack() |
goForward() |
Вперед в истории | await page.goForward() |
reload() |
Перезагрузка страницы | await page.reload() |
url() |
Текущий URL | url = page.url() |
title() |
Заголовок страницы | title = await page.title() |
Методы поиска элементов
| Метод | Описание | Пример использования |
|---|---|---|
querySelector() |
Поиск элемента по CSS | el = await page.querySelector('div') |
querySelectorAll() |
Поиск всех элементов | els = await page.querySelectorAll('a') |
xpath() |
Поиск по XPath | els = await page.xpath('//div') |
waitForSelector() |
Ожидание элемента | await page.waitForSelector('h1') |
waitForXPath() |
Ожидание по XPath | await page.waitForXPath('//h1') |
Методы взаимодействия
| Метод | Описание | Пример использования |
|---|---|---|
click() |
Клик по элементу | await page.click('button') |
type() |
Ввод текста | await page.type('input', 'text') |
focus() |
Фокус на элементе | await page.focus('input') |
hover() |
Наведение мыши | await page.hover('a') |
select() |
Выбор в select | await page.select('select', 'value') |
keyboard.press() |
Нажатие клавиши | await page.keyboard.press('Enter') |
Методы получения данных
| Метод | Описание | Пример использования |
|---|---|---|
content() |
HTML содержимое | html = await page.content() |
evaluate() |
Выполнение JS | result = await page.evaluate('code') |
evaluateOnNewDocument() |
JS при загрузке | await page.evaluateOnNewDocument('code') |
cookies() |
Получение cookies | cookies = await page.cookies() |
screenshot() |
Скриншот | await page.screenshot({'path': 'img.png'}) |
pdf() |
Создание PDF | await page.pdf({'path': 'doc.pdf'}) |
Методы настройки
| Метод | Описание | Пример использования |
|---|---|---|
setViewport() |
Размер viewport | await page.setViewport({'width': 1280}) |
setUserAgent() |
User-agent | await page.setUserAgent('Mozilla...') |
setExtraHTTPHeaders() |
HTTP заголовки | await page.setExtraHTTPHeaders({}) |
setCookie() |
Установка cookie | await page.setCookie({'name': 'key'}) |
setGeolocation() |
Геолокация | await page.setGeolocation({'latitude': 55}) |
setRequestInterception() |
Перехват запросов | await page.setRequestInterception(True) |
Практические примеры использования
Автоматизация входа в систему
async def login_automation():
browser = await launch(headless=False)
page = await browser.newPage()
await page.goto('https://example.com/login')
# Заполнение формы
await page.type('#username', 'your_username')
await page.type('#password', 'your_password')
# Нажатие кнопки входа
await page.click('button[type="submit"]')
# Ожидание успешного входа
await page.waitForSelector('.dashboard')
# Сохранение cookies для последующих сессий
cookies = await page.cookies()
await browser.close()
return cookies
Парсинг динамического контента
async def parse_dynamic_content():
browser = await launch(headless=True)
page = await browser.newPage()
await page.goto('https://example.com/products')
# Ожидание загрузки AJAX-контента
await page.waitForSelector('.product-list')
# Бесконечная прокрутка для загрузки всех товаров
await page.evaluate('''() => {
return new Promise((resolve) => {
let totalHeight = 0;
const distance = 100;
const timer = setInterval(() => {
const scrollHeight = document.body.scrollHeight;
window.scrollBy(0, distance);
totalHeight += distance;
if(totalHeight >= scrollHeight) {
clearInterval(timer);
resolve();
}
}, 100);
});
}''')
# Извлечение данных
products = await page.evaluate('''() => {
return Array.from(document.querySelectorAll('.product')).map(product => ({
name: product.querySelector('.name').textContent,
price: product.querySelector('.price').textContent,
image: product.querySelector('img').src
}));
}''')
await browser.close()
return products
Создание отчетов с графиками
async def generate_chart_report():
browser = await launch(headless=True)
page = await browser.newPage()
# Создание HTML с графиком
chart_html = '''
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<canvas id="myChart" width="800" height="400"></canvas>
<script>
const ctx = document.getElementById('myChart').getContext('2d');
const chart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Январь', 'Февраль', 'Март', 'Апрель'],
datasets: [{
label: 'Продажи',
data: [12, 19, 3, 5],
backgroundColor: 'rgba(54, 162, 235, 0.2)'
}]
}
});
</script>
</body>
</html>
'''
await page.setContent(chart_html)
# Ожидание отрисовки графика
await page.waitForTimeout(2000)
# Создание скриншота
await page.screenshot({'path': 'chart_report.png', 'fullPage': True})
# Создание PDF
await page.pdf({'path': 'chart_report.pdf', 'format': 'A4'})
await browser.close()
Интеграция с другими библиотеками
Использование с aiohttp
import aiohttp
import asyncio
from pyppeteer import launch
async def combined_scraping():
# Одновременное использование aiohttp и pyppeteer
async with aiohttp.ClientSession() as session:
browser = await launch(headless=True)
page = await browser.newPage()
# Получение данных через API
async with session.get('https://api.example.com/data') as response:
api_data = await response.json()
# Парсинг веб-страницы
await page.goto('https://example.com')
web_data = await page.evaluate('document.title')
await browser.close()
return {'api': api_data, 'web': web_data}
Интеграция с pandas
import pandas as pd
from pyppeteer import launch
async def scrape_to_dataframe():
browser = await launch(headless=True)
page = await browser.newPage()
await page.goto('https://example.com/table')
# Извлечение данных таблицы
table_data = await page.evaluate('''() => {
const rows = Array.from(document.querySelectorAll('table tr'));
return rows.map(row => {
const cells = Array.from(row.querySelectorAll('td, th'));
return cells.map(cell => cell.textContent.trim());
});
}''')
await browser.close()
# Создание DataFrame
df = pd.DataFrame(table_data[1:], columns=table_data[0])
return df
Обработка ошибок и отладка
Обработка типичных ошибок
import asyncio
from pyppeteer import launch
from pyppeteer.errors import TimeoutError, NetworkError
async def robust_scraping():
browser = None
try:
browser = await launch(headless=True)
page = await browser.newPage()
# Настройка таймаутов
page.setDefaultTimeout(30000)
page.setDefaultNavigationTimeout(60000)
await page.goto('https://example.com')
# Безопасное ожидание элементов
try:
await page.waitForSelector('.content', timeout=10000)
except TimeoutError:
print("Элемент не найден в течение 10 секунд")
return None
content = await page.content()
return content
except NetworkError as e:
print(f"Ошибка сети: {e}")
return None
except Exception as e:
print(f"Неожиданная ошибка: {e}")
return None
finally:
if browser:
await browser.close()
Отладка с логированием
import logging
from pyppeteer import launch
# Настройка логирования
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
async def debug_scraping():
browser = await launch(
headless=False,
slowMo=250, # Замедление для наблюдения
devtools=True # Открытие DevTools
)
page = await browser.newPage()
# Логирование всех консольных сообщений
page.on('console', lambda msg: logger.info(f'Console: {msg.text}'))
# Логирование сетевых запросов
page.on('request', lambda req: logger.info(f'Request: {req.url}'))
await page.goto('https://example.com')
await page.screenshot({'path': 'debug.png'})
await browser.close()
Оптимизация производительности
Отключение ненужных ресурсов
async def optimized_scraping():
browser = await launch(
headless=True,
args=[
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--disable-images',
'--disable-javascript', # Только если JS не нужен
'--disable-plugins',
'--disable-extensions'
]
)
page = await browser.newPage()
# Блокировка изображений и стилей
await page.setRequestInterception(True)
page.on('request', lambda req: asyncio.ensure_future(
req.abort() if req.resourceType in ['image', 'stylesheet', 'font']
else req.continue_()
))
await page.goto('https://example.com')
content = await page.content()
await browser.close()
return content
Пулинг браузеров
import asyncio
from pyppeteer import launch
class BrowserPool:
def __init__(self, size=5):
self.size = size
self.browsers = []
self.available = asyncio.Queue()
async def init(self):
for _ in range(self.size):
browser = await launch(headless=True)
self.browsers.append(browser)
await self.available.put(browser)
async def get_browser(self):
return await self.available.get()
async def return_browser(self, browser):
await self.available.put(browser)
async def close_all(self):
for browser in self.browsers:
await browser.close()
# Использование пула
pool = BrowserPool(3)
await pool.init()
browser = await pool.get_browser()
page = await browser.newPage()
# ... работа со страницей
await page.close()
await pool.return_browser(browser)
Тестирование с Pyppeteer
Создание автоматических тестов
import pytest
from pyppeteer import launch
@pytest.fixture
async def browser():
browser = await launch(headless=True)
yield browser
await browser.close()
@pytest.fixture
async def page(browser):
page = await browser.newPage()
yield page
await page.close()
async def test_login_form(page):
await page.goto('https://example.com/login')
# Проверка наличия формы
login_form = await page.querySelector('form#login')
assert login_form is not None
# Проверка полей
username_field = await page.querySelector('input[name="username"]')
password_field = await page.querySelector('input[name="password"]')
assert username_field is not None
assert password_field is not None
# Тест заполнения формы
await page.type('input[name="username"]', 'testuser')
await page.type('input[name="password"]', 'testpass')
# Проверка значений
username_value = await page.evaluate('document.querySelector("input[name=username]").value')
assert username_value == 'testuser'
async def test_page_load_time(page):
start_time = asyncio.get_event_loop().time()
await page.goto('https://example.com')
end_time = asyncio.get_event_loop().time()
load_time = end_time - start_time
assert load_time < 5.0 # Страница должна загружаться менее 5 секунд
Альтернативы и будущее Pyppeteer
Текущее состояние проекта
Pyppeteer не получает активных обновлений с 2021 года, что создает определенные ограничения для его использования в новых проектах. Основные проблемы:
- Отсутствие поддержки новых версий Chrome
- Нет исправлений критических ошибок
- Ограниченная совместимость с новыми версиями Python
Рекомендуемые альтернативы
Playwright для Python - наиболее современная и активно развивающаяся альтернатива:
# Пример с Playwright
from playwright.async_api import async_playwright
async def playwright_example():
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto('https://example.com')
await page.screenshot(path='example.png')
await browser.close()
Pyppeteer2 - неофициальный форк с обновлениями:
pip install pyppeteer2
Лучшие практики и рекомендации
Структура проекта
project/
├── scrapers/
│ ├── __init__.py
│ ├── base.py
│ └── specific_scraper.py
├── utils/
│ ├── __init__.py
│ ├── browser_utils.py
│ └── data_processing.py
├── config.py
└── main.py
Конфигурация для продакшена
# config.py
import os
BROWSER_CONFIG = {
'headless': os.getenv('HEADLESS', 'true').lower() == 'true',
'args': [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-dev-shm-usage',
'--disable-gpu',
'--memory-pressure-off',
'--max_old_space_size=4096'
]
}
TIMEOUTS = {
'navigation': 60000,
'default': 30000,
'element_wait': 10000
}
Мониторинг и логирование
import logging
import time
from functools import wraps
def log_execution_time(func):
@wraps(func)
async def wrapper(*args, **kwargs):
start_time = time.time()
result = await func(*args, **kwargs)
end_time = time.time()
logging.info(f'{func.__name__} выполнена за {end_time - start_time:.2f} секунд')
return result
return wrapper
@log_execution_time
async def scrape_page(url):
# Логика скрапинга
pass
Решение распространенных проблем
Проблемы с памятью
import gc
from pyppeteer import launch
async def memory_efficient_scraping():
browser = await launch(headless=True)
try:
for url in urls:
page = await browser.newPage()
await page.goto(url)
# Обработка данных
await page.close() # Важно закрывать страницы
gc.collect() # Принудительная очистка памяти
finally:
await browser.close()
Обход блокировок
import random
import asyncio
async def stealth_scraping():
# Случайные задержки
await asyncio.sleep(random.uniform(1, 3))
# Рандомизация user-agent
user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
]
await page.setUserAgent(random.choice(user_agents))
# Эмуляция человеческого поведения
await page.mouse.move(100, 100)
await page.mouse.move(200, 200)
Безопасность и этические аспекты
Соблюдение robots.txt
import urllib.robotparser
def can_fetch(url, user_agent='*'):
rp = urllib.robotparser.RobotFileParser()
rp.set_url(f"{url}/robots.txt")
rp.read()
return rp.can_fetch(user_agent, url)
async def ethical_scraping(url):
if not can_fetch(url):
print(f"Доступ к {url} запрещен robots.txt")
return
# Продолжение скрапинга
Ограничение скорости запросов
import asyncio
from asyncio import Semaphore
class RateLimiter:
def __init__(self, max_requests_per_second=1):
self.max_requests = max_requests_per_second
self.semaphore = Semaphore(max_requests_per_second)
self.requests = []
async def acquire(self):
async with self.semaphore:
now = asyncio.get_event_loop().time()
self.requests = [req for req in self.requests if now - req < 1.0]
if len(self.requests) >= self.max_requests:
sleep_time = 1.0 - (now - self.requests[0])
await asyncio.sleep(sleep_time)
self.requests.append(now)
Pyppeteer остается мощным инструментом для автоматизации браузера в Python, несмотря на замедление развития. Для новых проектов рекомендуется рассмотреть альтернативы, такие как Playwright, но существующие проекты на Pyppeteer могут продолжать функционировать при правильной настройке и обслуживании. Ключевыми факторами успеха являются правильная архитектура, обработка ошибок, оптимизация производительности и соблюдение этических принципов веб-скрапинга.
Настоящее и будущее развития ИИ: классической математики уже недостаточно
Эксперты предупредили о рисках фейковой благотворительности с помощью ИИ
В России разработали универсального ИИ-агента для роботов и индустриальных процессов