Sessions
Sessions keep a browser context open across multiple requests.
import asyncio
from pathlib import Path
from webskrap import SessionConfig, WebSkrapClient
async def main() -> None:
config = SessionConfig(
user_data_dir=Path(".webskrap/session"),
headless=True,
)
async with WebSkrapClient() as client:
session = await client.session("default", config=config)
first = await session.fetch("https://example.com")
second = await session.fetch("https://example.com/account")
print(first.status, second.status)
asyncio.run(main())Calling client.session() again with the same name returns the existing open
session:
session = await client.session("default")
same_session = await client.session("default")
assert session is same_sessionClose individual sessions when you are done with them, or let
WebSkrapClient.close() close all sessions:
await session.close()Persistent storage
Set user_data_dir to keep cookies, local storage, and browser profile state between runs.
config = SessionConfig(user_data_dir=Path(".webskrap/profile"))Use storage_state for a Playwright-style cookie/local-storage snapshot when
you do not need a full persistent browser profile:
config = SessionConfig(storage_state="state.json")storage_state is applied only for non-persistent contexts. If
user_data_dir is set, the persistent profile directory owns browser state.
Both hold real credentials: cookies, local storage, and any logged-in session
you established, unencrypted and surviving process exit. Put them somewhere
only your user can read, and delete them when the work is done. The persistent
sessions managed by webskrap browser do this for you: their directories
under ~/.webskrap/browser/ are created 0700 on POSIX.
Headed debugging
Set headless=False and keep a page open when you need to inspect behavior:
import asyncio
from pathlib import Path
from webskrap import SessionConfig, WebSkrapClient
async def main() -> None:
config = SessionConfig(
headless=False,
user_data_dir=Path(".webskrap/debug"),
slow_mo_ms=50,
)
async with WebSkrapClient() as client:
session = await client.session("debug", config=config)
page = await session.context.new_page()
await page.goto("https://example.com", wait_until="domcontentloaded")
input("Press Enter to close browser...")
asyncio.run(main())Human-like clicks
Sessions expose human_click for interactions that should behave more like a manual click
than a direct Playwright page.click.
async with WebSkrapClient() as client:
session = await client.session("default")
page = await session.context.new_page()
await page.goto("https://example.com", wait_until="domcontentloaded")
await session.human_click(page, "label[for='radio1']")Pass human=False to use the same helper while delegating directly to Playwright.
await session.human_click(page, "label[for='radio1']", human=False, timeout=5_000)Pass normal click options such as button, click_count, delay, modifiers,
position, strict, and trial:
await session.human_click(
page,
"button[type='submit']",
strict=True,
timeout=10_000,
modifiers=["Shift"],
)See the Humanizer guide for the focused behavior reference and safety boundaries.
Common options
config = SessionConfig(
browser="chromium",
channel="chrome",
headless=False,
navigation_timeout_ms=90_000,
default_timeout_ms=90_000,
slow_mo_ms=50,
launch_args=[
"--start-maximized",
"--no-first-run",
"--no-default-browser-check",
],
)Proxy example
from webskrap import ProxyConfig, SessionConfig
config = SessionConfig(
proxy=ProxyConfig(
server="http://127.0.0.1:8080",
username="user",
password="pass",
),
)Do not commit proxy credentials, cookies, storage-state files, or persistent session directories.
