Pyppeteer – управление браузером через Puppeteer

онлайн тренажер по питону
Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое 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 могут продолжать функционировать при правильной настройке и обслуживании. Ключевыми факторами успеха являются правильная архитектура, обработка ошибок, оптимизация производительности и соблюдение этических принципов веб-скрапинга.

Новости