@zenrows/cli 1.4.2 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +90 -19
- package/agent-plugin/skills/batch-jobs/SKILL.md +3 -3
- package/agent-plugin/skills/cost-control/SKILL.md +1 -2
- package/agent-plugin/skills/extract/SKILL.md +5 -5
- package/agent-plugin/skills/zenrows/SKILL.md +3 -3
- package/dist/src/adapters/batch.js +2 -3
- package/dist/src/adapters/extract.js +13 -1
- package/dist/src/cli/commands/batch.js +6 -6
- package/dist/src/cli/commands/crawl.js +535 -0
- package/dist/src/cli/commands/extract.js +7 -3
- package/dist/src/cli/index.js +2 -1
- package/dist/src/cli/output.js +38 -15
- package/dist/src/core/batch-api.js +2 -2
- package/dist/src/core/capabilities.js +2 -2
- package/dist/src/core/config.js +1 -1
- package/dist/src/core/crawl-api.js +418 -0
- package/dist/src/core/errors.js +9 -0
- package/dist/src/core/http.js +24 -5
- package/package.json +2 -1
- package/recipes/batch-estimate/RECIPE.md +2 -2
- package/registry/capabilities.json +14 -5
- package/registry/skills.json +14 -3
- package/registry/templates.json +2 -2
- package/skills/batch-jobs/SKILL.md +6 -7
- package/skills/crawl/SKILL.md +126 -0
- package/skills/extract/SKILL.md +3 -3
- package/skills/trace-debug/SKILL.md +12 -0
- package/skills/zenrows/SKILL.md +7 -2
- package/templates/batch-jsonl-pipeline/README.md +5 -5
- package/templates/extract-pricing-pages/README.md +1 -1
- package/workflows/competitor-intelligence/WORKFLOW.md +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: batch-jobs
|
|
3
|
-
description: Scale protected fetch/extract over many URLs via Batch
|
|
3
|
+
description: Scale protected fetch/extract over many URLs via Batch. Cloud create/status/results/cancel/wait/retry-failed work with an API key; estimate/validate run locally with no key.
|
|
4
4
|
version: 0.1.0
|
|
5
5
|
requires_backend_capabilities: [batch]
|
|
6
6
|
---
|
|
@@ -11,11 +11,10 @@ Process large workloads reliably and asynchronously. Batch is where Zenrows'
|
|
|
11
11
|
high-scale anti-bot advantage becomes obvious — Zenrows wins when the workflow
|
|
12
12
|
runs over thousands, millions, or recurring sets of URLs.
|
|
13
13
|
|
|
14
|
-
>
|
|
15
|
-
>
|
|
16
|
-
>
|
|
17
|
-
>
|
|
18
|
-
> toolkit never fakes a cloud run.
|
|
14
|
+
> Zenrows **Batch** runs on a separate host (`async.api.zenrows.com/v1`) and
|
|
15
|
+
> spends the same credits as Fetch. The cloud subcommands work with any active
|
|
16
|
+
> API key; a 403 maps to `BATCH_ACCESS_DENIED`. The toolkit never fakes a
|
|
17
|
+
> cloud run.
|
|
19
18
|
|
|
20
19
|
## Local (no key, always works)
|
|
21
20
|
```
|
|
@@ -40,7 +39,7 @@ correctly. The result carries two keys: `html` (the
|
|
|
40
39
|
raw page) and `parsed` (the structured data). Validate on a single URL with
|
|
41
40
|
`zenrows extract <url>` before running the full batch.
|
|
42
41
|
|
|
43
|
-
## Cloud (needs a key
|
|
42
|
+
## Cloud (needs a key)
|
|
44
43
|
```
|
|
45
44
|
zenrows batch create jobs.jsonl [--proxy-country cc] [--wait]
|
|
46
45
|
zenrows batch create jobs.jsonl --manual [--js-render] [--premium-proxy]
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: crawl
|
|
3
|
+
description: Collect the URLs behind one start page with Crawl (new): create a crawl, wait for it, read the kept URLs and optionally each page's HTML, stop it. Use when the user has a listing or section URL but not the item URLs.
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
requires_backend_capabilities: [crawl]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Crawl (new)
|
|
9
|
+
|
|
10
|
+
Give Crawl one start URL; it follows the links on that page (and on the
|
|
11
|
+
pages behind it, up to the depth you set) and returns the URLs it keeps. Use it
|
|
12
|
+
when you know where the items live (a category page, a blog index, a docs
|
|
13
|
+
section) but not the item URLs themselves. Once you have the URLs, read pages
|
|
14
|
+
with `zenrows fetch` / `zenrows extract`, or ask Crawl for each page's HTML
|
|
15
|
+
with `--output-format html`.
|
|
16
|
+
|
|
17
|
+
Crawl stays on the start URL's registrable domain; subdomains count. An account without Crawl access gets
|
|
18
|
+
403 `REQS008` → `CRAWL_NOT_ENABLED` ("Crawl is not enabled for this account");
|
|
19
|
+
do not retry it.
|
|
20
|
+
|
|
21
|
+
## Create, wait, read
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
zenrows crawl create https://example.com/products/ --depth 1 \
|
|
25
|
+
--max-items 20 --max-pages 25 --include-patterns /product/ --follow --json
|
|
26
|
+
zenrows crawl results <id> --json # every kept URL
|
|
27
|
+
zenrows crawl results <id> --out urls.jsonl # same, as JSONL
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- `--depth N` (1 to 100000) is optional: link hops from the start URL. `1` =
|
|
31
|
+
the start page's links; `2` = also the links on each of those pages. Leave
|
|
32
|
+
it out for no depth limit: the crawl follows links until `--max-items` or
|
|
33
|
+
`--max-pages` stops it, or nothing is left to open. A crawl created without
|
|
34
|
+
a depth has no `depth` field in its output.
|
|
35
|
+
- `--max-items` (kept URLs) and `--max-pages` (fetched pages) cap the crawl;
|
|
36
|
+
both default to 100. `--max-pages` bounds the cost: each page is one fetch.
|
|
37
|
+
The local policy `max_pages_per_run` caps `--max-pages` (default 1000);
|
|
38
|
+
above it the CLI refuses with `POLICY_LIMIT_EXCEEDED` before any request.
|
|
39
|
+
- `--include-patterns` / `--exclude-patterns` are substring matches on the
|
|
40
|
+
normalized URL and repeat:
|
|
41
|
+
`--include-patterns /product/ --exclude-patterns ?add-to-cart`.
|
|
42
|
+
- `create` returns at once. `--follow` (or `zenrows crawl wait <id>`) polls
|
|
43
|
+
until the crawl ends or `--timeout` seconds run out (default 600). When the
|
|
44
|
+
time runs out, the command exits 0 and prints the crawl with status
|
|
45
|
+
`running` and the hint `zenrows crawl wait <id>` (under `--json`, in
|
|
46
|
+
`note`). The crawl keeps running;
|
|
47
|
+
it is not stopped. Ctrl-C also stops the wait, not the crawl, and exits 130;
|
|
48
|
+
resume with `zenrows crawl wait <id>`.
|
|
49
|
+
- `results` on a running crawl returns the URLs kept so far, with
|
|
50
|
+
`partial: true`. Read again once the crawl ends. `--limit` sets the page size
|
|
51
|
+
of each request.
|
|
52
|
+
|
|
53
|
+
## Page HTML
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
zenrows crawl create <url> --depth 1 --output-format html --max-pages 20 --follow
|
|
57
|
+
zenrows crawl results <id> --json # fetched results carry content_url
|
|
58
|
+
zenrows crawl content <id> <content_id> # one page's HTML (or pass the content_url)
|
|
59
|
+
zenrows crawl download <id> --out pages.jsonl # every URL + HTML, NDJSON
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`--output-format html` uses up the page budget: each kept page is one more
|
|
63
|
+
fetch, and `--max-pages` counts it. Raise `--max-pages` to keep the same number
|
|
64
|
+
of URLs. A result's `content_status` is `pending`, `fetched` or `failed`; only
|
|
65
|
+
`fetched` results have content (else `CRAWL_CONTENT_NOT_FOUND`). `download`
|
|
66
|
+
reports the crawl's `status`, and `partial: true` while it runs.
|
|
67
|
+
|
|
68
|
+
## While it runs, and after
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
zenrows crawl get <id> # status, coverage, stop_reason / error, one page of results
|
|
72
|
+
zenrows crawl get <id> --cursor <c> --json # the next page; keep polling with next_cursor
|
|
73
|
+
zenrows crawl list # your crawls, newest first (--cursor, --limit)
|
|
74
|
+
zenrows crawl stop <id> # stop it; kept URLs stay readable
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
A crawl ends `completed` (nothing left, or a cap hit: `stop_reason`
|
|
78
|
+
`max_items` / `max_pages`), `stopped` (you stopped it) or `failed` (`error.code`
|
|
79
|
+
and `error.detail` say why). Only `failed` exits non-zero (`CRAWL_FAILED`).
|
|
80
|
+
`stop` on a crawl that already ended prints the status it ended with.
|
|
81
|
+
|
|
82
|
+
With `--json`, `create`, `get`, `wait` and `stop` print
|
|
83
|
+
`{ok, crawl_id, status, crawl}`; read `coverage`, `stop_reason` and `error`
|
|
84
|
+
under `crawl`. `get` adds `results` and `next_cursor`. `download` prints
|
|
85
|
+
`status: null` when the API sends no status.
|
|
86
|
+
|
|
87
|
+
## Limits
|
|
88
|
+
|
|
89
|
+
When the account has reached its limit of active jobs (3 by default), shared
|
|
90
|
+
with its Batch jobs, a create gets 429 `too_many_crawls` →
|
|
91
|
+
`CRAWL_TOO_MANY_CRAWLS`; nothing was created. Retry after `retry_after`
|
|
92
|
+
seconds (about 30), or stop one of your crawls or Batch jobs first. Any other
|
|
93
|
+
429 is `CRAWL_RATE_LIMITED`: requests are being throttled; retry after
|
|
94
|
+
`retry_after` seconds.
|
|
95
|
+
|
|
96
|
+
## Errors
|
|
97
|
+
|
|
98
|
+
Every Crawl error carries the API's code as `server_code` (when the API sent
|
|
99
|
+
one), and `crawl_id` on any call about one crawl.
|
|
100
|
+
|
|
101
|
+
The CLI retries transient failures, as the Crawl SDKs do: up to 3 retries,
|
|
102
|
+
waiting the `Retry-After` seconds (at most 30) or 250 ms x 2^n (+/-20% jitter,
|
|
103
|
+
at most 10 s). Reads retry on 429, 502, 503, 504 and network errors (a timeout
|
|
104
|
+
counts). `create` retries only with `--idempotency-key`, and only on 502, 503,
|
|
105
|
+
504 and network errors, never on 429. `stop` retries on 429, 502, 503 (including
|
|
106
|
+
`crawl_busy`) and 504, waiting the `Retry-After` seconds (at most 30) or 1 s.
|
|
107
|
+
The "Retry?" column is for errors that remain after these retries.
|
|
108
|
+
|
|
109
|
+
| Code | Meaning | Retry? |
|
|
110
|
+
| --- | --- | --- |
|
|
111
|
+
| `CRAWL_NOT_ENABLED` | 403 `REQS008`: Crawl is not enabled for this account | no |
|
|
112
|
+
| `AUTH_INVALID` | 401: the API key was rejected | no, log in again |
|
|
113
|
+
| `CRAWL_INSUFFICIENT_CREDITS` | 402: the account is out of credits (claim the account or add credits) | after credits renew or are added |
|
|
114
|
+
| `CRAWL_KEY_CAP_REACHED` | 402 `AUTH014` or `api_key_cap_reached`: this API key reached its credit cap | after the cap resets or is raised |
|
|
115
|
+
| `CRAWL_INVALID_REQUEST` | 400 or 422: fix the request. For `idempotency_key_reused`, send a new key or no key | no, not as is |
|
|
116
|
+
| `CRAWL_REQUEST_IN_FLIGHT` | 409: the same Idempotency-Key is still in flight | yes, once the first request ends |
|
|
117
|
+
| `CRAWL_NOT_FOUND` / `CRAWL_CONTENT_NOT_FOUND` | 404: wrong id, or the page has no content | no |
|
|
118
|
+
| `CRAWL_TOO_MANY_CRAWLS` | 429 `too_many_crawls` on `create`: the account's active-job limit | yes, after `retry_after` |
|
|
119
|
+
| `CRAWL_RATE_LIMITED` | any other 429: requests are being throttled | yes, after `retry_after` |
|
|
120
|
+
| `CRAWL_BUSY` | 503 `crawl_busy` on `stop`: the stop was not saved yet and the crawl still runs | yes, run the stop again after `retry_after` |
|
|
121
|
+
| `CRAWL_FAILED` | the crawl ended `failed`, or another error | 5xx: yes, with backoff |
|
|
122
|
+
| `BACKEND_UNAVAILABLE` | the API could not be reached | yes |
|
|
123
|
+
|
|
124
|
+
Rules: start small (`--depth 1`, low caps) and check the results before a
|
|
125
|
+
deep crawl. Mind the cost ([[cost-control]]). Read errors with
|
|
126
|
+
[[trace-debug]].
|
package/skills/extract/SKILL.md
CHANGED
|
@@ -12,7 +12,7 @@ access + extraction**, not generic LLM parsing.
|
|
|
12
12
|
|
|
13
13
|
## Methods
|
|
14
14
|
```
|
|
15
|
-
zenrows extract <url> # extract=auto (default); falls back to Autoparse if domain not
|
|
15
|
+
zenrows extract <url> # extract=auto (default); falls back to Autoparse if the domain is not prepared yet
|
|
16
16
|
zenrows extract <url> --autoparse # general-purpose Autoparse (any domain)
|
|
17
17
|
zenrows extract <url> --css '{"title":"h1","price":".price"}' # selector map
|
|
18
18
|
zenrows extract <url> --outputs emails,links # built-in output filters → JSON
|
|
@@ -21,8 +21,8 @@ zenrows extract <url> --validate # fail if not valid JSON
|
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
## When to use which
|
|
24
|
-
- **Extract** (`extract=auto`, default): richest fields on
|
|
25
|
-
- **Autoparse**: any website; also the automatic fallback when
|
|
24
|
+
- **Extract** (`extract=auto`, default): richest fields; works on any domain Zenrows has prepared.
|
|
25
|
+
- **Autoparse**: any website; also the automatic fallback when the domain is not prepared for Extract yet.
|
|
26
26
|
- **CSS**: you know the exact fields/selectors and want determinism.
|
|
27
27
|
- **Markdown/plaintext**: feed clean content to an LLM yourself.
|
|
28
28
|
|
|
@@ -45,6 +45,18 @@ zenrows trace export <run-id> # JSON for sharing
|
|
|
45
45
|
auto-created Free plan.
|
|
46
46
|
- `BATCH_FAILED` → the batch run ended `failed`; `failure_reason` and
|
|
47
47
|
`failure_detail` in `zenrows batch status <id> --json` say why.
|
|
48
|
+
- `CRAWL_NOT_ENABLED` → the API answered 403 `REQS008`: Crawl is not
|
|
49
|
+
enabled for this account. Do not retry; ask Zenrows support for access.
|
|
50
|
+
- `CRAWL_INSUFFICIENT_CREDITS` / `CRAWL_KEY_CAP_REACHED` → Crawl's 402: the
|
|
51
|
+
account is out of credits, or this key reached its credit cap (`AUTH014`).
|
|
52
|
+
Same advice as `POLICY_MAX_CREDITS_EXCEEDED` / `KEY_CREDIT_CAP_REACHED`.
|
|
53
|
+
- `CRAWL_TOO_MANY_CRAWLS` → 429 `too_many_crawls`: the account has reached
|
|
54
|
+
its limit of active jobs (3 by default), shared with its Batch jobs.
|
|
55
|
+
Nothing was created; retry after `retry_after` seconds (see
|
|
56
|
+
`zenrows crawl list`).
|
|
57
|
+
- `CRAWL_FAILED` → the crawl ended `failed`; `error.code` in
|
|
58
|
+
`zenrows crawl get <id> --json` says why, with `error.detail`. See
|
|
59
|
+
[[crawl]].
|
|
48
60
|
- `PARAM_CONFLICT_AUTO_MANUAL` → drop the managed flags or add `--manual`.
|
|
49
61
|
- `CAPABILITY_UNAVAILABLE` → the primitive is not available on this account (e.g. beta/invite-only); use the local-spec path where offered.
|
|
50
62
|
|
package/skills/zenrows/SKILL.md
CHANGED
|
@@ -34,6 +34,10 @@ If the user has a known URL and wants page content:
|
|
|
34
34
|
If the user has a known URL and wants structured data:
|
|
35
35
|
→ Use Extract. (zenrows extract <url> | --autoparse | --css)
|
|
36
36
|
|
|
37
|
+
If the user has a start page (listing, index, section) but not the item URLs:
|
|
38
|
+
→ Use Crawl. (zenrows crawl create <url> --depth 1 --follow,
|
|
39
|
+
then `zenrows crawl results <id>`)
|
|
40
|
+
|
|
37
41
|
If the user has many URLs (bulk):
|
|
38
42
|
→ Use Batch. (validate one page with fetch/extract first,
|
|
39
43
|
then `zenrows batch create <jobs.jsonl>`)
|
|
@@ -68,8 +72,9 @@ Run `zenrows status` for the live capability matrix. As of this toolkit:
|
|
|
68
72
|
| Primitive | Command | Status |
|
|
69
73
|
| --- | --- | --- |
|
|
70
74
|
| Protected Fetch | `zenrows fetch` | available (`GET /v1/`) |
|
|
71
|
-
| Extract (extract=auto / Autoparse/CSS/Markdown) | `zenrows extract` |
|
|
72
|
-
| Batch | `zenrows batch` |
|
|
75
|
+
| Extract (extract=auto / Autoparse/CSS/Markdown) | `zenrows extract` | available (same `/v1/`; extract=auto falls back to autoparse) |
|
|
76
|
+
| Batch | `zenrows batch` | available: runs cloud jobs (create/status/results); cheapest path at scale. Estimate specs locally with no key |
|
|
77
|
+
| Crawl | `zenrows crawl` | new — collect the URLs behind one start page, optionally with each page's HTML |
|
|
73
78
|
| Browser | `zenrows browser` | available (Browser Sessions REST API / MCP) |
|
|
74
79
|
| MCP | `zenrows mcp` | available (remote + local server) |
|
|
75
80
|
|
|
@@ -16,10 +16,10 @@ results carry `html` and `parsed` keys.
|
|
|
16
16
|
zenrows batch estimate jobs.example.jsonl # validate the spec + estimate credits
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
## Cloud (needs a key
|
|
19
|
+
## Cloud (needs a key)
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
The cloud subcommands run with any active API key and spend the same credits
|
|
22
|
+
as Fetch.
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
zenrows batch create jobs.example.jsonl --wait # submit + wait for the run to finish
|
|
@@ -33,5 +33,5 @@ Tasks use Adaptive Stealth Mode (`mode=auto`) by default. Job-level scrape
|
|
|
33
33
|
options come from flags (`--js-render`, `--premium-proxy`, `--proxy-country`,
|
|
34
34
|
`--output`, or `--manual` to turn Adaptive Stealth Mode off); per-line keys
|
|
35
35
|
override them for that URL.
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
Validate/estimate locally, or try `zenrows fetch` per URL on a small sample
|
|
37
|
+
first.
|
|
@@ -13,5 +13,5 @@ zenrows extract https://www.scrapingcourse.com/ecommerce/ --autoparse
|
|
|
13
13
|
zenrows extract <product-url> --css '{"title":"h1","price":".price"}' --validate
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
Requires `extract
|
|
16
|
+
Requires `extract`. Start on one page, confirm the fields, then
|
|
17
17
|
fan out `zenrows extract` across the rest of your URLs.
|
|
@@ -20,7 +20,7 @@ simple per-URL loop).
|
|
|
20
20
|
```
|
|
21
21
|
zenrows fetch https://competitor.example/products
|
|
22
22
|
```
|
|
23
|
-
2. **Validate extraction** on one page (extract
|
|
23
|
+
2. **Validate extraction** on one page (extract=auto falls back to autoparse on a domain not prepared yet).
|
|
24
24
|
```
|
|
25
25
|
zenrows extract https://competitor.example/p/123 --validate
|
|
26
26
|
```
|