
invisible_playwright v0.7.0
Бесплатный антидетект stealth-браузер для Playwright: необнаруживаемый отпечаток headless Firefox. Python-скрапинг, обход recaptcha и антибот-систем. Открытый исходный код.
Playwright ловится антиботами и капчами.
Этот работает на антидетект-сборке Firefox с недетектируемым отпечатком и совместим с вашим существующим кодом Playwright.

Как это работает
Антиботы задают два вопроса, и reCAPTCHA, hCaptcha и Cloudflare Turnstile оценивают ответы. invisible_playwright отвечает «да» на оба.
1. Это настоящий браузер? Да. Это Firefox, пропатченный на уровне исходного кода C++.
- Отпечаток браузера задаётся внутри движка, а не внедряется в страницу: navigator, screen, GPU/WebGL, canvas, шрифты, audio, WebRTC, часовой пояс, сеть. В headless- или headed-режиме значения одинаковы.
- Никакого JS-шимма, никаких переопределений, никакого шва, за который можно зацепиться.
2. Им пользуется реальный человек? Да. Действия очеловечены в драйвере.
- Каждый клик, наведение и перетаскивание следует естественной траектории мыши с человеческим таймингом, без телепортации курсора.
- Каждый ввод побайтово идентичен реальной мыши: настоящий источник ввода, давление, доверенные события.
Установка
Windows, в PowerShell:
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
$env:Path = "$env:USERPROFILE\.local\bin;$env:Path"
uv init --python ">=3.11" my-project
cd my-project
uv add invisible-playwright
uv run invisible-playwright fetch # one-time download, sha256-verified: 240 MB, about 550 MB unpacked
Linux:
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
uv init --python ">=3.11" my-project
cd my-project
uv add invisible-playwright
uv run invisible-playwright fetch # one-time download, sha256-verified: 262 MB (x86_64) / 253 MB (arm64), about 550 MB unpacked
Поддерживаемые платформы: Windows x86_64, Linux x86_64 / arm64.
Затем сохраните один из примеров ниже как main.py в my-project и запустите его с помощью uv run main.py.
Использование
Случайный отпечаток для каждой сессии
API Playwright, синхронный и асинхронный, без изменений в коде. Те же объекты, те же вызовы, те же возвращаемые значения. Несколько поверхностей выходят за рамки — трассировка, HAR, CDP, контекст API-запросов — и каждая из них отказывает с предложением, объясняющим причину, вместо того чтобы тихо работать неправильно. Если вы уже используете Playwright, переключение занимает две строки:
- from playwright.sync_api import sync_playwright
- with sync_playwright() as p:
- browser = p.firefox.launch()
+ from invisible_playwright import InvisiblePlaywright
+ with InvisiblePlaywright() as browser:
Каждая сессия получает уникальный отпечаток (GPU, аудио, шрифты, экран, ~200 полей) и движение мыши по кривым Безье.
Синхронизация
from invisible_playwright import InvisiblePlaywright
with InvisiblePlaywright(proxy={"server": "socks5://...", "username": "u", "password": "p"}) as browser:
page = browser.new_page()
page.goto("https://example.com")
page.click("#submit") # mouse arcs to the button on a Bezier curve
Асинхронный
from invisible_playwright.async_api import InvisiblePlaywright
async with InvisiblePlaywright(proxy={"server": "socks5://...", "username": "u", "password": "p"}) as browser:
page = await browser.new_page()
await page.goto("https://example.com")
await page.click("#submit")
Объект browser — это playwright.sync_api.Browser / playwright.async_api.Browser; каждый метод Playwright работает как есть.
Логируйте seed для воспроизведения запуска:
sf = InvisiblePlaywright()
with sf as browser:
print("seed =", sf.seed)
# ...
Воспроизводимый отпечаток
with InvisiblePlaywright(seed=42) as browser:
... # same GPU, same canvas hash, same audio context, every run
Прокси
proxy = {
"server": "socks5://gate.example.com:1080",
"username": "user",
"password": "pass",
}
with InvisiblePlaywright(proxy=proxy) as browser:
...
Поддерживаемые схемы: socks5, socks4, http, https. DNS по умолчанию маршрутизируется через прокси, без локальной утечки.
Часовой пояс
Часовой пояс браузера соответствует timezone=:
# default: timezone is auto-derived from the egress IP (proxy egress if a
# proxy is set, otherwise the host's own public IP)
with InvisiblePlaywright(proxy=proxy) as browser:
...
# explicit IANA zone always wins, the only way to force a specific zone
with InvisiblePlaywright(proxy=proxy, timezone="America/New_York") as browser:
...
Закрепление конкретных полей отпечатка
По умолчанию всё берётся из seed. Чтобы принудительно задать конкретные значения, пока остальные остаются производными от seed:
with InvisiblePlaywright(
seed=42,
pin={
"gpu.renderer": "ANGLE (AMD, Radeon R9 200 Series Direct3D11 vs_5_0 ps_5_0, D3D11)",
"gpu.vendor": "Google Inc. (AMD)",
"screen.width": 2560,
"screen.height": 1440,
"hardware.concurrency": 16,
},
) as browser:
...
GPU-пин выбирает одну из валидированных персон, а не задаёт произвольную строку,
поскольку ~81 значение getParameter и список расширений идут вместе с
именем рендерера, и детектор сверяет их с ним. Имя, которого нет в пуле,
вызывает ошибку, и в ошибке перечислены те, что есть.
Полный список закрепляемых ключей, как пиннинг взаимодействует с байесовским сэмплером, и типовые шаблоны — в docs/pinning.md.
CLI
Установленная команда — invisible-playwright, через дефис. python -m invisible_playwright работает идентично и не требует ничего в PATH.
invisible-playwright fetch # download the engine if missing, check every cached
# one against the seal, print the path
invisible-playwright version # wrapper, core and engine versions, and where the
# engine is cached