Skip to main content
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)  # [{"url": ..., "result": ...}, ...]

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
Content filtering Composable post-extraction filters by date, keywords, file type, and cosine similarity with AND/OR/NOT logic
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, 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]"

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

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

Quick Start

from onecrawler import Settings, Crawler
from onecrawler.utils import writter

async def main():
    settings = Settings(link_extraction_limit=100, concurrency=5)

    async with Crawler(settings) as engine:
        results = await engine.run("https://www.prothomalo.com/")

    writter.dump_json(results, "output.json")


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

Separate Workflow

from onecrawler import Settings, LinkExtractor, Scraper
from onecrawler.utils import writter

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)  # [{"url": ..., "result": ...}, ...]

    writter.dump_json(results, "output.json")


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

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())

Content Filtering

Filter crawled results by date, keywords, file type, or semantic similarity. Filters are passed to Crawler.run() or Crawler.stream() and applied after content extraction.

import asyncio
from onecrawler import Crawler, Settings
from onecrawler.filters import by_date, by_keywords
from onecrawler.filters.chain import AND


async def main():
    settings = Settings(
        link_extraction_limit=50,
        concurrency=5,
    )

    # Keep only pages from 2025 that mention "python" or "async"
    content_filter = AND(
        by_date(start="2025-01-01", end="2025-12-31"),
        by_keywords(["python", "async"]),
    )

    async with Crawler(settings) as engine:
        results = await engine.run(
            "https://example.com/blog",
            filters=content_filter,
        )

    print(f"Matched {len(results)} pages")


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

Available Filters

Filter Import Purpose
by_date(start, end) onecrawler.filters Keep items within a YYYY-MM-DD date range
by_keywords(keywords) onecrawler.filters Keep items whose text contains any keyword
by_files(types) onecrawler.filters Keep items by logical file type (pdf, image, docx, text)
by_extension(extensions) onecrawler.filters Keep items by URL file extension (.pdf, .jpg)
by_cosine_similarity(query, threshold) onecrawler.filters Keep items whose text is semantically similar to a query

Composing Filters

Use AND, OR, and NOT from onecrawler.filters.chain to combine filters:

from onecrawler.filters import by_date, by_keywords, by_files
from onecrawler.filters.chain import AND, OR, NOT

# Pages from 2025 that mention "python" but are not PDFs
f = AND(
    by_date(start="2025-01-01"),
    by_keywords(["python"]),
    NOT(by_files(["pdf"])),
)

# Pages that mention "AI" or are from 2025
f = OR(
    by_keywords(["AI"]),
    by_date(start="2025-01-01", end="2025-12-31"),
)

Streaming With Filters

Filters work with Crawler.stream() for real-time filtered output:

async with Crawler(settings) as engine:
    async for item in engine.stream(
        "https://example.com/news",
        filters=by_cosine_similarity("climate policy", threshold=0.3),
    ):
        print(item["title"])

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:
        item = await scraper.run("https://example.com/articles/story")

    result = item["result"]
    print(result.model_dump() if hasattr(result, "model_dump") else result)


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

Supported Providers

Provider Requires Models
OpenAI api_key (optional with a custom base_url) GPT-4o, GPT-4o-mini, or any OpenAI-compatible server
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,
    ),
)

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_method="round_robin",
)

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


Production Tips


License

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

Metadata

Release files for onecrawler 0.1.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for onecrawler 0.1.8
File Size Uploaded
onecrawler-0.1.8.tar.gz 65.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for onecrawler 0.1.8
File Interpreter ABI Platform
onecrawler-0.1.8-py3-none-any.whl Python 3 none any Details

Total release size: 132.4 kB

Release files / onecrawler-0.1.8.tar.gz

Download URL onecrawler-0.1.8.tar.gz
Size 65.3 kB
Tags Source
SHA-256 checksum
How to use checksums
d1115392e3b91bd37f36f5dd71f8e2945344f83ad3a7d58d0d3272f4f66834d9
BLAKE2b-256 checksum
How to use checksums
58e5f970d2523328be58932a604bb3cb0a51dba4641e85fc5ec09eec326d7b82
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release files / onecrawler-0.1.8-py3-none-any.whl

Download URL onecrawler-0.1.8-py3-none-any.whl
Size 67.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bd0872ceb8739a579c7210f168f17f2c7de8276e1b4b4fbd2dea415008202387
BLAKE2b-256 checksum
How to use checksums
8e10f3ba3eedca77c0636e5cf103ecdbb4c3b2098fb2e128f873281cee4de998
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.13

Release history Release notifications | RSS feed

0.1.9

2 release files

This release

0.1.8 This release

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page