mudfish
Python bindings for Mudfish Crawler, a Rust-native web crawling and intelligence engine.
This package wraps the Rust crawl engine directly (via PyO3) — there is no subprocess or network hop to a separate server. It exposes a typed, Pythonic API over the engine; the Rust project itself is at an early stage (see the main repo's ROADMAP_HONEST.md for full status).
Install
pip install mudfish
Usage
import mudfish
result = mudfish.crawl("https://example.com", depth=2, concurrency=30)
print(result.stats.urls_fetched, result.stats.duration_secs)
for page in result: # CrawlResult is iterable over its pages
print(page.status_code, page.url, page.title)
crawl() blocks until the crawl finishes (or hits max_urls / max_duration_secs) and returns a typed CrawlResult:
| Object | Fields |
|---|---|
CrawlResult |
crawl_id, pages: list[Page], errors: list[CrawlError], stats: CrawlStats — iterable over pages, len() is the page count, plus ok_pages |
Page |
url, final_url, status_code, content_type, depth, metadata: PageMetadata, links: list[Link], body_bytes, fetched_via: FetchMethod — helpers title, is_ok |
PageMetadata |
title, meta_description, canonical |
Link |
url, anchor_text, rel |
CrawlError |
url, message |
CrawlStats |
urls_discovered, urls_fetched, urls_skipped, errors, bytes_downloaded, duration_ms — helpers duration_secs, throughput_per_sec |
FetchMethod |
FetchMethod.HTTP ("Http") / FetchMethod.BROWSER ("Browser") |
Every typed object also supports the raw engine dict shape (result["stats"], page["status_code"], page.to_dict()), so code written against earlier versions keeps working. If you only want the raw dict, use mudfish.crawl_dict(...).
Async
crawl_async() runs the blocking engine on a worker thread, so it composes with asyncio and several crawls can run concurrently:
import asyncio
import mudfish
async def main() -> None:
results = await asyncio.gather(
mudfish.crawl_async("https://a.example"),
mudfish.crawl_async("https://b.example"),
)
for result in results:
print(result.stats.urls_fetched)
asyncio.run(main())
Reusable configuration
crawler = mudfish.Crawler(depth=1, concurrency=10)
home = crawler.crawl("https://example.com")
blog = await crawler.crawl_async("https://example.com/blog")
Errors
try:
mudfish.crawl("not-a-url")
except mudfish.InvalidURLError: # also a ValueError
...
except mudfish.CrawlFailedError: # also a RuntimeError
...
Everything derives from mudfish.MudfishError.
Options
All keyword-only, matching the CLI's flags (also available as the CrawlOptions dataclass):
| Parameter | Default | Meaning |
|---|---|---|
depth |
3 |
Max link-following depth |
concurrency |
50 |
Max requests in flight, whole crawl |
per_host_concurrency |
4 |
Max requests in flight per host |
same_domain |
True |
Restrict crawl to the seed's resolved domain |
max_urls |
10000 |
Hard cap on URLs fetched |
max_duration_secs |
None |
Optional wall-clock budget |
timeout_secs |
30 |
Per-request timeout |
request_delay_ms |
0 |
Min delay between requests to the same host |
max_response_bytes |
20 MB |
Per-response size cap |
respect_robots |
True |
Honor robots.txt |
allow_private_networks |
False |
Permit loopback/private targets (internal use only) |
render_js |
False |
Re-render JS-dependent pages in headless Chrome (needs Chrome on the host; much slower) |
render_settle_ms |
2000 |
When render_js is on, settle time before capturing a rendered page |
Limitations
- Chrome is not bundled. With
render_js=Truethe engine drives a headless Chrome that must already be installed on the host; if it cannot be launched, the crawl logs a warning and falls back to static HTML. - Single-platform wheels initially. Built and published from the maintainer's machine, not a cross-platform CI matrix yet — check PyPI for which platforms have wheels; others will need a Rust toolchain to build from source.
License
Apache-2.0.
Metadata
Release files for mudfish 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mudfish-0.2.0.tar.gz | 76.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mudfish-0.2.0-cp39-abi3-macosx_11_0_arm64.whl | CPython 3.9 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 5.0 MB
Release files / mudfish-0.2.0.tar.gz
| Download URL | mudfish-0.2.0.tar.gz |
|---|---|
| Size | 76.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
79067980803c080a69f71fbdf2d5c85a295b6ec5224ecfa9e4a0ae66388106d8
|
|
BLAKE2b-256 checksum How to use checksums |
5ca0b9eed0b37c1c7a37b985108dd97f079369834d9004d3a60dd8e41569ba81
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / mudfish-0.2.0-cp39-abi3-macosx_11_0_arm64.whl
| Download URL | mudfish-0.2.0-cp39-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 4.9 MB |
| Tags | CPython 3.9 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
0c069c83b2cc25ed74ebe9a546c695546bb248a3325c259a803de7b56abf9b7d
|
|
BLAKE2b-256 checksum How to use checksums |
3fe83b8187b133d8435e6c46b2b48e8b634f82629bc14f875bf6add614faa267
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|