n8n-nodes-crawlbrulee 0.2.0 → 0.3.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 +9 -6
- package/dist/nodes/Crawlbrulee/builders/map.js +2 -0
- package/dist/nodes/Crawlbrulee/builders/scrape.js +2 -0
- package/dist/nodes/Crawlbrulee/descriptions/map.js +1 -0
- package/dist/nodes/Crawlbrulee/descriptions/scrape.js +5 -4
- package/dist/nodes/Crawlbrulee/descriptions/shared.js +8 -1
- package/dist/nodes/Crawlbrulee/transport/errors.js +3 -0
- package/dist/nodes/Crawlbrulee/transport/request.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ pick a resource, then an operation:
|
|
|
47
47
|
| Scrape | Scrape URL | fetch one url, get back the content you asked for |
|
|
48
48
|
| Scrape | Scrape URL (Async) | start a background job, get back its job id |
|
|
49
49
|
| Scrape | Get Scrape Status | pending, running, done or failed |
|
|
50
|
-
| Scrape | Get Scrape Result | the content of a finished job |
|
|
50
|
+
| Scrape | Get Scrape Result | the content of a finished job, for 24 hours after it was submitted |
|
|
51
51
|
| Map | Map Website | a site's urls, from its sitemap and its homepage links |
|
|
52
52
|
| Account | Get Credit Usage | credits used and left this billing cycle, plus your concurrency limit |
|
|
53
53
|
| Account | Get Account Info | the organization and token behind the api key |
|
|
@@ -62,7 +62,7 @@ every field has a hint in n8n. three things the hints don't tell you:
|
|
|
62
62
|
|
|
63
63
|
### screenshots as files
|
|
64
64
|
|
|
65
|
-
turn on **Download Screenshot** — it's on **Scrape URL** and on **Get Scrape Result** — and the node attaches the image as binary data under `screenshot`, plus one key per tile (`screenshot_slice_0`, `screenshot_slice_1`, …) when you set Slice Height. the urls stay in the json too. a download can fail, since a signed url can expire; the item still comes through with its page content and the reason lands on the json as `screenshot_download_error`.
|
|
65
|
+
turn on **Download Screenshot** — it's on **Scrape URL** and on **Get Scrape Result** — and the node attaches the image as binary data under `screenshot`, plus one key per tile (`screenshot_slice_0`, `screenshot_slice_1`, …) when you set Slice Height. the urls stay in the json too, but they are signed links that expire 24 hours after the scrape (for **Scrape URL (Async)**, 24 hours after the job was submitted), so turn this on when you need the image later in the workflow. a download can fail, since a signed url can expire; the item still comes through with its page content and the reason lands on the json as `screenshot_download_error`.
|
|
66
66
|
|
|
67
67
|
### what comes back
|
|
68
68
|
|
|
@@ -76,6 +76,10 @@ set the node's "On Error" setting to continue and a failed item comes back as `{
|
|
|
76
76
|
|
|
77
77
|
a page the site really served is a normal item, whatever its status. a 404, 410 or 503 page comes back with its content, like any other page. it is not a node error, so "On Error" never sees it. when the status matters to your workflow, check it before you use the content — for example an **If** node on `{{ $json.page_status_code }}` is less than 400.
|
|
78
78
|
|
|
79
|
+
### zero data retention
|
|
80
|
+
|
|
81
|
+
turn on **Zero Data Retention** under **Options** of **Scrape URL**, **Scrape URL (Async)** or **Map Website** to keep the result out of the shared cache. anything stored to deliver it is kept for 24 hours, then deleted. it adds 1 credit and must be enabled for your organization. if it is not, the call fails with a clear message and costs no credits. see [zero data retention](https://crawlbrulee.com/docs/zero-data-retention).
|
|
82
|
+
|
|
79
83
|
### what a call cost
|
|
80
84
|
|
|
81
85
|
scrape, map and finished-job responses carry `response_meta.usage`, so the cost of each call is in front of you:
|
|
@@ -86,11 +90,10 @@ scrape, map and finished-job responses carry `response_meta.usage`, so the cost
|
|
|
86
90
|
| `engine_credit_cost` | the engine's base price: 1 for `http`, 3 for `browser`, 5 for `screenshot`, 0 for `cache` |
|
|
87
91
|
| `proxy_multiplier` | 1 for the Basic proxy tier, 5 for Advanced |
|
|
88
92
|
| `screenshot_slicing_credit_cost` | 1 when the screenshot was cut into slices on this call, else 0 (reusing slices from the cache costs 0). not on **Map Website** |
|
|
93
|
+
| `zero_data_retention_credit_cost` | 1 when **Zero Data Retention** added its credit to this call, else 0 |
|
|
89
94
|
| `engine`, `proxy` | the engine and the proxy tier that did the work |
|
|
90
95
|
|
|
91
|
-
`total_credit_cost` is always `engine_credit_cost × proxy_multiplier + screenshot_slicing_credit_cost
|
|
92
|
-
|
|
93
|
-
`credits` and `screenshot_slices` are still there, with the same values as `total_credit_cost` and `screenshot_slicing_credit_cost`. they are deprecated and will be removed in a future version, so read the new names in new workflows.
|
|
96
|
+
`total_credit_cost` is always `engine_credit_cost × proxy_multiplier + screenshot_slicing_credit_cost + zero_data_retention_credit_cost` (map has no slicing part). a page we don't bill, such as one the site answered with a 5xx status, has 0 in every `*_credit_cost` field. the [credits and pricing](https://crawlbrulee.com/docs/credits-and-pricing) page lists what is billed.
|
|
94
97
|
|
|
95
98
|
## the crawlbrulee Trigger
|
|
96
99
|
|
|
@@ -106,7 +109,7 @@ with the secret set, the trigger checks the HMAC-SHA256 signature on every deliv
|
|
|
106
109
|
|
|
107
110
|
## errors
|
|
108
111
|
|
|
109
|
-
the node turns api errors into messages you can act on: a rate limit says how long to wait, out of credits and concurrency limit are each named, an anti-bot block says so with no retry hint, a scrape error points you at the Advanced proxy tier and at Require JS, and a site we could not reach at all (for example it timed out, or its certificate is bad) tells you to check the url and try again later. the raw response stays on the error for the n8n error view, and every error name is in the [error reference](https://crawlbrulee.com/docs/errors).
|
|
112
|
+
the node turns api errors into messages you can act on: a rate limit says how long to wait, a Zero Data Retention request your organization cannot make yet says to turn the option off or ask us to enable it, out of credits and concurrency limit are each named, an anti-bot block says so with no retry hint, a scrape error points you at the Advanced proxy tier and at Require JS, and a site we could not reach at all (for example it timed out, or its certificate is bad) tells you to check the url and try again later. the raw response stays on the error for the n8n error view, and every error name is in the [error reference](https://crawlbrulee.com/docs/errors).
|
|
110
113
|
|
|
111
114
|
## development
|
|
112
115
|
|
|
@@ -8,6 +8,8 @@ function buildMapBody(_node, _itemIndex, p) {
|
|
|
8
8
|
const o = (_a = p.options) !== null && _a !== void 0 ? _a : {};
|
|
9
9
|
if (o.sitemapOnly === true)
|
|
10
10
|
body.sitemap_only = true;
|
|
11
|
+
if (o.zeroDataRetention === true)
|
|
12
|
+
body.zero_data_retention = true;
|
|
11
13
|
const types = {};
|
|
12
14
|
if (typeof o.internal === 'boolean')
|
|
13
15
|
types.internal = o.internal;
|
|
@@ -88,6 +88,8 @@ function buildScrapeBody(node, itemIndex, p) {
|
|
|
88
88
|
body.proxy = o.proxy;
|
|
89
89
|
if (o.requireJs === true)
|
|
90
90
|
body.require_js = true;
|
|
91
|
+
if (o.zeroDataRetention === true)
|
|
92
|
+
body.zero_data_retention = true;
|
|
91
93
|
const cleanup = {};
|
|
92
94
|
if (typeof o.removeAdsAndPopups === 'boolean')
|
|
93
95
|
cleanup.ads_and_popups = o.removeAdsAndPopups;
|
|
@@ -17,13 +17,13 @@ exports.scrapeOperations = {
|
|
|
17
17
|
name: 'Get Scrape Result',
|
|
18
18
|
value: 'getScrapeResult',
|
|
19
19
|
action: 'Get scrape result',
|
|
20
|
-
description: "Fetch the content of a finished async scrape. The site's own HTTP status is in page_status_code.",
|
|
20
|
+
description: "Fetch the content of a finished async scrape, up to 24 hours after it was submitted. The site's own HTTP status is in page_status_code.",
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
name: 'Get Scrape Status',
|
|
24
24
|
value: 'getScrapeStatus',
|
|
25
25
|
action: 'Get scrape status',
|
|
26
|
-
description: 'Check whether an async scrape is pending, running, done or failed',
|
|
26
|
+
description: 'Check whether an async scrape is pending, running, done or failed. Available for 24 hours after it was submitted.',
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
name: 'Scrape URL',
|
|
@@ -200,7 +200,7 @@ exports.scrapeFields = [
|
|
|
200
200
|
name: 'downloadScreenshot',
|
|
201
201
|
type: 'boolean',
|
|
202
202
|
default: false,
|
|
203
|
-
description: 'Whether to download the screenshot (and its slices) into binary data on the item',
|
|
203
|
+
description: 'Whether to download the screenshot (and its slices) into binary data on the item. Screenshot links are signed and expire 24 hours after the scrape.',
|
|
204
204
|
displayOptions: {
|
|
205
205
|
show: {
|
|
206
206
|
resource: ['scrape'],
|
|
@@ -244,6 +244,7 @@ exports.scrapeFields = [
|
|
|
244
244
|
default: false,
|
|
245
245
|
description: 'Whether to render JavaScript in a headless browser first. Adds latency and credits.',
|
|
246
246
|
},
|
|
247
|
+
shared_1.zeroDataRetentionOption,
|
|
247
248
|
],
|
|
248
249
|
},
|
|
249
250
|
{
|
|
@@ -268,7 +269,7 @@ exports.scrapeFields = [
|
|
|
268
269
|
name: 'downloadScreenshot',
|
|
269
270
|
type: 'boolean',
|
|
270
271
|
default: false,
|
|
271
|
-
description: 'Whether to download the screenshot (and its slices) into binary data when the result has one',
|
|
272
|
+
description: 'Whether to download the screenshot (and its slices) into binary data when the result has one. Screenshot links expire 24 hours after the job was submitted.',
|
|
272
273
|
displayOptions: { show: { resource: ['scrape'], operation: ['getScrapeResult'] } },
|
|
273
274
|
},
|
|
274
275
|
];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.localeOption = exports.countryOption = exports.cacheMaxAgeOption = exports.proxyOption = void 0;
|
|
3
|
+
exports.localeOption = exports.countryOption = exports.zeroDataRetentionOption = exports.cacheMaxAgeOption = exports.proxyOption = void 0;
|
|
4
4
|
exports.proxyOption = {
|
|
5
5
|
displayName: 'Proxy',
|
|
6
6
|
name: 'proxy',
|
|
@@ -30,6 +30,13 @@ const cacheMaxAgeOption = (defaultText) => ({
|
|
|
30
30
|
description: `Seconds, or an ISO-8601 cutoff. Cached results older than this are skipped. Default ${defaultText}.`,
|
|
31
31
|
});
|
|
32
32
|
exports.cacheMaxAgeOption = cacheMaxAgeOption;
|
|
33
|
+
exports.zeroDataRetentionOption = {
|
|
34
|
+
displayName: 'Zero Data Retention',
|
|
35
|
+
name: 'zeroDataRetention',
|
|
36
|
+
type: 'boolean',
|
|
37
|
+
default: false,
|
|
38
|
+
description: 'Whether to keep the result out of the shared cache. Anything stored to deliver it is kept for 24 hours, then deleted. Adds 1 credit. Must be enabled for your organization.',
|
|
39
|
+
};
|
|
33
40
|
exports.countryOption = {
|
|
34
41
|
displayName: 'Country',
|
|
35
42
|
name: 'country',
|
|
@@ -5,6 +5,7 @@ exports.toNodeApiError = toNodeApiError;
|
|
|
5
5
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
6
6
|
const KEY_REJECTED = 'crawlbrulee rejected the API key. Check the key on the credential.';
|
|
7
7
|
const UNREACHABLE = 'crawlbrulee could not reach the target site. Check the URL. If it is right, the site may be down or slow, so try again later. This costs no credits.';
|
|
8
|
+
const ZDR_NOT_ENABLED = 'Zero data retention is not enabled for your organization. Turn the Zero Data Retention option off, or contact sales@crawlbrulee.com to have it turned on. This costs no credits.';
|
|
8
9
|
const SCRAPE_HINT = 'The Advanced proxy tier has a higher success rate; enable Require JS for JavaScript-rendered content.';
|
|
9
10
|
function isApiErrorBody(body) {
|
|
10
11
|
return (typeof body === 'object' &&
|
|
@@ -42,6 +43,8 @@ function describeApiError(status, body) {
|
|
|
42
43
|
return { message: body.message, description };
|
|
43
44
|
case 'target_unreachable':
|
|
44
45
|
return { message: UNREACHABLE, description };
|
|
46
|
+
case 'zero_data_retention_not_enabled':
|
|
47
|
+
return { message: ZDR_NOT_ENABLED, description };
|
|
45
48
|
case 'scrape_error':
|
|
46
49
|
return { message: `${body.message.replace(/[.\s]*$/, '')}. ${SCRAPE_HINT}`, description };
|
|
47
50
|
default:
|
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.USER_AGENT = void 0;
|
|
4
4
|
exports.crawlbruleeRequest = crawlbruleeRequest;
|
|
5
5
|
const errors_1 = require("./errors");
|
|
6
|
-
exports.USER_AGENT = 'n8n-nodes-crawlbrulee/0.
|
|
6
|
+
exports.USER_AGENT = 'n8n-nodes-crawlbrulee/0.3.1';
|
|
7
7
|
function stripTrailingSlash(url) {
|
|
8
8
|
return url.replace(/\/+$/, '');
|
|
9
9
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "n8n-nodes-crawlbrulee",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "crawlbrulee for n8n — EU-native web scraping for AI agents & developers. scrape any url to markdown, html, links, images, metadata or a screenshot, map a site's urls, and react to finished background scrapes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://crawlbrulee.com",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
]
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
-
"@crawlbrulee/sdk": "^1.1
|
|
60
|
+
"@crawlbrulee/sdk": "^1.2.1",
|
|
61
61
|
"@n8n/node-cli": "0.48.6",
|
|
62
62
|
"@types/node": "^22.0.0",
|
|
63
63
|
"eslint": "9.32.0",
|