Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

pyfox

Async Firefox browser automation for Python, built on the W3C WebDriver BiDi protocol.
Inspired by Pydoll, built for Firefox.

Why WebDriver BiDi?

WebDriver BiDi is the W3C protocol for bidirectional browser automation, natively supported by modern Firefox releases.

pyfox connects to Firefox directly through BiDi over WebSocket. No Selenium, no geckodriver, no Playwright underneath. This keeps the API fully asynchronous and removes the need for any external WebDriver binary.


Features

  • Async API built around asyncio
  • Direct WebDriver BiDi communication over WebSocket
  • Multiple tabs and isolated browser contexts
  • CSS, XPath, ID, class, name, tag, text, and attribute selectors
  • Iframe and Shadow DOM traversal
  • Humanized mouse movement and keyboard input
  • Screenshots and PDF generation
  • Cookie management
  • Network monitoring and interception
  • Request and response modification, mocking, and failure
  • Response body capture during interception
  • HAR 1.2 recording
  • Download handling with expect_download()
  • Browser dialogs and network logs
  • Pydantic-based structured extraction
  • Async retry decorator
  • ForgeAPI integrated fingerprint controls
  • Cloudflare Turnstile interaction support

Installation

pip install pyfox-auto

Requirements

  • Python 3.12+
  • Firefox 128+

Firefox 130+ is recommended when using download functionality. Firefox-based browsers with WebDriver BiDi support also work.


Getting Started

import asyncio
from pyfox import Firefox, FirefoxOptions


async def main():
    options = FirefoxOptions()
    # Point to any Firefox-based browser binary:
    # options.binary_path = "/path/to/firefox-based-browser"

    async with Firefox(options=options) as browser:
        tab = await browser.new_tab()
        await tab.navigate("https://www.google.com")

        search = await tab.find_or_wait_element("input[name='q']", timeout=10)
        await search.type_text("pyfox automation")
        await tab.screenshot("screenshot.png")


asyncio.run(main())

Browser and Tab Management

async with Firefox(options=options) as browser:
    tab = await browser.new_tab()
    await tab.navigate("https://example.com")
    print(await tab.title)

For isolated sessions, create a browser context:

context_id = await browser.create_context()
tab = await browser.new_tab(context_id=context_id)

Each context maintains its own browser state, allowing multiple independent sessions within the same Firefox instance.


Finding Elements

Supported selector types: CSS, XPath, ID, class, name, tag, text, and attributes. Elements can also be searched across iframes.

element = await tab.find_or_wait_element("button.submit", timeout=10)

WebElement exposes click, type, scroll, get attribute, screenshot, and Shadow DOM access.


Humanized Input

Mouse movement uses cubic Bézier curves, Fitts's Law timing, Gaussian tremor, and overshoot correction.

await tab.mouse.move(500, 300, humanize=True)
await tab.mouse.click(500, 300, humanize=True)

Keyboard input supports variable per-character delays and QWERTY-based typo simulation.

await element.type_text("pyfox automation", humanize=True)

Shadow DOM

shadow_roots = await tab.find_shadow_roots(deep=True)

for shadow_root in shadow_roots:
    button = await shadow_root.query(".internal-button", raise_exc=False)
    if button:
        await button.click()

Shadow roots expose the same element-finding API used elsewhere in the library.


Network Interception

Monitor and intercept browser network traffic through WebDriver BiDi.

Supported operations: request and response interception, request modification, response handling, mocking, failure, authentication, and network logging.

Capturing Response Bodies

async with tab.capture_response_body(url_pattern="api/data") as capture:
    await tab.navigate("https://example.com")
    response = capture.get("api/data")

WebDriver BiDi does not provide direct response body access outside an active interception workflow, unlike CDP.


HAR Recording

Network activity can be recorded and exported as HAR 1.2. Useful for keeping a complete trace of requests and responses during a session.


Cookies

cookies = await tab.get_cookies()

Setting and deleting cookies is also supported through the BiDi storage API.


Downloads

async with tab.expect_download() as download:
    await element.click()

file = await download.value

Firefox 130+ is recommended for download functionality.


Structured Extraction

Define a Pydantic model and extract typed data directly from the page:

from pyfox.extractor import ExtractionModel, Field


class Quote(ExtractionModel):
    text: str = Field(selector=".text")
    author: str = Field(selector=".author")


quote = await tab.extract(Quote)
print(quote.author)

quotes = await tab.extract_all(Quote, scope=".quote")

ForgeAPI provides browser fingerprint controls via script.addPreloadScript. It requires no browser extension and no mandatory proxy.

Controllable properties: canvas, WebGL, AudioContext, fonts, navigator, screen, hardware concurrency, timezone, permissions, battery.

from pyfox.antidetect import forge_check

result = await forge_check(tab)

ForgeAPI can also be enabled at the browser level so every new tab gets it automatically:

async with Firefox(options=options, antidetect=True) as browser:
    tab = await browser.new_tab()

Cloudflare Turnstile

async with tab.expect_and_bypass_cloudflare_captcha():
    await tab.navigate("https://site-with-turnstile.com")

This is not a guaranteed bypass. Results depend on browser environment, network, IP reputation, and the challenge itself.


Retry Decorator

from pyfox.decorators import retry


@retry(max_retries=3, exponential_backoff=True)
async def scrape():
    ...

Custom recovery logic can be executed between attempts.


Supported Browsers

pyfox targets Firefox and Firefox-based browsers with WebDriver BiDi support.

Tested or targeted: Firefox, Zen Browser, Floorp, LibreWolf, and Waterfox. Any Firefox-based browser with WebDriver BiDi support should work.


Architecture

pyfox uses a single WebSocket connection per browser instance, shared across all tabs.

Firefox
   │
WebDriver BiDi (WebSocket)
   │
ConnectionHandler
   ├── Tab ── WebElement
   ├── Tab ── WebElement
   └── Tab ── WebElement
pyfox/
├── antidetect/    # ForgeAPI and preload scripts
├── browser/       # Firefox, Tab, FirefoxOptions, downloads, requests
├── connection/    # ConnectionHandler, CommandsManager, EventsManager
├── elements/      # WebElement, ShadowRoot, FindElementsMixin
├── extractor/     # Pydantic structured extraction
├── interactions/  # Mouse, Keyboard, Scroll
└── protocol/      # WebDriver BiDi protocol builders

Dependencies

websockets>=12.0
aiofiles>=23.0
pydantic>=2.0
typing-extensions>=4.9

Pydoll

pyfox follows a similar API philosophy to Pydoll, targeting Firefox via WebDriver BiDi instead of Chromium via CDP.

Feature Pydoll pyfox
Browser Chromium Firefox
Protocol CDP WebDriver BiDi
Async API
WebDriver binary
Multiple tabs
Browser contexts
Shadow DOM
Network interception
HAR recording
Humanized mouse
Humanized keyboard
Structured extraction
Retry decorator
Downloads
Firefox support
Chromium support

Limitations

These are protocol-level differences, not missing wrappers:

  • Chromium and Chrome are not supported
  • navigator.webdriver remains true under Firefox WebDriver BiDi (W3C spec behavior)
  • No direct equivalent to CDP's file chooser APIs
  • Response bodies are only accessible during an active network interception workflow

Project Status

Version 0.1.0 - 119 unit tests, 204 integration tests (run against real Firefox on Windows).


Contributing

Issues and pull requests are welcome. When reporting a bug, include enough information to reproduce it - browser version, OS, and a minimal script if possible.


License

MIT

About

Firefox browser automation via WebDriver BiDi

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages