Skip to main content

An async Python crawling framework for discovering URLs, extracting links, and scraping structured content.

Project description

Onecrawler

Onecrawler

An async Python crawling framework for discovering URLs, extracting links, and scraping structured content.

CI Python PyPI Code style: black Imports: isort License: MIT

Installation · Quick Start · Documentation


Overview

Onecrawler helps you build maintainable crawling and extraction workflows without turning every project into a custom scraping script. It provides a shared configuration model, async execution, sitemap discovery, browser-backed link extraction, heuristic content extraction, and optional GenAI extraction for typed outputs.

Recommended workflow:

  1. Use sitemaps first whenever possible.
  2. Fall back to browser link extraction when sitemap coverage is missing or dynamic.
  3. Scrape the final URL list with heuristic extraction by default.
  4. Use GenAI extraction when you need structured output in a Pydantic schema.
async with LinkExtractor(settings) as link_engine:
    links = await link_engine.run("https://example.com")

async with Scraper(settings) as scraper_engine:
    records = await scraper_engine.run(links)

Features

Capability Details
Sitemap discovery Resolves robots.txt, common sitemap paths, nested indexes, .xml.gz, feeds, and HTML fallback
Browser link extraction Shallow and deep Playwright-backed discovery for JavaScript-rendered or sitemap-poor sites
URL filtering Wildcard path filters with include_link_patterns
Async performance Tunable concurrency, retries, timeouts, and crawl limits
Content extraction Heuristic extraction with trafilatura for fast article-like content
GenAI extraction Optional model-assisted extraction for strongly typed Pydantic outputs
Output formats markdown, json, txt, xml, xmltei
Proxy support Single proxy or rotating proxy pools for browser and sitemap workflows
Browser controls Viewport, user agent, locale, timezone, storage state, and runtime settings

When To Use What

Need Use Why
Fast URL discovery from a public site UniversalSiteMap Simplest, fastest, and least expensive way to collect URLs
Links from one listing page Shallow LinkExtractor Reads direct same-site links from the page
Recursive discovery through navigation Deep LinkExtractor Follows internal links until your configured limit
Bulk article or page text extraction Heuristic Scraper Deterministic and avoids model cost
Typed fields or semantic normalization GenAI extraction Produces schema-shaped output for downstream systems

Installation

pip install onecrawler

Install Playwright browser binaries when you use browser-backed crawling or scraping:

python -m playwright install chromium

Install optional GenAI dependencies when you use model-assisted extraction:

pip install "onecrawler[genai]"

[!NOTE] GenAI extraction requires an API key from your chosen provider (OpenAI, Google) or a running Ollama instance. See GenAI Extraction for details.

For local development:

git clone https://github.com/sayedshaun/onecrawler.git
cd onecrawler
python -m pip install -e ".[dev]"
python -m playwright install chromium

Docker Support

OneCrawler provides an optimized Docker image that includes all necessary browser dependencies. This is the recommended way to run the framework in production or CI/CD environments.

Build the Image

docker pull ghcr.io/sayedshaun/onecrawler:latest

[!TIP] You can rename it for convenience

docker tag ghcr.io/sayedshaun/onecrawler:latest onecrawler

Run a Script with Docker

docker run -it --rm -v $(pwd):/app onecrawler python your_script.py

[!NOTE] The script must be located at the root of the mounted volume.


Quick Start

import json
from onecrawler import Settings, LinkExtractor, Scraper


async def main():
    settings = Settings(
        link_extraction_strategy="deep",
        link_extraction_limit=10,
        concurrency=7,
        scraping_strategy="heuristic",
        scraping_output_format="json",
        enable_human_behaviors=True,
    )

    async with LinkExtractor(settings) as link_engine:
        links = await link_engine.run("https://www.example.com/")

    async with Scraper(settings) as scraper_engine:
        results = await scraper_engine.run(links)

    with open("output.json", "w", encoding="utf-8") as f:
        json.dump(results, f, ensure_ascii=False, indent=4)


if __name__ == "__main__":
    import asyncio

    asyncio.run(main())

[!TIP] Always set link_extraction_limit when crawling broad sites. Without it, discovery can run indefinitely on large domains.


Browser Link Extraction

Use browser extraction when sitemaps are incomplete, unavailable, or unable to expose JavaScript-rendered links.

import asyncio
from onecrawler import Settings, LinkExtractor


async def main():
    settings = Settings(
        link_extraction_strategy="deep",
        link_extraction_limit=250,
        include_link_patterns=["/news/*"],
        concurrency=5,
    )

    async with LinkExtractor(settings) as engine:
        links = await engine.run("https://example.com/news")

    print(f"Collected {len(links)} links")


if __name__ == "__main__":
    asyncio.run(main())

[!TIP] Use include_link_patterns to keep discovery focused on relevant paths. For example, ["/blog/*", "/docs/*"] prevents the crawler from wandering into auth pages, admin routes, or unrelated sections.

[!NOTE] Deep extraction follows internal links recursively. Use shallow strategy when you only need links visible on a single listing page — it's significantly faster.


GenAI Extraction With a Schema

Use GenAI extraction when you need a strongly typed response shape instead of plain content.

pip install "onecrawler[genai]"
import asyncio
from typing import Optional
from pydantic import BaseModel
from onecrawler import Settings, GenerativeAISettings, Scraper


class ArticleSummary(BaseModel):
    title: str
    author: Optional[str] = None
    published_at: Optional[str] = None
    summary: str
    topics: list[str]


async def main():
    settings = Settings(
        scraping_strategy="genai",
        scraping_output_format="json",
        genai=GenerativeAISettings(
            provider="openai",
            model_name="gpt-4o-mini",
            api_key="YOUR_API_KEY",
            output_schema=ArticleSummary,
        ),
        concurrency=2,
        request_timeout=30,
    )

    async with Scraper(settings) as scraper:
        result = await scraper.run("https://example.com/articles/story")

    print(result.model_dump() if hasattr(result, "model_dump") else result)


if __name__ == "__main__":
    asyncio.run(main())

[!TIP] Keep concurrency low (2–4) for GenAI extraction. Each page triggers a model call; high concurrency can exhaust rate limits quickly and inflate costs.

[!WARNING] Never hardcode your API key in source files. Use environment variables or a secrets manager instead:

import os
api_key=os.environ["OPENAI_API_KEY"]

Supported Providers

Provider Requires Models
OpenAI api_key GPT-4o, GPT-4o-mini, etc.
Google api_key Gemini models
Ollama base_url (no key needed) Any locally hosted model

Ollama Example

settings = Settings(
    scraping_strategy="genai",
    genai=GenerativeAISettings(
        provider="ollama",
        model_name="llama3:8b",
        base_url="http://localhost:11434/",
        output_schema=ArticleSummary,
    ),
)

[!NOTE] Ollama requires a running local instance. Install it from ollama.com and pull your model (ollama pull llama3:8b) before running.


Proxy Support

Attach one proxy or a rotating proxy pool directly to Settings.

from onecrawler import Settings, ProxySettings


settings = Settings(
    proxies=[
        ProxySettings(server="http://proxy-1.example:8080"),
        ProxySettings(
            server="http://proxy-2.example:8080",
            username="user",
            password="pass",
        ),
    ],
    proxy_rotation="round_robin",
)

Use proxy=ProxySettings(...) for a single proxy, or proxies=[...] with proxy_rotation for a pool.

[!TIP] round_robin rotation distributes requests evenly across your proxy pool. For rate-limited targets, pair this with a modest concurrency value and a request_delay to avoid triggering bans.


Production Tips

[!IMPORTANT] Split URL discovery and scraping into separate pipeline steps. Collecting all URLs first gives you a checkpoint to resume from if scraping fails partway through — without re-running discovery.

[!TIP] Start with UniversalSiteMap before reaching for browser extraction. Sitemap-based discovery is faster, cheaper, and more complete on well-maintained sites. Fall back to LinkExtractor only when sitemaps are missing or stale.

[!TIP] Use heuristic scraping (scraping_strategy="heuristic") for bulk content extraction. Reserve GenAI extraction for cases where you genuinely need structured, schema-shaped output — it adds latency and cost at scale.

[!CAUTION] Respect robots.txt and a site's terms of service before crawling. Onecrawler does not enforce crawl policies automatically — you are responsible for staying within allowed access patterns.


License

Released under the MIT License. See LICENSE for full terms.

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

onecrawler-0.1.4.tar.gz (45.1 kB view details)

Uploaded Source

Built Distribution

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

onecrawler-0.1.4-py3-none-any.whl (45.3 kB view details)

Uploaded Python 3

File details

Details for the file onecrawler-0.1.4.tar.gz.

File metadata

  • Download URL: onecrawler-0.1.4.tar.gz
  • Upload date:
  • Size: 45.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for onecrawler-0.1.4.tar.gz
Algorithm Hash digest
SHA256 4729f2070c82f421407f539f0e9a243729d507067ec0dc9e5ec4f6df15d9516e
MD5 42fa257cd4e2bf529a0d5fed2d59afd5
BLAKE2b-256 afdc062d718fcb3721a8ce265a0207db910d790167e800642f1226a0c04208e5

See more details on using hashes here.

File details

Details for the file onecrawler-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: onecrawler-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 45.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for onecrawler-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 2ea735fe140ebce660aad59caba38d02174aa9eb4e77abf07406009741cc5d13
MD5 49bcba3b2a8706af0361ad767a3c479b
BLAKE2b-256 0ac58ab1ad498ef1593f234306d0fd973b7d8c0163b76bccd8de110946c6722d

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