High-performance async web scraper with Playwright and httpx. Scrape JavaScript-rendered pages, crawl websites recursively, parse sitemaps, and extract content with anti-bot bypass.
Project description
Trace Scraper
High-performance async web scraper for Python. Scrape JavaScript-rendered pages, crawl websites recursively, parse sitemaps, and extract clean content — all with built-in anti-bot bypass.
Why Trace Scraper?
- Hybrid Engine: Uses
httpxfor fast static pages,Playwrightfor JavaScript-heavy sites - Anti-Bot Bypass: Built-in detection evasion with realistic browser fingerprints
- Async & Parallel: Scrape hundreds of pages concurrently with asyncio
- Multiple Modes: Single page, recursive crawl, sitemap parsing, URL lists
- Clean Output: Automatic HTML cleanup, content deduplication, PDF extraction
- Type Safe: Full type hints with
py.typedmarker
Installation
pip install trace-scraper
Install Playwright browsers (required for JS rendering):
playwright install chromium
Quick Start
Command Line
# Scrape a single page
trace https://example.com
# Crawl entire website
trace https://docs.example.com --mode recursive --max-pages 100
# Parse sitemap
trace https://example.com/sitemap.xml --mode sitemap
# Use browser for JavaScript sites
trace https://spa-website.com --browser
# Save to JSON
trace https://example.com -o output.json
Python API
import asyncio
from trace_scraper import WebScraper, ScrapeMode
async def main():
async with WebScraper() as scraper:
async for doc in scraper.scrape("https://example.com", mode=ScrapeMode.SINGLE):
print(f"Title: {doc.semantic_identifier}")
print(f"Content: {doc.sections[0].text}")
asyncio.run(main())
Advanced Configuration
from trace_scraper import WebScraper, ScraperConfig, ScrapeMode
config = ScraperConfig(
max_concurrent_pages=20, # Parallel scraping
page_timeout=15.0, # Timeout per page
scroll_pages=True, # Load lazy content
extract_pdfs=True, # Extract PDF text
use_browser_for_all=False, # Use httpx when possible
)
async with WebScraper(config) as scraper:
async for doc in scraper.scrape(
"https://docs.example.com",
mode=ScrapeMode.RECURSIVE
):
print(doc.semantic_identifier)
CLI Options
| Option | Short | Default | Description |
|---|---|---|---|
--mode |
-m |
single |
Mode: single, recursive, sitemap |
--output |
-o |
- | Save results to JSON file |
--concurrency |
-c |
10 |
Max concurrent pages |
--timeout |
-t |
30 |
Page timeout (seconds) |
--max-pages |
- | - | Limit pages to scrape |
--browser |
- | - | Force browser for all pages |
--scroll |
- | - | Scroll to load dynamic content |
--delay |
-d |
0.1 |
Delay between requests |
--verbose |
-v |
- | Enable debug logging |
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
max_concurrent_pages |
int |
10 |
Pages to scrape in parallel |
max_concurrent_browsers |
int |
3 |
Browser contexts pool size |
page_timeout |
float |
30.0 |
Page load timeout |
request_timeout |
float |
10.0 |
HTTP request timeout |
max_retries |
int |
3 |
Retry attempts per page |
delay_between_requests |
float |
0.1 |
Rate limiting delay |
scroll_pages |
bool |
False |
Scroll for lazy-loaded content |
extract_pdfs |
bool |
True |
Extract text from PDFs |
deduplicate_content |
bool |
True |
Skip duplicate pages |
use_browser_for_all |
bool |
False |
Always use Playwright |
headless |
bool |
True |
Run browser headless |
Features
Scraping Modes
- Single: Scrape one URL
- Recursive: Crawl entire site following internal links
- Sitemap: Parse sitemap.xml and scrape all URLs
- URL List: Scrape a provided list of URLs
Content Extraction
- Automatic removal of scripts, styles, navigation, footers
- Clean text extraction with structure preservation
- Link extraction with markdown formatting
- PDF text extraction (optional dependency)
Anti-Bot Features
- Realistic browser fingerprints
- Custom User-Agent and headers
- Stealth mode scripts
- Automatic retry with browser fallback
Development
# Clone repository
git clone https://github.com/boxed-dev/trace.git
cd trace
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run linter
ruff check .
# Type check
mypy trace_scraper
License
MIT License - see LICENSE for details.
Project details
Release history Release notifications | RSS feed
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 trace_scraper-1.0.0.tar.gz.
File metadata
- Download URL: trace_scraper-1.0.0.tar.gz
- Upload date:
- Size: 18.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ff0936745f11c2a6e116849d74e47e52d2d755fee41f3c93afe1df3711f3e84
|
|
| MD5 |
4f34dd55c1b097a4529fc443d04fbee2
|
|
| BLAKE2b-256 |
f6aff93ad6cc151d1c5e66fec312879aabb56a803c3eb9b3604651fedb1a8b89
|
File details
Details for the file trace_scraper-1.0.0-py3-none-any.whl.
File metadata
- Download URL: trace_scraper-1.0.0-py3-none-any.whl
- Upload date:
- Size: 17.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f94f98def9e8d0e4e87e8dde45cfcf2606b645aa776b5404c901d158dd5e9075
|
|
| MD5 |
c7a393be8580be99fda1fe33d2c56c10
|
|
| BLAKE2b-256 |
0209b20e98c880d9cb4d91b4211d797f1acf824b93a32ac2907d22198b5fb963
|