@zenrows/cli 1.10.0 → 1.11.0
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 +10 -2
- package/agent-plugin/README.md +1 -1
- package/agent-plugin/skills/extract/SKILL.md +9 -4
- package/agent-plugin/skills/zenrows/SKILL.md +1 -1
- package/dist/src/cli/commands/extract-prepare.js +18 -4
- package/dist/src/core/config.js +1 -1
- package/dist/src/core/http.js +1 -1
- package/dist/src/core/prepared-domains-api.js +20 -2
- package/package.json +1 -1
- package/registry/capabilities.json +1 -1
- package/skills/extract/SKILL.md +11 -5
- package/skills/zenrows/SKILL.md +2 -1
package/README.md
CHANGED
|
@@ -147,10 +147,18 @@ few minutes if it should work, or use `--css`; preparing again does not change
|
|
|
147
147
|
it. `zenrows extract` never falls back to Autoparse. The `fallbackAutoparse`
|
|
148
148
|
adapter option is deprecated and has no effect.
|
|
149
149
|
|
|
150
|
+
Pass 1 to 5 example URLs. One works; we recommend 3 or more of the same page
|
|
151
|
+
type (e.g. 3 product pages), because Extract compares pages of one type to check
|
|
152
|
+
the fields it found and fill in fields one page is missing. Several page types
|
|
153
|
+
can share the 5 (e.g. 3 product pages + 2 search-result pages).
|
|
154
|
+
|
|
150
155
|
```bash
|
|
151
|
-
zenrows extract prepare example.com
|
|
156
|
+
zenrows extract prepare example.com \
|
|
157
|
+
--url https://www.example.com/products/a \
|
|
158
|
+
--url https://www.example.com/products/b \
|
|
159
|
+
--url https://www.example.com/products/c --wait
|
|
152
160
|
zenrows extract prepare status example.com # progress + monthly allowance
|
|
153
|
-
zenrows extract https://example.com/
|
|
161
|
+
zenrows extract https://www.example.com/products/a # then extract again
|
|
154
162
|
```
|
|
155
163
|
|
|
156
164
|
## 9. Batch
|
package/agent-plugin/README.md
CHANGED
|
@@ -62,7 +62,7 @@ Use MCP tool names — not CLI `zenrows fetch`:
|
|
|
62
62
|
| --- | --- |
|
|
63
63
|
| `zenrows` | Decision tree across all primitives |
|
|
64
64
|
| `protected-fetch` | `scrape` |
|
|
65
|
-
| `extract` | `extract` (fallback: `scrape` + css_extractor); on REQS007 with reason `domain_not_prepared`, `prepare_domain` then `prepared_domain_status` |
|
|
65
|
+
| `extract` | `extract` (fallback: `scrape` + css_extractor); on REQS007 with reason `domain_not_prepared`, `prepare_domain` (1 to 5 example URLs; we recommend 3 or more of the same page type) then `prepared_domain_status` |
|
|
66
66
|
| `batch-jobs` | `batch_create`, `batch_status`, `batch_results`, `batch_cancel` |
|
|
67
67
|
| `interact-browser` | `browser_*` (escalation only) |
|
|
68
68
|
| `cost-control` | Cost multipliers + escalate-with-evidence |
|
|
@@ -48,15 +48,20 @@ Preparing a domain:
|
|
|
48
48
|
|
|
49
49
|
```
|
|
50
50
|
extract({ url }) # 1. REQS007, reason domain_not_prepared
|
|
51
|
-
prepare_domain({ domain: "example.com",
|
|
52
|
-
|
|
51
|
+
prepare_domain({ domain: "example.com", example_urls: [
|
|
52
|
+
"https://www.example.com/products/a",
|
|
53
|
+
"https://www.example.com/products/b",
|
|
54
|
+
"https://www.example.com/products/c"] })
|
|
53
55
|
# 2. returns at once, status "preparing"
|
|
54
56
|
prepared_domain_status({ domain: "example.com" }) # 3. about every 30 seconds until "ready"
|
|
55
57
|
extract({ url }) # 4. extract again
|
|
56
58
|
```
|
|
57
59
|
|
|
58
|
-
- `example_urls`: 1 to 5 real pages you want to extract
|
|
59
|
-
|
|
60
|
+
- `example_urls`: 1 to 5 real pages you want to extract. One works; we
|
|
61
|
+
recommend 3 or more of the same page type (e.g. 3 product pages), because
|
|
62
|
+
Extract compares pages of one type to check the fields it found and fill in
|
|
63
|
+
fields one page is missing. Several page types can share the 5 (e.g. 3
|
|
64
|
+
product pages + 2 search-result pages).
|
|
60
65
|
- The domain is the host: `shop.example.com` and `example.com` are prepared
|
|
61
66
|
separately, and a leading `www.` is dropped.
|
|
62
67
|
- Preparing takes a few minutes and costs no credits. Each new domain uses one
|
|
@@ -71,7 +71,7 @@ If the user needs login, clicks, forms, sessions, or persistent state:
|
|
|
71
71
|
| --- | --- | --- |
|
|
72
72
|
| Protected Fetch | `scrape` | Default markdown; HTML / plaintext / PDF / screenshot options |
|
|
73
73
|
| Extract | `extract` | Structured JSON (`extract=auto` on any prepared domain, css_extractor; autoparse deprecated). `extract=auto` is currently free; billing may apply later |
|
|
74
|
-
| Prepare a domain | `prepare_domain`, `prepared_domain_status` | After an `extract` REQS007 with reason `domain_not_prepared`: prepare the domain with 1 to 5 example URLs, poll about every 30 seconds until ready, extract again. No credits; uses one monthly allowance slot. Not for `page_not_recognised`: that domain is already prepared |
|
|
74
|
+
| Prepare a domain | `prepare_domain`, `prepared_domain_status` | After an `extract` REQS007 with reason `domain_not_prepared`: prepare the domain with 1 to 5 example URLs (one works; we recommend 3 or more of the same page type, because Extract compares pages of one type to check the fields it found and fill in fields one page is missing), poll about every 30 seconds until ready, extract again. No credits; uses one monthly allowance slot. Not for `page_not_recognised`: that domain is already prepared |
|
|
75
75
|
| Batch | `batch_create`, `batch_status`, `batch_results`, `batch_cancel` | Same credits as Fetch; a 403 maps to `BATCH_ACCESS_DENIED` |
|
|
76
76
|
| Browser | `browser_*` (start with `browser_navigate`) | Escalation-only; same backend as Browser Sessions |
|
|
77
77
|
|
|
@@ -5,14 +5,15 @@
|
|
|
5
5
|
* The way out of REQS007: prepare the domain so `extract=auto` works on it.
|
|
6
6
|
* Submitting returns at once; `--wait` polls until the preparation is ready or
|
|
7
7
|
* failed (a few minutes). Costs no credits; each new domain uses one slot of the
|
|
8
|
-
* account's monthly allowance.
|
|
8
|
+
* account's monthly allowance. One --url works; with fewer than 3 the command prints a
|
|
9
|
+
* tip to stderr (never an error): we recommend 3 or more of the same page type, up to 5.
|
|
9
10
|
*/
|
|
10
11
|
import { ensureApiKey } from "../../core/ensure-key.js";
|
|
11
12
|
import { loadConfig } from "../../core/config.js";
|
|
12
13
|
import { loadPolicy } from "../../core/policy.js";
|
|
13
14
|
import { log } from "../../core/logger.js";
|
|
14
15
|
import { ToolkitError } from "../../core/errors.js";
|
|
15
|
-
import { DEFAULT_WAIT_TIMEOUT_MS, MAX_EXAMPLE_URLS, failureNextStep, getAllowance, getPreparedDomain, normalizeDomain, prepareDomain, statusNextStep, waitForPreparedDomain, } from "../../core/prepared-domains-api.js";
|
|
16
|
+
import { DEFAULT_WAIT_TIMEOUT_MS, MAX_EXAMPLE_URLS, RECOMMENDED_EXAMPLE_URLS, exampleUrlsHint, failureNextStep, getAllowance, getPreparedDomain, normalizeDomain, prepareDomain, statusNextStep, waitForPreparedDomain, } from "../../core/prepared-domains-api.js";
|
|
16
17
|
import { parse, asString } from "../command.js";
|
|
17
18
|
import { printError } from "../output.js";
|
|
18
19
|
export const PREPARE_USAGE = "zenrows extract prepare <domain> --url <page-url> [--url <page-url>...] [--wait [--timeout <seconds>]]\n" +
|
|
@@ -23,7 +24,8 @@ export const PREPARE_HELP = [
|
|
|
23
24
|
"Not for EXTRACT_PAGE_NOT_RECOGNISED: that domain is already prepared, and preparing it",
|
|
24
25
|
"again does not change that answer.",
|
|
25
26
|
"",
|
|
26
|
-
` --url <page-url>
|
|
27
|
+
` --url <page-url> a real page you want to extract (repeat --url, 1 to ${MAX_EXAMPLE_URLS}). One works;`,
|
|
28
|
+
` we recommend ${RECOMMENDED_EXAMPLE_URLS} or more of the same page type (e.g. 3 product pages)`,
|
|
27
29
|
" --wait poll every 30 seconds until the domain is ready or failed; off by default",
|
|
28
30
|
` --timeout <seconds> give up waiting after this long (default ${DEFAULT_WAIT_TIMEOUT_MS / 1000})`,
|
|
29
31
|
" status <domain> show progress and the account's monthly allowance",
|
|
@@ -33,6 +35,14 @@ export const PREPARE_HELP = [
|
|
|
33
35
|
"account's monthly allowance; a domain that is already prepared answers ready at once and",
|
|
34
36
|
"uses none. The domain is the host (shop.example.com and example.com are separate); a",
|
|
35
37
|
"leading www. is dropped.",
|
|
38
|
+
"",
|
|
39
|
+
`1 to ${MAX_EXAMPLE_URLS} example URLs. One works; we recommend ${RECOMMENDED_EXAMPLE_URLS} or more of the same page type`,
|
|
40
|
+
"(e.g. 3 product pages), because Extract compares pages of one type to check the fields",
|
|
41
|
+
`it found and fill in fields one page is missing. Several page types can share the ${MAX_EXAMPLE_URLS}`,
|
|
42
|
+
"(e.g. 3 product pages + 2 search-result pages). Three product pages:",
|
|
43
|
+
"",
|
|
44
|
+
" zenrows extract prepare example.com --url https://www.example.com/products/a \\",
|
|
45
|
+
" --url https://www.example.com/products/b --url https://www.example.com/products/c --wait",
|
|
36
46
|
].join("\n");
|
|
37
47
|
export async function runPrepare(argv, ctx, deps = {}) {
|
|
38
48
|
const isStatus = argv[0] === "status";
|
|
@@ -69,6 +79,10 @@ export async function runPrepare(argv, ctx, deps = {}) {
|
|
|
69
79
|
return 0;
|
|
70
80
|
}
|
|
71
81
|
log.step(`Prepare ${domain} for Extract (${urls.length} example URL${urls.length === 1 ? "" : "s"})…`);
|
|
82
|
+
// Advice on stderr only: the --json payload on stdout and the exit code are unchanged.
|
|
83
|
+
const hint = exampleUrlsHint(urls.length);
|
|
84
|
+
if (hint)
|
|
85
|
+
log.dim(hint);
|
|
72
86
|
let record = await prepareDomain(domain, urls, opts);
|
|
73
87
|
if (record.already_in_progress)
|
|
74
88
|
log.info(`${domain} was already being prepared; following that preparation.`);
|
|
@@ -108,7 +122,7 @@ function validateUrls(raw, domain) {
|
|
|
108
122
|
code: "INVALID_USAGE",
|
|
109
123
|
message: `Pass 1 to ${MAX_EXAMPLE_URLS} example page URLs with --url (got ${urls.length}).`,
|
|
110
124
|
likely_cause: "Preparation learns the domain from real pages you want to extract.",
|
|
111
|
-
next_action:
|
|
125
|
+
next_action: `Add 1 to ${MAX_EXAMPLE_URLS} --url pages. One works; ${RECOMMENDED_EXAMPLE_URLS} or more of the same page type work better.`,
|
|
112
126
|
suggested_commands: [`zenrows extract prepare ${domain} --url https://${domain}/<page>`],
|
|
113
127
|
});
|
|
114
128
|
}
|
package/dist/src/core/config.js
CHANGED
|
@@ -14,7 +14,7 @@ export const CONFIG_VERSION = "0.1.0";
|
|
|
14
14
|
* entrypoint) so core modules — telemetry, signup provenance — can read it
|
|
15
15
|
* without an import cycle. `VERSION` in `cli/index.ts` re-exports this.
|
|
16
16
|
*/
|
|
17
|
-
export const CLI_VERSION = "1.
|
|
17
|
+
export const CLI_VERSION = "1.11.0"; // x-release-please-version
|
|
18
18
|
/** The User-Agent on every request to a Zenrows API. The gateway reads the version from it. */
|
|
19
19
|
export const CLI_USER_AGENT = `zenrows-cli/${CLI_VERSION}`;
|
|
20
20
|
/** Env var to override the Fetch and Extract API base (local/staging testing). */
|
package/dist/src/core/http.js
CHANGED
|
@@ -314,7 +314,7 @@ export function extractDomainNotPrepared(url, body) {
|
|
|
314
314
|
code: "EXTRACT_DOMAIN_NOT_PREPARED",
|
|
315
315
|
message: `Extract hasn't prepared ${domain} yet. Prepare it with \`${prepare}\` (a few example URLs, a few minutes, no credits), then retry; meanwhile use --css.`,
|
|
316
316
|
likely_cause: detail ?? `Extract has not prepared ${domain} yet.`,
|
|
317
|
-
next_action: `Run \`${prepare} --wait\` (
|
|
317
|
+
next_action: `Run \`${prepare} --wait\` (1 to 5 --url pages: one works; we recommend 3 or more of the same page type), then retry \`zenrows extract ${url}\`. Without --wait, check progress about every 30 seconds with \`zenrows extract prepare status ${domain}\`. Meanwhile extract with --css and explicit selectors.`,
|
|
318
318
|
suggested_commands: [`${prepare} --wait`, `zenrows extract prepare status ${domain}`, css],
|
|
319
319
|
server_code: "REQS007",
|
|
320
320
|
});
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* `extract=auto` answers REQS007 on a domain Extract has not prepared yet. Preparing
|
|
5
5
|
* it is a call any key can make: `POST {apiBase}/extract/prepared-domains` with the
|
|
6
6
|
* domain and 1 to 5 example URLs answers 202 at once; the preparation itself takes a
|
|
7
|
-
* few minutes and costs no credits.
|
|
7
|
+
* few minutes and costs no credits. One example URL works; we recommend 3 or more of
|
|
8
|
+
* the same page type (see `RECOMMENDED_EXAMPLE_URLS`). `GET .../{domain}` reports progress and
|
|
8
9
|
* `GET .../allowance` the account's monthly allowance of new domains. Auth is the
|
|
9
10
|
* `X-API-Key` header; errors are problem+json and we branch on `status` + `code`.
|
|
10
11
|
* `fetchImpl` / `sleepImpl` / `now` are injectable for tests.
|
|
@@ -14,6 +15,23 @@ import { registerSecret } from "./logger.js";
|
|
|
14
15
|
import { CLI_USER_AGENT, loadConfig } from "./config.js";
|
|
15
16
|
import { agentClientHeader } from "./agent-client.js";
|
|
16
17
|
export const MAX_EXAMPLE_URLS = 5;
|
|
18
|
+
/**
|
|
19
|
+
* How many example URLs to recommend: 3 or more of the same page type, because
|
|
20
|
+
* Extract compares pages of one type to check the fields it found and fill in fields
|
|
21
|
+
* one page is missing. Advice only: 1 and 2 URLs are still valid.
|
|
22
|
+
*/
|
|
23
|
+
export const RECOMMENDED_EXAMPLE_URLS = 3;
|
|
24
|
+
/**
|
|
25
|
+
* A short, non-blocking hint when fewer than `RECOMMENDED_EXAMPLE_URLS` example
|
|
26
|
+
* URLs were given; undefined otherwise. Never an error.
|
|
27
|
+
*/
|
|
28
|
+
export function exampleUrlsHint(count) {
|
|
29
|
+
if (count >= RECOMMENDED_EXAMPLE_URLS)
|
|
30
|
+
return undefined;
|
|
31
|
+
return (`Tip: ${count === 1 ? "one example URL works" : `${count} example URLs work`}; we recommend ` +
|
|
32
|
+
`${RECOMMENDED_EXAMPLE_URLS} or more of the same page type (e.g. 3 product pages), up to ${MAX_EXAMPLE_URLS} in total, ` +
|
|
33
|
+
"because Extract compares pages of one type to check the fields it found and fill in fields one page is missing.");
|
|
34
|
+
}
|
|
17
35
|
/** How often `--wait` polls, and for how long by default. */
|
|
18
36
|
export const DEFAULT_POLL_INTERVAL_MS = 30_000;
|
|
19
37
|
export const DEFAULT_WAIT_TIMEOUT_MS = 15 * 60_000;
|
|
@@ -247,7 +265,7 @@ export function failureNextStep(domain, failure) {
|
|
|
247
265
|
step = `Run the same zenrows extract prepare ${domain} command again.`;
|
|
248
266
|
break;
|
|
249
267
|
case "discovery_failed":
|
|
250
|
-
step = `Run zenrows extract prepare ${domain} again with 1 to ${MAX_EXAMPLE_URLS} --url page URLs.`;
|
|
268
|
+
step = `Run zenrows extract prepare ${domain} again with 1 to ${MAX_EXAMPLE_URLS} --url page URLs; we recommend ${RECOMMENDED_EXAMPLE_URLS} or more of the same page type (e.g. 3 product pages).`;
|
|
251
269
|
break;
|
|
252
270
|
case "unpreparable":
|
|
253
271
|
step = `Run zenrows extract prepare ${domain} again with different --url pages from the same site; the same URLs fail again.`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenrows/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "Open-source CLI, MCP, skills, templates, workflows, recipes, and evals layer for giving AI agents reliable access to protected web data through Zenrows cloud infrastructure.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"command": "zenrows extract",
|
|
18
18
|
"backend": "Extract — GET https://api.zenrows.com/v1/ (extract=auto, css_extractor, outputs, response_type; autoparse deprecated)",
|
|
19
19
|
"requiresAuth": true,
|
|
20
|
-
"notes": "Default is extract=auto, which works on any prepared domain with any key. A REQS007 (legacy AUTH010) is reported, never retried, with the next step for its reason: on a domain not prepared yet (EXTRACT_DOMAIN_NOT_PREPARED), prepare it with `zenrows extract prepare <domain> --url <page> [--wait]` (POST /v1/extract/prepared-domains: 1 to 5 example URLs, a few minutes, no credits) and check it with `zenrows extract prepare status <domain>`; on a page Extract did not recognise on a prepared domain (EXTRACT_PAGE_NOT_RECOGNISED), try a product, article or listing page, retry it once in a few minutes, or use --css, because preparing again does not change it. CSS / outputs / markdown work on any domain; autoparse is deprecated and runs only with --autoparse."
|
|
20
|
+
"notes": "Default is extract=auto, which works on any prepared domain with any key. A REQS007 (legacy AUTH010) is reported, never retried, with the next step for its reason: on a domain not prepared yet (EXTRACT_DOMAIN_NOT_PREPARED), prepare it with `zenrows extract prepare <domain> --url <page> [--wait]` (POST /v1/extract/prepared-domains: 1 to 5 example URLs; one works, we recommend 3 or more of the same page type because Extract compares pages of one type to check the fields it found and fill in fields one page is missing; a few minutes, no credits) and check it with `zenrows extract prepare status <domain>`; on a page Extract did not recognise on a prepared domain (EXTRACT_PAGE_NOT_RECOGNISED), try a product, article or listing page, retry it once in a few minutes, or use --css, because preparing again does not change it. CSS / outputs / markdown work on any domain; autoparse is deprecated and runs only with --autoparse."
|
|
21
21
|
},
|
|
22
22
|
"batch": {
|
|
23
23
|
"key": "batch",
|
package/skills/extract/SKILL.md
CHANGED
|
@@ -43,15 +43,21 @@ of three cases it is and prints the next step. It never retries with Autoparse.
|
|
|
43
43
|
Preparing a domain:
|
|
44
44
|
|
|
45
45
|
```
|
|
46
|
-
zenrows extract https://example.com/
|
|
46
|
+
zenrows extract https://www.example.com/products/a # 1. fails: EXTRACT_DOMAIN_NOT_PREPARED
|
|
47
47
|
zenrows extract prepare example.com \
|
|
48
|
-
--url https://example.com/
|
|
48
|
+
--url https://www.example.com/products/a \
|
|
49
|
+
--url https://www.example.com/products/b \
|
|
50
|
+
--url https://www.example.com/products/c --wait
|
|
49
51
|
# 2. prepare it and wait until ready (a few minutes)
|
|
50
|
-
zenrows extract https://example.com/
|
|
52
|
+
zenrows extract https://www.example.com/products/a # 3. extract again
|
|
51
53
|
```
|
|
52
54
|
|
|
53
|
-
- `--url`: 1 to 5 real pages you want to extract
|
|
54
|
-
|
|
55
|
+
- `--url`: 1 to 5 real pages you want to extract. One works; we recommend 3 or
|
|
56
|
+
more of the same page type (e.g. 3 product pages), because Extract compares
|
|
57
|
+
pages of one type to check the fields it found and fill in fields one page is
|
|
58
|
+
missing. Several page types can share the 5 (e.g. 3 product pages + 2
|
|
59
|
+
search-result pages). With fewer than 3 the command prints a tip on stderr;
|
|
60
|
+
it is never an error.
|
|
55
61
|
- Without `--wait` the command returns at once; then check about every 30
|
|
56
62
|
seconds with `zenrows extract prepare status example.com` until it says
|
|
57
63
|
`ready`. `--wait` polls at the same pace.
|
package/skills/zenrows/SKILL.md
CHANGED
|
@@ -90,7 +90,8 @@ Run `zenrows status` for the live capability matrix. As of this toolkit:
|
|
|
90
90
|
|
|
91
91
|
- Extract: `extract=auto` works on any prepared domain. On one not prepared yet
|
|
92
92
|
(`EXTRACT_DOMAIN_NOT_PREPARED`), run `zenrows extract prepare <domain> --url
|
|
93
|
-
<page> --wait`,
|
|
93
|
+
<page> --wait` (repeat `--url`, 1 to 5: one works; we recommend 3 or more of
|
|
94
|
+
the same page type), then extract again. `EXTRACT_PAGE_NOT_RECOGNISED` means the
|
|
94
95
|
domain is prepared but not this page: do not prepare again; see [[extract]].
|
|
95
96
|
- Batch: the reliable path at scale, at Fetch's prices (create, list, status, wait, results, content, pause, resume, rerun, delete). Estimate specs locally with no key.
|
|
96
97
|
- Crawl: collects the URLs behind one start page, optionally with each page's HTML.
|