opencraw (Python)
Crawl with OpenCraw from Python, with no Node to install: Crawler
downloads the driver's runtime for this platform once (a Node binary and the engine in one archive, checked
against its SHA-256 and cached in ~/.cache/opencraw/driver/), starts it, and talks to it over its pipes.
Standard library only; Python 3.12+.
from opencraw import Crawler
with Crawler(version="0.6.0") as crawler:
@crawler.hook()
def tidy(value, args, request): # a hook the recipes call: plain Python
return str(value).strip().lower()
run = crawler.run(paths=["recipes/"])
for record in run.records(): # as they are emitted
print(record)
print(run.report()["records"])
crawler.run(...)takes the driver's run options (out,only,dryRun,parallel,access, ...);run.records()andrun.events()yield as it crawls,run.report()waits for the end,run.cancel()stops it.crawler.work(next_item, ...)is worker mode:next_item()returns each window's item ({"id": ..., "vars": {...}}), orNoneto end.@crawler.hook(),@crawler.captcha_solver(),@crawler.access_plugin()register Python functions by name; raising fails that one call (CalloutErrorfor a plain message), never the run.crawler.validate,probe,diff,exportanswer as the driver does.AsyncCrawleris the asyncio twin:async with AsyncCrawler(version=...) as crawler,await crawler.run(...),async for record in run.records(), and hooks, plugins andnext_itemmay beasync def.OPENCRAW_DRIVER=<folder>uses an unpacked runtime;OPENCRAW_DRIVER_OFFLINE=1never downloads;command=starts any other driver (["node", "path/to/main.esm.js"]).
The rest of this page is the older way, which stays: build recipes in Python and run the opencraw CLI once
per call (npm i -g @opencraw/cli, or OPENCRAW_CLI set to the command that starts it; with neither,
npx @opencraw/cli is used).
A recipe stays a plain dict in the engine's own shape, so the recipe guide (docs/recipes/authoring.md) is the reference for every key. The constructors only save typing, and the engine, not this package, says what is valid.
from opencraw import input_recipe, output_recipe, run, step, validate
product = output_recipe(
"product",
{
"url": {"type": "url", "required": True, "key": True},
"title": {"type": "string", "required": True},
},
)
shops = [
input_recipe(
f"shop-{name}",
"product",
"web",
[url],
[
step("goto", url="{{start.url}}"),
step("extract", id="title", selector=selector, kind="css", take="text"),
step("emit"),
],
{"url": {"from": "start.url"}, "title": {"from": "title"}},
)
for name, url, selector in [
("a", "https://a.example", "h1"),
("b", "https://b.example", ".name"),
]
]
result = validate(
[product, *shops]
) # Validation(ok, output): problems are data, not exceptions
records = run(
[product, *shops], "--only", "shop-a"
) # records as dicts; OpenCrawError if the crawl fails
Reserved words: pass a step's as or from through **{"as": "json"}.
write_recipes(folder, recipes) writes <id>.input.json and <id>.output.json for the CLI, the Studio
and the MCP server.
A hook written in Python
A recipe's hook ({ "op": "hook", "name": "slug" }) can be a Python script. The hooks module registers it
with commandHook (@opencraw/core), and the script is a few lines:
# hooks/slug.py
import re
from opencraw import serve_hook
serve_hook(
lambda value, args, request: re.sub(r"[^a-z0-9]+", "-", str(value).lower()).strip(
"-"
)
)
serve_hook(handler) reads the request from stdin, calls handler(input, args, request) (input is None
for a hook step; request carries context and idempotencyKey) and writes the answer to stdout. What the
handler returns is the output; an exception becomes an error answer with its message, so the step fails with
that reason. A handler whose work takes longer raises HookPending(retry_after_ms): OpenCraw runs the script
again after that wait, with the same idempotencyKey, until it returns or the hook's maxWaitMs passes, so the
script starts the work once and looks it up by that key on later runs. The request and answer shapes are in
packages/core/schemas/callout-*.schema.json.
Not in this package: a Python engine and generated typed models. The crawl itself always runs in the
OpenCraw CLI. It is published to PyPI as opencraw: mnci ci release versions and publishes what sits
under python-packages/.
Development
smith run test -p opencraw (pytest; the CLI integration tests use this repository's built CLI and skip
without it), smith run lint -p opencraw (Ruff), smith run typecheck -p opencraw (mypy strict).
Layout. One slice package per outcome: recipe_building/ (recipes in Python, written to files),
hook_serving/ (hooks served as command callouts), cli_bridge/ (the CLI, run once per call),
driver_runtime/ (the runtime's download and cache), driver_channel/ (JSON-RPC over the driver's pipes) and
crawl_session/ (Crawler and Run). Its tests replay the driver's conformance transcripts against the
repository's built driver.
Metadata
Release files for opencraw 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| opencraw-0.3.1.tar.gz | 26.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| opencraw-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 52.9 kB
Release files / opencraw-0.3.1.tar.gz
| Download URL | opencraw-0.3.1.tar.gz |
|---|---|
| Size | 26.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
88520fcf06b875929560417548be0d9845e7ad54740df847defb472714a65a17
|
|
BLAKE2b-256 checksum How to use checksums |
b81a92957eef46ffe6f9e6337bddf21aeb7ae3a6db40d76e7264602fe63bba7d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Release files / opencraw-0.3.1-py3-none-any.whl
| Download URL | opencraw-0.3.1-py3-none-any.whl |
|---|---|
| Size | 26.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
021e45d0cdf3d5e1cb7161d44a5adb8dac9e00a5cc8e0b9be3e6aab5d3b5f518
|
|
BLAKE2b-256 checksum How to use checksums |
316879f4b2e8666b1cd05ddae6f13f0e26377c9401f2aa34213f646ff7e146c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.15
|
Security for opencraw 0.3.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.