@crawlee/basic 3.17.1-beta.54 → 3.17.1-beta.55
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/index.mjs +3 -0
- package/internals/basic-crawler.d.ts +18 -0
- package/internals/basic-crawler.js +43 -0
- package/package.json +5 -5
package/index.mjs
CHANGED
|
@@ -48,6 +48,7 @@ export const RequestQueue = mod.RequestQueue;
|
|
|
48
48
|
export const RequestQueueV1 = mod.RequestQueueV1;
|
|
49
49
|
export const RequestQueueV2 = mod.RequestQueueV2;
|
|
50
50
|
export const RequestState = mod.RequestState;
|
|
51
|
+
export const RequestValidationError = mod.RequestValidationError;
|
|
51
52
|
export const RetryRequestError = mod.RetryRequestError;
|
|
52
53
|
export const Router = mod.Router;
|
|
53
54
|
export const STATE_PERSISTENCE_KEY = mod.STATE_PERSISTENCE_KEY;
|
|
@@ -76,6 +77,7 @@ export const createDeserialize = mod.createDeserialize;
|
|
|
76
77
|
export const createEventLoopLoadSignal = mod.createEventLoopLoadSignal;
|
|
77
78
|
export const createRequestOptions = mod.createRequestOptions;
|
|
78
79
|
export const createRequests = mod.createRequests;
|
|
80
|
+
export const defaultRoute = mod.defaultRoute;
|
|
79
81
|
export const deserializeArray = mod.deserializeArray;
|
|
80
82
|
export const enqueueLinks = mod.enqueueLinks;
|
|
81
83
|
export const evaluateLoadSignalSample = mod.evaluateLoadSignalSample;
|
|
@@ -96,5 +98,6 @@ export const tryAbsoluteURL = mod.tryAbsoluteURL;
|
|
|
96
98
|
export const updateEnqueueLinksPatternCache = mod.updateEnqueueLinksPatternCache;
|
|
97
99
|
export const useState = mod.useState;
|
|
98
100
|
export const validateGlobPattern = mod.validateGlobPattern;
|
|
101
|
+
export const validateUserData = mod.validateUserData;
|
|
99
102
|
export const validators = mod.validators;
|
|
100
103
|
export const withCheckedStorageAccess = mod.withCheckedStorageAccess;
|
|
@@ -545,6 +545,24 @@ export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawlin
|
|
|
545
545
|
*/
|
|
546
546
|
stop(reason?: string): void;
|
|
547
547
|
getRequestQueue(): Promise<RequestProvider>;
|
|
548
|
+
/**
|
|
549
|
+
* The request handler exactly as the user supplied it — a {@link Router} when one is in use, whether it
|
|
550
|
+
* was passed as `requestHandler` or auto-wired from {@link BasicCrawler.router|`crawler.router`}.
|
|
551
|
+
*
|
|
552
|
+
* Router-aware features read per-label metadata off this handler (currently the `userData` schema map), so
|
|
553
|
+
* it must resolve to the *unwrapped* handler. Subclasses that hand a wrapper to `BasicCrawler` instead of
|
|
554
|
+
* the user's own function — {@link BrowserCrawler} and its descendants do — have to override this, or
|
|
555
|
+
* those features silently no-op against the wrapper.
|
|
556
|
+
*/
|
|
557
|
+
protected get userRequestHandler(): RequestHandler<Context>;
|
|
558
|
+
/**
|
|
559
|
+
* Validates a request source's `userData` against the {@link RouteSchemas|Standard Schema} registered
|
|
560
|
+
* for its label on the crawler's schema-router (if any), throwing a {@link RequestValidationError} on
|
|
561
|
+
* mismatch. A no-op when the user's request handler is not a schema-router, or no schema is registered for
|
|
562
|
+
* the request's label. Applied by the crawler on the add paths it owns — `crawler.addRequests`,
|
|
563
|
+
* `crawler.run`, `context.addRequests` and `context.enqueueLinks`.
|
|
564
|
+
*/
|
|
565
|
+
protected validateRequestUserData(source: Source | string): Promise<void>;
|
|
548
566
|
useState<State extends Dictionary = Dictionary>(defaultValue?: State): Promise<State>;
|
|
549
567
|
protected get pendingRequestCountApproximation(): number;
|
|
550
568
|
protected calculateEnqueuedRequestLimit(explicitLimit?: number): number | undefined;
|
|
@@ -729,6 +729,44 @@ class BasicCrawler {
|
|
|
729
729
|
}
|
|
730
730
|
return this.requestQueue;
|
|
731
731
|
}
|
|
732
|
+
/**
|
|
733
|
+
* The request handler exactly as the user supplied it — a {@link Router} when one is in use, whether it
|
|
734
|
+
* was passed as `requestHandler` or auto-wired from {@link BasicCrawler.router|`crawler.router`}.
|
|
735
|
+
*
|
|
736
|
+
* Router-aware features read per-label metadata off this handler (currently the `userData` schema map), so
|
|
737
|
+
* it must resolve to the *unwrapped* handler. Subclasses that hand a wrapper to `BasicCrawler` instead of
|
|
738
|
+
* the user's own function — {@link BrowserCrawler} and its descendants do — have to override this, or
|
|
739
|
+
* those features silently no-op against the wrapper.
|
|
740
|
+
*/
|
|
741
|
+
get userRequestHandler() {
|
|
742
|
+
return this.requestHandler;
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Validates a request source's `userData` against the {@link RouteSchemas|Standard Schema} registered
|
|
746
|
+
* for its label on the crawler's schema-router (if any), throwing a {@link RequestValidationError} on
|
|
747
|
+
* mismatch. A no-op when the user's request handler is not a schema-router, or no schema is registered for
|
|
748
|
+
* the request's label. Applied by the crawler on the add paths it owns — `crawler.addRequests`,
|
|
749
|
+
* `crawler.run`, `context.addRequests` and `context.enqueueLinks`.
|
|
750
|
+
*/
|
|
751
|
+
async validateRequestUserData(source) {
|
|
752
|
+
if (typeof source === 'string') {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
const getSchema = this.userRequestHandler.getSchema;
|
|
756
|
+
if (typeof getSchema !== 'function') {
|
|
757
|
+
return;
|
|
758
|
+
}
|
|
759
|
+
// Resolve the label via its public accessors only — the top-level `label` of a `RequestOptions` or the
|
|
760
|
+
// `Request.label` getter — rather than reaching into `userData`, where the request happens to store it.
|
|
761
|
+
const target = source;
|
|
762
|
+
const schema = getSchema(target.label);
|
|
763
|
+
if (!schema) {
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
// Store the parsed value rather than the raw input, so the queue holds the same coerced `userData` the
|
|
767
|
+
// handler will see. Assigning through a `Request` instance's setter keeps its internal `__crawlee` meta.
|
|
768
|
+
target.userData = await (0, core_1.validateUserData)(target.label, schema, target.userData ?? {});
|
|
769
|
+
}
|
|
732
770
|
async useState(defaultValue = {}) {
|
|
733
771
|
const kvs = await core_1.KeyValueStore.open(null, { config: this.config });
|
|
734
772
|
return kvs.getAutoSavedValue(BasicCrawler.CRAWLEE_STATE_KEY, defaultValue);
|
|
@@ -777,6 +815,7 @@ class BasicCrawler {
|
|
|
777
815
|
const skippedBecauseOfMaxCrawlDepth = new Set();
|
|
778
816
|
const isAllowedBasedOnRobotsTxtFile = this.isAllowedBasedOnRobotsTxtFile.bind(this);
|
|
779
817
|
const maxCrawlDepth = this.maxCrawlDepth;
|
|
818
|
+
const validateRequestUserData = this.validateRequestUserData.bind(this);
|
|
780
819
|
(0, ow_1.default)(requests, ow_1.default.object
|
|
781
820
|
.is((value) => (0, utils_1.isIterable)(value) || (0, utils_1.isAsyncIterable)(value))
|
|
782
821
|
.message((value) => `Expected an iterable or async iterable, got ${(0, utils_1.getObjectType)(value)}`));
|
|
@@ -788,6 +827,7 @@ class BasicCrawler {
|
|
|
788
827
|
continue;
|
|
789
828
|
}
|
|
790
829
|
if (await isAllowedBasedOnRobotsTxtFile(url)) {
|
|
830
|
+
await validateRequestUserData(request);
|
|
791
831
|
yield request;
|
|
792
832
|
}
|
|
793
833
|
else {
|
|
@@ -1177,6 +1217,9 @@ class BasicCrawler {
|
|
|
1177
1217
|
}
|
|
1178
1218
|
await this.handleSkippedRequest(skippedOptions);
|
|
1179
1219
|
};
|
|
1220
|
+
// `enqueueLinks` applies `options.label`/`options.userData` to every newly enqueued request, so a single
|
|
1221
|
+
// validation against the label's schema covers them all (a no-op unless the router declares a schema).
|
|
1222
|
+
await this.validateRequestUserData({ label: options.label, userData: options.userData });
|
|
1180
1223
|
return (0, core_1.enqueueLinks)({
|
|
1181
1224
|
requestQueue,
|
|
1182
1225
|
robotsTxtFile: await this.getRobotsTxtFileForUrl(request.url),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crawlee/basic",
|
|
3
|
-
"version": "3.17.1-beta.
|
|
3
|
+
"version": "3.17.1-beta.55",
|
|
4
4
|
"description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=16.0.0"
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"@apify/log": "^2.4.0",
|
|
50
50
|
"@apify/timeout": "^0.3.0",
|
|
51
51
|
"@apify/utilities": "^2.7.10",
|
|
52
|
-
"@crawlee/core": "3.17.1-beta.
|
|
53
|
-
"@crawlee/types": "3.17.1-beta.
|
|
54
|
-
"@crawlee/utils": "3.17.1-beta.
|
|
52
|
+
"@crawlee/core": "3.17.1-beta.55",
|
|
53
|
+
"@crawlee/types": "3.17.1-beta.55",
|
|
54
|
+
"@crawlee/utils": "3.17.1-beta.55",
|
|
55
55
|
"csv-stringify": "^6.2.0",
|
|
56
56
|
"fs-extra": "^11.0.0",
|
|
57
57
|
"got-scraping": "^4.2.1",
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "93d29e305f01ca6ca9bb79264a5ca553b19766ef"
|
|
71
71
|
}
|