Metadata-Version: 2.4
Name: fetchdriver
Version: 0.1.0
Summary: Browser fetch() API
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: pydantic>=2.13.4
Provides-Extra: patchright
Requires-Dist: patchright>=1.60.1; extra == "patchright"
Provides-Extra: selenium
Requires-Dist: selenium>=4.36.0; extra == "selenium"
Dynamic: license-file

# fetchdriver

A Python library that lets you seamlessly use the JavaScript `fetch` API directly through browser automation frameworks.

This project is an upgraded version of [`selenium-fetch`](https://github.com/aprilahijriyan/selenium-fetch). It is designed to help bypass strict anti-bot protections (like Cloudflare) by executing requests directly from a real browser context.

## Features

- **Pydantic Models:** Strongly typed inputs and outputs (`FetchOptions`, `Response`) for better developer experience, autocomplete, and validation.
- **Multiple Engines:** Support for Selenium and Playwright (via Patchright).

## Installation

You can install the package with the specific browser automation engine you intend to use:

```bash
# For Selenium support
pip install fetchdriver[selenium]

# For Patchright/Playwright support
pip install fetchdriver[patchright]
```

## Usage (Selenium)

You can use `fetchdriver` with any Selenium WebDriver. For bypassing bot protections, pairing it with stealth drivers like `undetected-chromedriver` is recommended.

```python
import undetected_chromedriver as uc
from fetchdriver.selenium_api import fetch, get_browser_user_agent
from fetchdriver.types import FetchOptions

# Initialize the browser
driver = uc.Chrome()

# Navigate to the site first to pass Cloudflare/WAF checks and establish cookies
driver.get("https://example.com")

# Define fetch options (strongly typed with Pydantic)
options = FetchOptions(
    method="POST",
    headers={"Content-Type": "application/json", "Accept": "application/json"},
    body={"username": "my_user", "password": "my_password"},
)

# Execute the fetch request natively inside the browser context
response = fetch(driver, "https://example.com/api/login", options)

if response:
    print(f"Status: {response.status.code} {response.status.text}")
    print(f"Headers: {response.headers}")
    print(f"Body: {response.text}")
    print(f"Is OK: {response.ok}")

driver.quit()
```

## Usage (Playwright)

You can use `fetchdriver` with Playwright or Patchright. Here is an example using `async_playwright` (sync is also supported).

```python
import asyncio
from patchright.async_api import async_playwright
from fetchdriver.playwright_api import async_fetch
from fetchdriver.types import FetchOptions


async def main():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page()

        # Navigate to the site first to pass checks and establish cookies
        await page.goto("https://example.com")

        # Define fetch options (strongly typed with Pydantic)
        options = FetchOptions(
            method="POST",
            headers={"Content-Type": "application/json", "Accept": "application/json"},
            body={"username": "my_user", "password": "my_password"},
        )

        # Execute the fetch request natively inside the browser context
        response = await async_fetch(page, "https://example.com/api/login", options)

        if response:
            print(f"Status: {response.status.code} {response.status.text}")
            print(f"Headers: {response.headers}")
            print(f"Body: {response.text}")
            print(f"Is OK: {response.ok}")

        await browser.close()


asyncio.run(main())
```

## Why `fetchdriver`?

When building scrapers or automation tools, you frequently encounter APIs protected by Cloudflare, Datadome, or other WAFs that easily fingerprint and block standard Python HTTP clients (like `requests`, `httpx`, or `aiohttp`).

By executing a native `fetch` call from within an actual browser that has already solved the bot challenges, your background API requests inherit the browser's cookies, headers, and "human" trust score, avoiding blocks entirely.
