Skip to main content

Stealth web scraping SDK with optional cloud browser support

Project description

Abrasio SDK

Python 3.8+ Version 0.1.0

Undetected web scraping SDK inspired on Patchright with human-like behavior simulation and optional cloud browser support.

Features

Feature Description
Undetected Patchright bypasses Runtime.enable and CDP detection
Free Local Mode Run on your machine with anti-detection patches
Cloud Mode Real fingerprints(paid)
Human Behavior Bezier mouse movements, natural typing, smooth scrolling
TLS Fingerprinting curl_cffi for JA3/JA4 TLS fingerprint matching
Fingerprint Config Control WebGL, WebRTC, canvas/audio noise per session
Playwright API Same API you already know

Anti-Detection Status

Technique Status Notes
Patchright (CDP leak) Implemented Protocol-level, not JS patches
navigator.webdriver Implemented --disable-blink-features=AutomationControlled
Headless User-Agent fix Implemented Auto-removes "HeadlessChrome" in headless mode
Human behavior (Bezier) Implemented Mouse, typing, scrolling
TLS fingerprinting (JA3/JA4) Implemented via curl_cffi for HTTP requests
Canvas noise Implemented Optional via FingerprintConfig(canvas_noise=True)
Audio noise Implemented Optional via FingerprintConfig(audio_noise=True)
WebRTC IP leak protection Implemented Via FingerprintConfig(webrtc=False)
WebGL control Implemented Enabled by default, disable via config
Timezone/Locale consistency Auto-validated Auto-configures from region or IP
Retry on rate limit Implemented Exponential backoff with Retry-After

Table of Contents

Installation

# Install SDK
pip install abrasio

# Install real Chrome (NOT Chromium) for maximum stealth
patchright install chrome

# Optional: TLS fingerprinting for HTTP requests
pip install abrasio[tls]

# Optional: fingerprint generation utilities
pip install abrasio[fingerprint]

# Install everything
pip install abrasio[all]

Requirements

  • Python 3.8+
  • Chrome browser (installed via patchright install chrome)

Quick Start

Local Mode (Free)

import asyncio
from abrasio import Abrasio

async def main():
    async with Abrasio(headless=False) as browser:
        page = await browser.new_page()
        await page.goto("https://example.com")
        print(await page.title())

asyncio.run(main())

Cloud Mode (Paid)

import asyncio
from abrasio import Abrasio

async def main():
    async with Abrasio(
        api_key="sk_live_xxx",
        region="BR",
        url="https://example.com.br",
    ) as browser:
        page = await browser.new_page()
        await page.goto("https://example.com.br")
        print(await page.title())

asyncio.run(main())

Synchronous API

from abrasio.sync_api import Abrasio

with Abrasio(headless=False) as browser:
    page = browser.new_page()
    page.goto("https://example.com")
    print(page.title())

FingerprintConfig

Control browser fingerprint protections in local mode only. In cloud mode, the cloud browser handles all fingerprinting automatically.

from abrasio import Abrasio, FingerprintConfig

async with Abrasio(
    headless=False,
    fingerprint=FingerprintConfig(
        webgl=True,          # Keep WebGL enabled (default). False blocks it.
        webrtc=False,        # Block WebRTC IP leak (recommended with proxy)
        canvas_noise=True,   # Add noise to canvas fingerprint
        audio_noise=True,    # Add noise to audio fingerprint
    ),
) as browser:
    page = await browser.new_page()
    await page.goto("https://example.com")
Option Default Description
webgl True Enable WebGL APIs. Disabling is a strong bot signal.
webrtc True Enable WebRTC. Set False with proxy to prevent real IP leak.
canvas_noise False Add imperceptible noise to canvas reads. Randomizes fingerprint.
audio_noise False Add noise to AudioContext reads. Randomizes fingerprint.

Cloud mode: FingerprintConfig is completely ignored. The cloud browser uses real collected fingerprints

Human-Like Behavior

Utilities for simulating realistic human behavior to bypass behavioral analysis.

Mouse Movement (Bezier Curves)

from abrasio.utils import human_move_to, human_click

# Move mouse with natural Bezier curve trajectory
await human_move_to(page, x=500, y=300)

# Click with natural movement and random offset
await human_click(page, "button#submit")

Natural Typing

from abrasio.utils import human_type

await human_type(
    page,
    "Hello, World!",
    selector="input#search",
    mistake_probability=0.02,
    think_pause_probability=0.05,
)

Smooth Scrolling

from abrasio.utils import human_scroll, simulate_reading

await human_scroll(page, "down", amount=400, smooth=True)
await simulate_reading(page, min_seconds=3, max_seconds=8)

All Utilities

from abrasio.utils import (
    human_move_to,      # Bezier curve mouse movement
    human_click,        # Natural click with movement
    human_type,         # Variable-speed typing with mistakes
    human_scroll,       # Smooth scrolling with momentum
    human_wait,         # Random wait (skewed distribution)
    random_delay,       # Simple random delay
    simulate_reading,   # Simulate page reading behavior
)

TLS Fingerprinting (HTTP)

For HTTP requests outside the browser, use StealthClient which matches real browser TLS fingerprints via curl_cffi.

pip install abrasio[tls]
from abrasio.http import StealthClient

# Async
async with StealthClient() as client:
    response = await client.get("https://example.com")
    print(response.text)

# With region (auto-sets Accept-Language)
async with StealthClient(region="BR") as client:
    response = await client.get("https://example.com.br")

# With proxy
async with StealthClient(proxy="http://user:pass@host:8080") as client:
    response = await client.get("https://example.com")

# Rotate browser version on each request
async with StealthClient(rotate_impersonation=True) as client:
    for url in urls:
        response = await client.get(url)

Configuration

AbrasioConfig

from abrasio import Abrasio, AbrasioConfig, FingerprintConfig

config = AbrasioConfig(
    # Mode: None = local (free), "sk_xxx" = cloud (paid)
    api_key=None,

    # Browser
    headless=False,                  # Visible = more stealthy
    proxy="http://user:pass@host:8080",
    timeout=30000,

    # Region (auto-configures locale/timezone)
    region="BR",

    # Fingerprint (local mode only)
    fingerprint=FingerprintConfig(
        webgl=True,
        webrtc=False,
        canvas_noise=True,
        audio_noise=True,
    ),

    # Profile persistence
    user_data_dir="./my_profile",

    # Cloud mode
    profile_id="my-profile",

    # Advanced
    extra_args=[],
    debug=False,
)

async with Abrasio(config) as browser:
    ...

Region Auto-Configuration

config = AbrasioConfig(region="BR")
# locale="pt-BR", timezone="America/Sao_Paulo"

config = AbrasioConfig(region="JP")
# locale="ja-JP", timezone="Asia/Tokyo"

50+ regions supported. If you set a mismatched timezone, you'll get a warning:

config = AbrasioConfig(region="BR", timezone="America/New_York")
print(config.region_warnings)
# ['Timezone mismatch: using America/New_York but region BR expects America/Sao_Paulo']

Without explicit region, locale/timezone are auto-detected from your public IP.

Environment Variables

Variable Description Default
ABRASIO_API_KEY API key for cloud mode None
ABRASIO_API_URL API base URL https://abrasio.scrapetechnology.com/

Cloud Mode (Paid)

With an API key, you get access to the Abrasio cloud infrastructure:

Feature Description
Real Fingerprints collected device data
Geo-Targeting Target specific countries/regions
Persistent Profiles Maintain cookies and history across sessions
Session Recording Playwright trace recording for debugging
Live View Real-time browser streaming via noVNC
Automatic Retry SDK retries on rate limit (429) with backoff
from abrasio import Abrasio

async with Abrasio(
    api_key="sk_live_xxx",
    region="BR",
    url="https://target-site.com.br",
    profile_id="my-profile",
) as browser:
    page = await browser.new_page()

    # Live view URL (if enabled on server)
    if browser.live_view_url:
        print(f"Watch live: {browser.live_view_url}")

    await page.goto("https://target-site.com.br")
    print(await page.title())

Error Handling

from abrasio import (
    Abrasio,
    AbrasioError,           # Base error
    AuthenticationError,    # Invalid API key (401)
    InsufficientFundsError, # Not enough balance (402)
    RateLimitError,         # Too many sessions (429) - auto-retried
    SessionError,           # Session creation/management error
    BrowserError,           # Browser operation error
    TimeoutError,           # Operation timeout
    BlockedError,           # Target site blocked request
)

try:
    async with Abrasio(api_key="sk_live_xxx") as browser:
        page = await browser.new_page()
        await page.goto("https://example.com")
except AuthenticationError:
    print("Invalid API key")
except InsufficientFundsError as e:
    print(f"Add funds. Balance: ${e.balance:.2f}")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except SessionError as e:
    print(f"Session error: {e.message}")
except AbrasioError as e:
    print(f"Error: {e.message}")

Note: The SDK automatically retries on 429 (rate limit), 502, 503, 504 with exponential backoff up to 3 times.

API Reference

Abrasio

class Abrasio:
    def __init__(
        self,
        config: Optional[AbrasioConfig] = None,
        *,
        api_key: Optional[str] = None,
        headless: bool = True,
        proxy: Optional[str] = None,
        stealth: bool = True,
        **kwargs,
    ): ...

    async def start(self) -> "Abrasio": ...
    async def close(self) -> None: ...
    async def new_page(self) -> Page: ...
    async def new_context(self, **kwargs) -> BrowserContext: ...

    @property
    def browser(self): ...       # Browser (cloud) or BrowserContext (local)
    @property
    def is_cloud(self) -> bool: ...
    @property
    def is_local(self) -> bool: ...
    @property
    def live_view_url(self) -> Optional[str]: ...  # Cloud mode only

Human Utilities

async def human_move_to(page, x, y, *, min_time=0.1, max_time=1.5): ...
async def human_click(page, selector=None, *, offset_range=5, move_first=True): ...
async def human_type(page, text, selector=None, *, mistake_probability=0.02): ...
async def human_scroll(page, direction="down", amount=None, *, smooth=True): ...
async def random_delay(min_ms=100, max_ms=500): ...
async def human_wait(min_seconds=0.5, max_seconds=2.0): ...
async def simulate_reading(page, min_seconds=2.0, max_seconds=8.0): ...

StealthClient (TLS)

from abrasio.http import StealthClient, BrowserImpersonation

class StealthClient:
    def __init__(self, impersonate=BrowserImpersonation.DEFAULT,
                 proxy=None, region=None, rotate_impersonation=False): ...

    async def get(self, url, **kwargs) -> StealthResponse: ...
    async def post(self, url, **kwargs) -> StealthResponse: ...

Best Practices

  1. Headless mode is safe — SDK automatically removes "HeadlessChrome" from User-Agent
  2. Don't set user_agent — let the SDK handle it (auto-fixed in headless mode)
  3. Don't set viewport — uses no_viewport for realistic behavior
  4. Add human behavior between actions (human_wait, human_click)
  5. Use persistent profiles with user_data_dir for cookie persistence
  6. Use region to auto-configure locale/timezone consistently
  7. Set webrtc=False when using a proxy (prevents IP leak)
  8. Test against bot detection sites before production deployment

Testing Anti-Detection

import asyncio
from abrasio import Abrasio

async def test():
    async with Abrasio(headless=False) as browser:
        page = await browser.new_page()

        await page.goto("https://bot.sannysoft.com/")
        await page.screenshot(path="sannysoft.png")

        await page.goto("https://abrahamjuliot.github.io/creepjs/")
        await page.wait_for_timeout(5000)
        await page.screenshot(path="creepjs.png")

asyncio.run(test())

Project Structure

abrasio-sdk/
├── abrasio/
│   ├── __init__.py          # Public API exports
│   ├── _api.py              # Abrasio class (local + cloud)
│   ├── _config.py           # AbrasioConfig, FingerprintConfig
│   ├── _exceptions.py       # Exception hierarchy
│   ├── local/
│   │   └── browser.py       # StealthBrowser (Patchright)
│   ├── cloud/
│   │   ├── browser.py       # CloudBrowser (API + CDP)
│   │   └── api_client.py    # HTTP client with retry
│   ├── http/
│   │   └── client.py        # StealthClient (curl_cffi TLS)
│   ├── sync_api/
│   │   └── _sync.py         # Synchronous wrapper
│   └── utils/
│       ├── human.py         # Human behavior simulation
│       ├── fingerprint.py   # Region config, validation
│       └── geolocation.py   # IP-based locale detection
├── examples/
│   ├── basic_local.py       # Local mode example
│   ├── basic_cloud.py       # Cloud mode example
│   ├── human_behavior.py    # Human behavior demo
│   ├── fingerprint_check.py # Fingerprint validation
│   └── tls_fingerprint.py   # TLS fingerprinting
├── docs/                    # Documentation
└── pyproject.toml

References

Support & Community

Channel Link
💬 Discord discord.gg/GBSKsC8DvS
📧 Email joao.sobhie@scrapetechnology.com
🌐 Docs scrapetechnology.com/abrasio/docs

For bug reports and feature requests, open a thread in the #abrasio-feedback channel on Discord.

License

Proprietary - Scrape Technology

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

abrasio-0.1.2.tar.gz (60.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

abrasio-0.1.2-py3-none-any.whl (50.4 kB view details)

Uploaded Python 3

File details

Details for the file abrasio-0.1.2.tar.gz.

File metadata

  • Download URL: abrasio-0.1.2.tar.gz
  • Upload date:
  • Size: 60.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for abrasio-0.1.2.tar.gz
Algorithm Hash digest
SHA256 934d7fbb32f8f67c76b4f2f779a0a1090ef995699e474d46deebd32f43ae05e5
MD5 920d8368c35bed85659df2855f9ab76b
BLAKE2b-256 3916945241e721763740260e3633604b883b0dd960abc30a6bdd5f02e7a9cfba

See more details on using hashes here.

File details

Details for the file abrasio-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: abrasio-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 50.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for abrasio-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 282e939a1fbf2818c8cafbbeb6a60dc8e62cb9701ee96a4a4c28a31629576093
MD5 2c95b2bc6f171724f8ad2fb6f6f564c2
BLAKE2b-256 222063b777b48fd827b56001c6431c9697af442a78a18576e7bcff3d08c11956

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page