A lightweight async Playwright wrapper for Python that supports three browser launch strategies and can intercept authenticated HTTP sessions from live browser traffic.
Project description
pwbase
A lightweight async Playwright wrapper for Python that supports three browser launch strategies and can intercept authenticated HTTP sessions from live browser traffic.
Features
- Three browser modes: plain Playwright, stealth (bot-detection evasion), and CDP attachment
- Persistent browser state (cookies + localStorage) via
save_state/state_path BrowserSessionExtractor— intercepts JSON responses and converts them into authenticatedrequests.Sessionobjects- Fully async, context-manager-friendly API
Requirements
- Python 3.12+
- uv (recommended) or pip
Installation
Available on PyPI.
uv add pwbase
# or
pip install pwbase
Install Playwright browsers after installing the package:
playwright install chromium
Quick Start
import asyncio
from pwbase import Browser, BrowserConfig, BrowserType
async def main():
async with Browser(BrowserConfig(type=BrowserType.STEALTH)) as browser:
page = await browser.get_page()
await page.goto("https://example.com")
print(await page.title())
asyncio.run(main())
Browser Modes
| Mode | BrowserType |
Description |
|---|---|---|
| Default | DEFAULT |
Pure Playwright, no extras |
| Stealth | STEALTH |
Applies playwright-stealth to reduce bot detection signals |
| CDP | CDP |
Attaches to an existing Chrome instance via Chrome DevTools Protocol |
Default
Browser(BrowserConfig(type=BrowserType.DEFAULT))
Stealth
Browser(BrowserConfig(type=BrowserType.STEALTH))
CDP
Start Chrome with remote debugging enabled:
google-chrome --remote-debugging-port=9222
Then attach:
Browser(BrowserConfig(type=BrowserType.CDP, cdp_url="http://localhost:9222"))
Note:
headless,state_path,viewport, and related options are ignored in CDP mode.save_state()is not available in CDP mode.
BrowserConfig Reference
@dataclass
class BrowserConfig:
type: BrowserType = BrowserType.DEFAULT
headless: bool = True
state_path: Path | None = None # Load/save cookies + localStorage
channel: str = "chrome" # Browser channel for STEALTH mode
cdp_url: str = "http://localhost:9222"
viewport: tuple[int, int] = (1920, 1080)
user_agent: str = "..." # Windows Chrome UA by default
locale: str = "en-US"
timezone: str = "America/New_York"
args: list[str] = [ # Extra Chromium flags
"--disable-blink-features=AutomationControlled",
"--no-sandbox",
]
Saving and Restoring Browser State
from pathlib import Path
from pwbase import Browser, BrowserConfig, BrowserType
config = BrowserConfig(
type=BrowserType.STEALTH,
state_path=Path("state.json"),
)
# First run — log in and save session
async with Browser(config) as browser:
page = await browser.get_page()
await page.goto("https://example.com/login")
# ... perform login ...
await browser.save_state()
# Subsequent runs — state is restored automatically
async with Browser(config) as browser:
page = await browser.get_page()
await page.goto("https://example.com/dashboard")
Session Extraction
BrowserSessionExtractor extends Browser and intercepts JSON responses in real time. Use it to capture authenticated sessions without manually copying cookies or headers.
from pwbase import BrowserSessionExtractor, BrowserConfig, BrowserType
async with BrowserSessionExtractor(BrowserConfig(type=BrowserType.STEALTH)) as browser:
page = await browser.get_page()
await browser.start_recording(page)
await page.goto("https://example.com")
# Trigger the API call you want to capture, then:
response = browser.find_response("api/data")
if response:
session = browser.to_session(response)
r = session.get("https://example.com/api/data")
print(r.json())
API
| Method | Description |
|---|---|
start_recording(page) |
Begin intercepting JSON responses on page |
stop_recording() |
Stop intercepting; safe to call if never started |
find_response(url_contains) |
Return the most recent captured response matching the substring |
find_all_responses(url_contains) |
Return all captured responses matching the substring |
wait_for_response(url_contains, timeout) |
Poll until a matching response is captured |
to_session(response) |
Build an authenticated requests.Session from a CapturedResponse |
CapturedResponse Fields
@dataclass
class CapturedResponse:
url: str
method: str
headers: dict[str, str] # Response headers
body: dict | list | None # Parsed JSON body
request_headers: dict[str, str] # Request headers (HTTP/2 pseudo-headers excluded from session)
request_post_data: str | None
cookies: list[Cookie]
Manual Lifecycle
If you prefer not to use the context manager:
browser = Browser(BrowserConfig())
await browser.start()
page = await browser.get_page()
# ... do work ...
await browser.stop()
Development
# Install with dev dependencies
uv sync --group dev
# Run tests
uv run pytest
# Run tests with output
uv run pytest -v
Project Structure
src/pwbase/
├── __init__.py # Public API surface
├── browser.py # Browser — core async Playwright wrapper
├── browser_config.py # BrowserConfig dataclass
├── browser_type.py # BrowserType enum
└── browser_session_extractor.py # BrowserSessionExtractor + CapturedResponse
tests/
├── conftest.py # Shared async mock fixtures
├── test_browser.py # Unit tests for Browser (all three modes)
└── test_browser_session_extractor.py
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pwbase-0.2.2.tar.gz.
File metadata
- Download URL: pwbase-0.2.2.tar.gz
- Upload date:
- Size: 48.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7316d33d33200b80a0f261fbce363ccd35bb3b0224bef0a6c61c7f3771836c7f
|
|
| MD5 |
00a9bada20b9fd018d2751e55a0ca011
|
|
| BLAKE2b-256 |
0737dd96fd5fb6dd988d9beb51c8b9660735f70fe24b223d4244750dbcf8ee5b
|
File details
Details for the file pwbase-0.2.2-py3-none-any.whl.
File metadata
- Download URL: pwbase-0.2.2-py3-none-any.whl
- Upload date:
- Size: 13.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0341170fdf1a41796a2c2ef19d537a699ae9828aca80b98bdde8bc4a399df58f
|
|
| MD5 |
453d28cb5cc7210a0416dfe2905759f3
|
|
| BLAKE2b-256 |
52a20c487e39e1e8fbac54350c04c625701f9e5fcc1e7b826708b06e73cd32bb
|