@crawlee/core 4.0.0-beta.1 → 4.0.0-beta.100
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 +17 -13
- package/autoscaling/autoscaled_pool.d.ts +69 -156
- package/autoscaling/autoscaled_pool.js +97 -252
- package/autoscaling/client_load_signal.d.ts +59 -0
- package/autoscaling/client_load_signal.js +73 -0
- package/autoscaling/concurrency_system.d.ts +283 -0
- package/autoscaling/concurrency_system.js +350 -0
- package/autoscaling/cpu_load_signal.d.ts +44 -0
- package/autoscaling/cpu_load_signal.js +46 -0
- package/autoscaling/event_loop_load_signal.d.ts +54 -0
- package/autoscaling/event_loop_load_signal.js +60 -0
- package/autoscaling/index.d.ts +6 -1
- package/autoscaling/index.js +6 -1
- package/autoscaling/load_signal.d.ts +99 -0
- package/autoscaling/load_signal.js +103 -0
- package/autoscaling/memory_load_signal.d.ts +56 -0
- package/autoscaling/memory_load_signal.js +106 -0
- package/autoscaling/snapshotter.d.ts +61 -163
- package/autoscaling/snapshotter.js +45 -270
- package/autoscaling/system_status.d.ts +63 -83
- package/autoscaling/system_status.js +90 -120
- package/autoscaling/weighted_avg.d.ts +5 -0
- package/autoscaling/weighted_avg.js +14 -0
- package/byte_utils.d.ts +17 -0
- package/byte_utils.js +42 -0
- package/configuration.d.ts +96 -230
- package/configuration.js +170 -226
- package/cookie_utils.d.ts +4 -3
- package/cookie_utils.js +22 -13
- package/crawlers/context_pipeline.d.ts +70 -0
- package/crawlers/context_pipeline.js +122 -0
- package/crawlers/crawler_commons.d.ts +96 -40
- package/crawlers/crawler_commons.js +15 -24
- package/crawlers/error_snapshotter.d.ts +3 -3
- package/crawlers/error_snapshotter.js +2 -3
- package/crawlers/error_tracker.d.ts +2 -2
- package/crawlers/error_tracker.js +0 -1
- package/crawlers/index.d.ts +1 -3
- package/crawlers/index.js +1 -3
- package/crawlers/internals/types.d.ts +7 -0
- package/crawlers/internals/types.js +1 -0
- package/crawlers/statistics.d.ts +28 -23
- package/crawlers/statistics.js +38 -34
- package/debug.d.ts +36 -0
- package/debug.js +70 -0
- package/enqueue_links/enqueue_links.d.ts +59 -68
- package/enqueue_links/enqueue_links.js +57 -62
- package/enqueue_links/index.d.ts +0 -1
- package/enqueue_links/index.js +0 -1
- package/enqueue_links/shared.d.ts +39 -26
- package/enqueue_links/shared.js +89 -67
- package/errors.d.ts +53 -4
- package/errors.js +70 -5
- package/events/event_manager.d.ts +34 -8
- package/events/event_manager.js +8 -10
- package/events/index.d.ts +0 -1
- package/events/index.js +0 -1
- package/events/local_event_manager.d.ts +15 -5
- package/events/local_event_manager.js +37 -40
- package/index.d.ts +6 -4
- package/index.js +5 -3
- package/iterables.d.ts +79 -0
- package/iterables.js +134 -0
- package/log.d.ts +82 -3
- package/log.js +102 -1
- package/memory-storage/consts.d.ts +4 -0
- package/memory-storage/consts.js +4 -0
- package/memory-storage/index.d.ts +1 -0
- package/memory-storage/index.js +1 -0
- package/memory-storage/memory-storage.d.ts +46 -0
- package/memory-storage/memory-storage.js +136 -0
- package/memory-storage/resource-clients/common/base-client.d.ts +4 -0
- package/memory-storage/resource-clients/common/base-client.js +6 -0
- package/memory-storage/resource-clients/dataset.d.ts +40 -0
- package/memory-storage/resource-clients/dataset.js +113 -0
- package/memory-storage/resource-clients/key-value-store.d.ts +63 -0
- package/memory-storage/resource-clients/key-value-store.js +203 -0
- package/memory-storage/resource-clients/request-queue.d.ts +96 -0
- package/memory-storage/resource-clients/request-queue.js +421 -0
- package/memory-storage/utils.d.ts +16 -0
- package/memory-storage/utils.js +41 -0
- package/owned_or_injected.d.ts +60 -0
- package/owned_or_injected.js +98 -0
- package/package.json +13 -12
- package/proxy_configuration.d.ts +29 -152
- package/proxy_configuration.js +21 -173
- package/recoverable_state.d.ts +120 -0
- package/recoverable_state.js +143 -0
- package/request.d.ts +85 -17
- package/request.js +107 -36
- package/router.d.ts +194 -19
- package/router.js +177 -32
- package/serialization.d.ts +0 -1
- package/serialization.js +1 -2
- package/service_locator.d.ts +156 -0
- package/service_locator.js +244 -0
- package/session_pool/consts.d.ts +1 -2
- package/session_pool/consts.js +1 -2
- package/session_pool/errors.d.ts +0 -1
- package/session_pool/errors.js +0 -1
- package/session_pool/fingerprint.d.ts +9 -0
- package/session_pool/fingerprint.js +30 -0
- package/session_pool/index.d.ts +0 -2
- package/session_pool/index.js +0 -2
- package/session_pool/session.d.ts +37 -75
- package/session_pool/session.js +49 -102
- package/session_pool/session_pool.d.ts +85 -90
- package/session_pool/session_pool.js +131 -120
- package/storages/access_checking.d.ts +1 -2
- package/storages/access_checking.js +5 -2
- package/storages/dataset.d.ts +103 -54
- package/storages/dataset.js +174 -132
- package/storages/index.d.ts +8 -7
- package/storages/index.js +6 -7
- package/storages/key_value_store.d.ts +167 -39
- package/storages/key_value_store.js +274 -127
- package/storages/key_value_store_codec.d.ts +32 -0
- package/storages/key_value_store_codec.js +113 -0
- package/storages/request_dedup_cache.d.ts +23 -0
- package/storages/request_dedup_cache.js +48 -0
- package/storages/request_list.d.ts +54 -98
- package/storages/request_list.js +99 -75
- package/storages/request_loader.d.ts +96 -0
- package/storages/request_loader.js +1 -0
- package/storages/request_manager.d.ts +33 -0
- package/storages/request_manager.js +1 -0
- package/storages/request_manager_tandem.d.ts +106 -0
- package/storages/request_manager_tandem.js +197 -0
- package/storages/request_queue.d.ts +287 -47
- package/storages/request_queue.js +620 -215
- package/storages/{sitemap_request_list.d.ts → sitemap_request_loader.d.ts} +38 -46
- package/storages/{sitemap_request_list.js → sitemap_request_loader.js} +58 -65
- package/storages/storage_instance_manager.d.ts +88 -0
- package/storages/storage_instance_manager.js +256 -0
- package/storages/storage_stats.d.ts +48 -0
- package/storages/storage_stats.js +29 -0
- package/storages/utils.d.ts +54 -9
- package/storages/utils.js +64 -13
- package/system-info/cpu-info.d.ts +67 -0
- package/system-info/cpu-info.js +216 -0
- package/system-info/memory-info.d.ts +31 -0
- package/system-info/memory-info.js +115 -0
- package/system-info/ps-tree.d.ts +17 -0
- package/system-info/ps-tree.js +144 -0
- package/system-info/runtime.d.ts +14 -0
- package/system-info/runtime.js +80 -0
- package/typedefs.d.ts +0 -6
- package/typedefs.js +0 -1
- package/validators.d.ts +8 -1
- package/validators.js +10 -3
- package/autoscaling/autoscaled_pool.d.ts.map +0 -1
- package/autoscaling/autoscaled_pool.js.map +0 -1
- package/autoscaling/index.d.ts.map +0 -1
- package/autoscaling/index.js.map +0 -1
- package/autoscaling/snapshotter.d.ts.map +0 -1
- package/autoscaling/snapshotter.js.map +0 -1
- package/autoscaling/system_status.d.ts.map +0 -1
- package/autoscaling/system_status.js.map +0 -1
- package/configuration.d.ts.map +0 -1
- package/configuration.js.map +0 -1
- package/cookie_utils.d.ts.map +0 -1
- package/cookie_utils.js.map +0 -1
- package/crawlers/crawler_commons.d.ts.map +0 -1
- package/crawlers/crawler_commons.js.map +0 -1
- package/crawlers/crawler_extension.d.ts +0 -12
- package/crawlers/crawler_extension.d.ts.map +0 -1
- package/crawlers/crawler_extension.js +0 -14
- package/crawlers/crawler_extension.js.map +0 -1
- package/crawlers/crawler_utils.d.ts +0 -10
- package/crawlers/crawler_utils.d.ts.map +0 -1
- package/crawlers/crawler_utils.js +0 -12
- package/crawlers/crawler_utils.js.map +0 -1
- package/crawlers/error_snapshotter.d.ts.map +0 -1
- package/crawlers/error_snapshotter.js.map +0 -1
- package/crawlers/error_tracker.d.ts.map +0 -1
- package/crawlers/error_tracker.js.map +0 -1
- package/crawlers/index.d.ts.map +0 -1
- package/crawlers/index.js.map +0 -1
- package/crawlers/statistics.d.ts.map +0 -1
- package/crawlers/statistics.js.map +0 -1
- package/enqueue_links/enqueue_links.d.ts.map +0 -1
- package/enqueue_links/enqueue_links.js.map +0 -1
- package/enqueue_links/index.d.ts.map +0 -1
- package/enqueue_links/index.js.map +0 -1
- package/enqueue_links/shared.d.ts.map +0 -1
- package/enqueue_links/shared.js.map +0 -1
- package/errors.d.ts.map +0 -1
- package/errors.js.map +0 -1
- package/events/event_manager.d.ts.map +0 -1
- package/events/event_manager.js.map +0 -1
- package/events/index.d.ts.map +0 -1
- package/events/index.js.map +0 -1
- package/events/local_event_manager.d.ts.map +0 -1
- package/events/local_event_manager.js.map +0 -1
- package/http_clients/base-http-client.d.ts +0 -134
- package/http_clients/base-http-client.d.ts.map +0 -1
- package/http_clients/base-http-client.js +0 -33
- package/http_clients/base-http-client.js.map +0 -1
- package/http_clients/form-data-like.d.ts +0 -67
- package/http_clients/form-data-like.d.ts.map +0 -1
- package/http_clients/form-data-like.js +0 -5
- package/http_clients/form-data-like.js.map +0 -1
- package/http_clients/got-scraping-http-client.d.ts +0 -15
- package/http_clients/got-scraping-http-client.d.ts.map +0 -1
- package/http_clients/got-scraping-http-client.js +0 -69
- package/http_clients/got-scraping-http-client.js.map +0 -1
- package/http_clients/index.d.ts +0 -3
- package/http_clients/index.d.ts.map +0 -1
- package/http_clients/index.js +0 -3
- package/http_clients/index.js.map +0 -1
- package/index.d.ts.map +0 -1
- package/index.js.map +0 -1
- package/log.d.ts.map +0 -1
- package/log.js.map +0 -1
- package/proxy_configuration.d.ts.map +0 -1
- package/proxy_configuration.js.map +0 -1
- package/request.d.ts.map +0 -1
- package/request.js.map +0 -1
- package/router.d.ts.map +0 -1
- package/router.js.map +0 -1
- package/serialization.d.ts.map +0 -1
- package/serialization.js.map +0 -1
- package/session_pool/consts.d.ts.map +0 -1
- package/session_pool/consts.js.map +0 -1
- package/session_pool/errors.d.ts.map +0 -1
- package/session_pool/errors.js.map +0 -1
- package/session_pool/events.d.ts +0 -3
- package/session_pool/events.d.ts.map +0 -1
- package/session_pool/events.js +0 -3
- package/session_pool/events.js.map +0 -1
- package/session_pool/index.d.ts.map +0 -1
- package/session_pool/index.js.map +0 -1
- package/session_pool/session.d.ts.map +0 -1
- package/session_pool/session.js.map +0 -1
- package/session_pool/session_pool.d.ts.map +0 -1
- package/session_pool/session_pool.js.map +0 -1
- package/storages/access_checking.d.ts.map +0 -1
- package/storages/access_checking.js.map +0 -1
- package/storages/dataset.d.ts.map +0 -1
- package/storages/dataset.js.map +0 -1
- package/storages/index.d.ts.map +0 -1
- package/storages/index.js.map +0 -1
- package/storages/key_value_store.d.ts.map +0 -1
- package/storages/key_value_store.js.map +0 -1
- package/storages/request_list.d.ts.map +0 -1
- package/storages/request_list.js.map +0 -1
- package/storages/request_provider.d.ts +0 -307
- package/storages/request_provider.d.ts.map +0 -1
- package/storages/request_provider.js +0 -555
- package/storages/request_provider.js.map +0 -1
- package/storages/request_queue.d.ts.map +0 -1
- package/storages/request_queue.js.map +0 -1
- package/storages/request_queue_v2.d.ts +0 -87
- package/storages/request_queue_v2.d.ts.map +0 -1
- package/storages/request_queue_v2.js +0 -438
- package/storages/request_queue_v2.js.map +0 -1
- package/storages/sitemap_request_list.d.ts.map +0 -1
- package/storages/sitemap_request_list.js.map +0 -1
- package/storages/storage_manager.d.ts +0 -58
- package/storages/storage_manager.d.ts.map +0 -1
- package/storages/storage_manager.js +0 -105
- package/storages/storage_manager.js.map +0 -1
- package/storages/utils.d.ts.map +0 -1
- package/storages/utils.js.map +0 -1
- package/tsconfig.build.tsbuildinfo +0 -1
- package/typedefs.d.ts.map +0 -1
- package/typedefs.js.map +0 -1
- package/validators.d.ts.map +0 -1
- package/validators.js.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import ow from 'ow';
|
|
2
2
|
import { getDomain } from 'tldts';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import { Request } from '../request.js';
|
|
4
|
+
import { applyRequestTransform, constructUrlPatternObjects, createRequestOptions, filterRequestOptionsByPatterns, } from './shared.js';
|
|
5
5
|
/**
|
|
6
6
|
* The different enqueueing strategies available.
|
|
7
7
|
*
|
|
@@ -58,17 +58,16 @@ export var EnqueueStrategy;
|
|
|
58
58
|
* This function enqueues the urls provided to the {@link RequestQueue} provided. If you want to automatically find and enqueue links,
|
|
59
59
|
* you should use the context-aware `enqueueLinks` function provided on the crawler contexts.
|
|
60
60
|
*
|
|
61
|
-
* Optionally, the function allows you to filter the target links' URLs using an array of
|
|
62
|
-
* and override settings of the enqueued {@link Request} objects.
|
|
61
|
+
* Optionally, the function allows you to filter the target links' URLs using an array of glob or regexp patterns.
|
|
63
62
|
*
|
|
64
63
|
* **Example usage**
|
|
65
64
|
*
|
|
66
65
|
* ```javascript
|
|
67
66
|
* await enqueueLinks({
|
|
68
67
|
* urls: aListOfFoundUrls,
|
|
69
|
-
*
|
|
68
|
+
* requestManager,
|
|
70
69
|
* selector: 'a.product-detail',
|
|
71
|
-
*
|
|
70
|
+
* include: [
|
|
72
71
|
* 'https://www.example.com/handbags/*',
|
|
73
72
|
* 'https://www.example.com/purses/*'
|
|
74
73
|
* ],
|
|
@@ -85,52 +84,33 @@ export async function enqueueLinks(options) {
|
|
|
85
84
|
'Check out our guide on how to use enqueueLinks() here: https://crawlee.dev/js/docs/examples/crawl-relative-links',
|
|
86
85
|
].join('\n'));
|
|
87
86
|
}
|
|
87
|
+
const urlPatternValidator = ow.any(ow.string, ow.regExp, ow.object.hasKeys('glob'), ow.object.hasKeys('regexp'));
|
|
88
88
|
ow(options, ow.object.exactShape({
|
|
89
89
|
urls: ow.array.ofType(ow.string),
|
|
90
|
-
|
|
90
|
+
requestManager: ow.object.hasKeys('addRequestsBatched'),
|
|
91
91
|
robotsTxtFile: ow.optional.object.hasKeys('isAllowed'),
|
|
92
|
+
respectRobotsTxtFile: ow.optional.any(ow.boolean, ow.object.exactShape({ userAgent: ow.optional.string })),
|
|
92
93
|
onSkippedRequest: ow.optional.function,
|
|
93
94
|
forefront: ow.optional.boolean,
|
|
94
95
|
skipNavigation: ow.optional.boolean,
|
|
96
|
+
sessionId: ow.optional.string,
|
|
95
97
|
limit: ow.optional.number,
|
|
96
98
|
selector: ow.optional.string,
|
|
97
99
|
baseUrl: ow.optional.string,
|
|
98
100
|
userData: ow.optional.object,
|
|
99
101
|
label: ow.optional.string,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
exclude: ow.optional.array.ofType(ow.any(ow.string, ow.regExp, ow.object.hasKeys('glob'), ow.object.hasKeys('regexp'))),
|
|
103
|
-
regexps: ow.optional.array.ofType(ow.any(ow.regExp, ow.object.hasKeys('regexp'))),
|
|
102
|
+
include: ow.optional.array.minLength(1).ofType(urlPatternValidator),
|
|
103
|
+
exclude: ow.optional.array.ofType(urlPatternValidator),
|
|
104
104
|
transformRequestFunction: ow.optional.function,
|
|
105
105
|
strategy: ow.optional.string.oneOf(Object.values(EnqueueStrategy)),
|
|
106
106
|
waitForAllRequestsToBeAdded: ow.optional.boolean,
|
|
107
107
|
}));
|
|
108
|
-
const {
|
|
109
|
-
const urlExcludePatternObjects = [];
|
|
110
|
-
const urlPatternObjects = [];
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
urlExcludePatternObjects.push(...constructGlobObjectsFromGlobs([excl]));
|
|
115
|
-
}
|
|
116
|
-
else if (excl instanceof RegExp || 'regexp' in excl) {
|
|
117
|
-
urlExcludePatternObjects.push(...constructRegExpObjectsFromRegExps([excl]));
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
if (pseudoUrls?.length) {
|
|
122
|
-
log.deprecated('`pseudoUrls` option is deprecated, use `globs` or `regexps` instead');
|
|
123
|
-
urlPatternObjects.push(...constructRegExpObjectsFromPseudoUrls(pseudoUrls));
|
|
124
|
-
}
|
|
125
|
-
if (globs?.length) {
|
|
126
|
-
urlPatternObjects.push(...constructGlobObjectsFromGlobs(globs));
|
|
127
|
-
}
|
|
128
|
-
if (regexps?.length) {
|
|
129
|
-
urlPatternObjects.push(...constructRegExpObjectsFromRegExps(regexps));
|
|
130
|
-
}
|
|
131
|
-
if (!urlPatternObjects.length) {
|
|
132
|
-
options.strategy ??= EnqueueStrategy.SameHostname;
|
|
133
|
-
}
|
|
108
|
+
const { requestManager, limit, urls, include, exclude, transformRequestFunction, forefront, waitForAllRequestsToBeAdded, robotsTxtFile, onSkippedRequest, } = options;
|
|
109
|
+
const urlExcludePatternObjects = exclude?.length ? constructUrlPatternObjects(exclude) : [];
|
|
110
|
+
const urlPatternObjects = include?.length ? constructUrlPatternObjects(include) : [];
|
|
111
|
+
// The strategy always applies, even when `include` patterns are provided - the two are AND-ed together
|
|
112
|
+
// (a URL must match an `include` pattern *and* satisfy the strategy). This mirrors crawlee-python.
|
|
113
|
+
options.strategy ??= EnqueueStrategy.SameHostname;
|
|
134
114
|
const enqueueStrategyPatterns = [];
|
|
135
115
|
if (options.baseUrl) {
|
|
136
116
|
const url = new URL(options.baseUrl);
|
|
@@ -167,44 +147,60 @@ export async function enqueueLinks(options) {
|
|
|
167
147
|
break;
|
|
168
148
|
}
|
|
169
149
|
}
|
|
150
|
+
async function reportSkippedRequests(skippedRequests, reason) {
|
|
151
|
+
if (onSkippedRequest && skippedRequests.length > 0) {
|
|
152
|
+
await Promise.all(skippedRequests.map((request) => {
|
|
153
|
+
return onSkippedRequest({
|
|
154
|
+
url: request.url,
|
|
155
|
+
reason: request.skippedReason ?? reason,
|
|
156
|
+
});
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
170
160
|
let requestOptions = createRequestOptions(urls, options);
|
|
171
|
-
if (robotsTxtFile) {
|
|
161
|
+
if (robotsTxtFile && options.respectRobotsTxtFile !== false) {
|
|
162
|
+
const robotsUserAgent = typeof options.respectRobotsTxtFile === 'object' ? (options.respectRobotsTxtFile.userAgent ?? '*') : '*';
|
|
172
163
|
const skippedRequests = [];
|
|
173
164
|
requestOptions = requestOptions.filter((request) => {
|
|
174
|
-
if (robotsTxtFile.isAllowed(request.url)) {
|
|
165
|
+
if (robotsTxtFile.isAllowed(request.url, robotsUserAgent)) {
|
|
175
166
|
return true;
|
|
176
167
|
}
|
|
177
168
|
skippedRequests.push(request);
|
|
178
169
|
return false;
|
|
179
170
|
});
|
|
180
|
-
|
|
181
|
-
await Promise.all(skippedRequests.map((request) => {
|
|
182
|
-
return onSkippedRequest({ url: request.url, reason: 'robotsTxt' });
|
|
183
|
-
}));
|
|
184
|
-
}
|
|
171
|
+
await reportSkippedRequests(skippedRequests, 'robotsTxt');
|
|
185
172
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
function createFilteredRequests() {
|
|
192
|
-
// No user provided patterns means we can skip an extra filtering step
|
|
173
|
+
async function createFilteredRequests() {
|
|
174
|
+
const skippedRequests = [];
|
|
175
|
+
// Step 1: Filter request options by exclude patterns, user include patterns, and strategy patterns.
|
|
176
|
+
let filteredOptions;
|
|
193
177
|
if (urlPatternObjects.length === 0) {
|
|
194
|
-
|
|
178
|
+
filteredOptions = filterRequestOptionsByPatterns(requestOptions, enqueueStrategyPatterns.length > 0 ? enqueueStrategyPatterns : undefined, urlExcludePatternObjects, options.strategy, (url) => skippedRequests.push(url));
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
// Filter by user patterns first (with exclude)
|
|
182
|
+
const afterUserPatterns = filterRequestOptionsByPatterns(requestOptions, urlPatternObjects, urlExcludePatternObjects, options.strategy, (url) => skippedRequests.push(url));
|
|
183
|
+
// ...then filter by the enqueue links strategy (making this an AND check)
|
|
184
|
+
filteredOptions = filterRequestOptionsByPatterns(afterUserPatterns, enqueueStrategyPatterns.length > 0 ? enqueueStrategyPatterns : undefined, [], options.strategy, (url) => skippedRequests.push(url));
|
|
195
185
|
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
186
|
+
await reportSkippedRequests(skippedRequests.map((url) => ({ url })), 'filters');
|
|
187
|
+
// Step 2: Apply transformRequestFunction on request options - it has the highest priority
|
|
188
|
+
if (transformRequestFunction) {
|
|
189
|
+
const skippedByTransform = [];
|
|
190
|
+
filteredOptions = applyRequestTransform(filteredOptions, transformRequestFunction, (r) => skippedByTransform.push(r));
|
|
191
|
+
await reportSkippedRequests(skippedByTransform, 'transform');
|
|
192
|
+
}
|
|
193
|
+
// Step 3: Create Request instances from the final request options
|
|
194
|
+
return filteredOptions.map((opts) => new Request(opts));
|
|
200
195
|
}
|
|
201
|
-
|
|
202
|
-
if (limit)
|
|
203
|
-
requests = requests.slice(0, limit);
|
|
204
|
-
const { addedRequests } = await requestQueue.addRequestsBatched(requests, {
|
|
196
|
+
const { addedRequests, requestsOverLimit } = await requestManager.addRequestsBatched(await createFilteredRequests(), {
|
|
205
197
|
forefront,
|
|
206
198
|
waitForAllRequestsToBeAdded,
|
|
199
|
+
maxNewRequests: limit,
|
|
207
200
|
});
|
|
201
|
+
if (requestsOverLimit?.length !== undefined && requestsOverLimit.length > 0) {
|
|
202
|
+
await reportSkippedRequests(requestsOverLimit.map((r) => ({ url: typeof r === 'string' ? r : r.url })), 'enqueueLimit');
|
|
203
|
+
}
|
|
208
204
|
return { processedRequests: addedRequests, unprocessedRequests: [] };
|
|
209
205
|
}
|
|
210
206
|
/**
|
|
@@ -242,9 +238,8 @@ export function resolveBaseUrlForEnqueueLinksFiltering({ enqueueStrategy, finalR
|
|
|
242
238
|
return originalUrlOrigin;
|
|
243
239
|
}
|
|
244
240
|
/**
|
|
245
|
-
* Internal function that changes the enqueue
|
|
241
|
+
* Internal function that changes the enqueue glob patterns to match both http and https
|
|
246
242
|
*/
|
|
247
243
|
function ignoreHttpSchema(pattern) {
|
|
248
244
|
return pattern.replace(/^(https?):\/\//, 'http{s,}://');
|
|
249
245
|
}
|
|
250
|
-
//# sourceMappingURL=enqueue_links.js.map
|
package/enqueue_links/index.d.ts
CHANGED
package/enqueue_links/index.js
CHANGED
|
@@ -1,33 +1,30 @@
|
|
|
1
|
+
import type { Awaitable } from '@crawlee/types';
|
|
1
2
|
import type { RequestOptions } from '../request.js';
|
|
2
|
-
import { Request } from '../request.js';
|
|
3
3
|
import type { EnqueueLinksOptions } from './enqueue_links.js';
|
|
4
4
|
export { tryAbsoluteURL } from '@crawlee/utils';
|
|
5
|
-
export
|
|
5
|
+
export interface UrlPatternObject {
|
|
6
6
|
glob?: string;
|
|
7
7
|
regexp?: RegExp;
|
|
8
|
-
}
|
|
9
|
-
export
|
|
10
|
-
purl: string;
|
|
11
|
-
} & Pick<RequestOptions, 'method' | 'payload' | 'label' | 'userData' | 'headers'>;
|
|
12
|
-
export type PseudoUrlInput = string | PseudoUrlObject;
|
|
13
|
-
export type GlobObject = {
|
|
8
|
+
}
|
|
9
|
+
export interface GlobObject {
|
|
14
10
|
glob: string;
|
|
15
|
-
}
|
|
11
|
+
}
|
|
16
12
|
export type GlobInput = string | GlobObject;
|
|
17
|
-
export
|
|
13
|
+
export interface RegExpObject {
|
|
18
14
|
regexp: RegExp;
|
|
19
|
-
}
|
|
15
|
+
}
|
|
20
16
|
export type RegExpInput = RegExp | RegExpObject;
|
|
17
|
+
/** Unified URL pattern input — accepts glob strings, glob objects, RegExp instances, or regexp objects. */
|
|
18
|
+
export type UrlPatternInput = GlobInput | RegExpInput;
|
|
19
|
+
export type SkippedRequestReason = 'robotsTxt' | 'limit' | 'enqueueLimit' | 'filters' | 'transform' | 'redirect' | 'depth';
|
|
20
|
+
export type SkippedRequestCallback = (args: {
|
|
21
|
+
url: string;
|
|
22
|
+
reason: SkippedRequestReason;
|
|
23
|
+
}) => Awaitable<void>;
|
|
21
24
|
/**
|
|
22
25
|
* @ignore
|
|
23
26
|
*/
|
|
24
|
-
export declare function updateEnqueueLinksPatternCache(item: GlobInput | RegExpInput
|
|
25
|
-
/**
|
|
26
|
-
* Helper factory used in the `enqueueLinks()` and enqueueLinksByClickingElements() function
|
|
27
|
-
* to construct RegExps from PseudoUrl strings.
|
|
28
|
-
* @ignore
|
|
29
|
-
*/
|
|
30
|
-
export declare function constructRegExpObjectsFromPseudoUrls(pseudoUrls: readonly PseudoUrlInput[]): RegExpObject[];
|
|
27
|
+
export declare function updateEnqueueLinksPatternCache(item: GlobInput | RegExpInput, pattern: RegExpObject | GlobObject): void;
|
|
31
28
|
/**
|
|
32
29
|
* Helper factory used in the `enqueueLinks()` and enqueueLinksByClickingElements() function
|
|
33
30
|
* to construct Glob objects from Glob pattern strings.
|
|
@@ -45,23 +42,39 @@ export declare function validateGlobPattern(glob: string): string;
|
|
|
45
42
|
*/
|
|
46
43
|
export declare function constructRegExpObjectsFromRegExps(regexps: readonly RegExpInput[]): RegExpObject[];
|
|
47
44
|
/**
|
|
45
|
+
* Helper factory used in the `enqueueLinks()` function to construct UrlPatternObjects
|
|
46
|
+
* from a mixed array of glob strings, glob objects, RegExp instances, and regexp objects.
|
|
48
47
|
* @ignore
|
|
49
48
|
*/
|
|
50
|
-
export declare function
|
|
51
|
-
export declare function filterRequestsByPatterns(requests: Request[], patterns?: UrlPatternObject[]): Request[];
|
|
49
|
+
export declare function constructUrlPatternObjects(patterns: readonly UrlPatternInput[]): UrlPatternObject[];
|
|
52
50
|
/**
|
|
51
|
+
* Filters request options by URL patterns.
|
|
52
|
+
*
|
|
53
|
+
* When `includePatterns` is empty/undefined, all options pass through (only exclude filtering applies).
|
|
53
54
|
* @ignore
|
|
54
55
|
*/
|
|
55
|
-
export declare function
|
|
56
|
+
export declare function filterRequestOptionsByPatterns(requestOptions: RequestOptions[], includePatterns: UrlPatternObject[] | undefined, excludePatterns?: UrlPatternObject[], strategy?: EnqueueLinksOptions['strategy'], onSkippedUrl?: (url: string) => void): RequestOptions[];
|
|
56
57
|
/**
|
|
57
|
-
*
|
|
58
|
-
|
|
58
|
+
* @ignore
|
|
59
|
+
*/
|
|
60
|
+
export declare function createRequestOptions(sources: readonly (string | Record<string, unknown>)[], options?: Pick<EnqueueLinksOptions, 'label' | 'userData' | 'baseUrl' | 'skipNavigation' | 'sessionId' | 'strategy'>): RequestOptions[];
|
|
61
|
+
/**
|
|
62
|
+
* Takes a {@link RequestOptions} object and changes its attributes in a desired way. This user-function is used
|
|
63
|
+
* by {@link enqueueLinks} to modify request options before they are converted to {@link Request} instances.
|
|
59
64
|
*/
|
|
60
65
|
export interface RequestTransform {
|
|
61
66
|
/**
|
|
62
67
|
* @param original Request options to be modified.
|
|
63
|
-
* @returns The modified request options to enqueue
|
|
68
|
+
* @returns The modified request options to enqueue, `'unchanged'` to keep the original options as-is,
|
|
69
|
+
* or a falsy value / `'skip'` to exclude the request from the queue.
|
|
64
70
|
*/
|
|
65
|
-
(original: RequestOptions): RequestOptions | false | undefined | null;
|
|
71
|
+
(original: RequestOptions): RequestOptions | false | undefined | null | 'skip' | 'unchanged';
|
|
66
72
|
}
|
|
67
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Applies a {@link RequestTransform} function to a list of request options.
|
|
75
|
+
* Options for which the transform returns a falsy value are removed from the list.
|
|
76
|
+
* @param onSkipped Called with the original request options when the transform returns a falsy value (i.e. the request is skipped).
|
|
77
|
+
* @ignore
|
|
78
|
+
* @internal
|
|
79
|
+
*/
|
|
80
|
+
export declare function applyRequestTransform(requestOptions: RequestOptions[], transformFn: RequestTransform, onSkipped?: (requestOptions: RequestOptions) => void): RequestOptions[];
|
package/enqueue_links/shared.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { URL } from 'node:url';
|
|
2
|
-
import {
|
|
3
|
-
import { purlToRegExp } from '@apify/pseudo_url';
|
|
4
|
-
import { Request } from '../request.js';
|
|
2
|
+
import { Minimatch } from 'minimatch';
|
|
5
3
|
export { tryAbsoluteURL } from '@crawlee/utils';
|
|
6
4
|
const MAX_ENQUEUE_LINKS_CACHE_SIZE = 1000;
|
|
7
5
|
/**
|
|
8
|
-
* To
|
|
9
|
-
*
|
|
10
|
-
* by the `enqueueLinks()` function.
|
|
6
|
+
* To keep high performance when the same patterns are passed on every `enqueueLinks()` call,
|
|
7
|
+
* each glob/regexp is only compiled once and then kept in a cache.
|
|
11
8
|
* @ignore
|
|
12
9
|
*/
|
|
13
10
|
const enqueueLinksPatternCache = new Map();
|
|
@@ -21,28 +18,6 @@ export function updateEnqueueLinksPatternCache(item, pattern) {
|
|
|
21
18
|
enqueueLinksPatternCache.delete(key);
|
|
22
19
|
}
|
|
23
20
|
}
|
|
24
|
-
/**
|
|
25
|
-
* Helper factory used in the `enqueueLinks()` and enqueueLinksByClickingElements() function
|
|
26
|
-
* to construct RegExps from PseudoUrl strings.
|
|
27
|
-
* @ignore
|
|
28
|
-
*/
|
|
29
|
-
export function constructRegExpObjectsFromPseudoUrls(pseudoUrls) {
|
|
30
|
-
return pseudoUrls.map((item) => {
|
|
31
|
-
// Get pseudoUrl object from cache.
|
|
32
|
-
let regexpObject = enqueueLinksPatternCache.get(item);
|
|
33
|
-
if (regexpObject)
|
|
34
|
-
return regexpObject;
|
|
35
|
-
if (typeof item === 'string') {
|
|
36
|
-
regexpObject = { regexp: purlToRegExp(item) };
|
|
37
|
-
}
|
|
38
|
-
else {
|
|
39
|
-
const { purl, ...requestOptions } = item;
|
|
40
|
-
regexpObject = { regexp: purlToRegExp(purl), ...requestOptions };
|
|
41
|
-
}
|
|
42
|
-
updateEnqueueLinksPatternCache(item, regexpObject);
|
|
43
|
-
return regexpObject;
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
21
|
/**
|
|
47
22
|
* Helper factory used in the `enqueueLinks()` and enqueueLinksByClickingElements() function
|
|
48
23
|
* to construct Glob objects from Glob pattern strings.
|
|
@@ -72,8 +47,7 @@ export function constructGlobObjectsFromGlobs(globs) {
|
|
|
72
47
|
globObject = { glob: validateGlobPattern(item) };
|
|
73
48
|
}
|
|
74
49
|
else {
|
|
75
|
-
|
|
76
|
-
globObject = { glob: validateGlobPattern(glob), ...requestOptions };
|
|
50
|
+
globObject = { glob: validateGlobPattern(item.glob) };
|
|
77
51
|
}
|
|
78
52
|
updateEnqueueLinksPatternCache(item, globObject);
|
|
79
53
|
return globObject;
|
|
@@ -103,58 +77,60 @@ export function constructRegExpObjectsFromRegExps(regexps) {
|
|
|
103
77
|
regexpObject = { regexp: item };
|
|
104
78
|
}
|
|
105
79
|
else {
|
|
106
|
-
regexpObject = item;
|
|
80
|
+
regexpObject = { regexp: item.regexp };
|
|
107
81
|
}
|
|
108
82
|
updateEnqueueLinksPatternCache(item, regexpObject);
|
|
109
83
|
return regexpObject;
|
|
110
84
|
});
|
|
111
85
|
}
|
|
112
86
|
/**
|
|
87
|
+
* Helper factory used in the `enqueueLinks()` function to construct UrlPatternObjects
|
|
88
|
+
* from a mixed array of glob strings, glob objects, RegExp instances, and regexp objects.
|
|
89
|
+
* @ignore
|
|
90
|
+
*/
|
|
91
|
+
export function constructUrlPatternObjects(patterns) {
|
|
92
|
+
const result = [];
|
|
93
|
+
for (const item of patterns) {
|
|
94
|
+
if (typeof item === 'string' || 'glob' in item) {
|
|
95
|
+
result.push(...constructGlobObjectsFromGlobs([item]));
|
|
96
|
+
}
|
|
97
|
+
else if (item instanceof RegExp || 'regexp' in item) {
|
|
98
|
+
result.push(...constructRegExpObjectsFromRegExps([item]));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Filters request options by URL patterns.
|
|
105
|
+
*
|
|
106
|
+
* When `includePatterns` is empty/undefined, all options pass through (only exclude filtering applies).
|
|
113
107
|
* @ignore
|
|
114
108
|
*/
|
|
115
|
-
export function
|
|
109
|
+
export function filterRequestOptionsByPatterns(requestOptions, includePatterns, excludePatterns = [], strategy, onSkippedUrl) {
|
|
110
|
+
const excludeMatchers = excludePatterns.map(createPatternObjectMatcher);
|
|
111
|
+
const includeMatchers = includePatterns?.length ? includePatterns.map(createPatternObjectMatcher) : undefined;
|
|
116
112
|
return requestOptions
|
|
117
|
-
.map((opts) => ({ url: typeof opts === 'string' ? opts : opts.url, opts }))
|
|
118
113
|
.filter(({ url }) => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
114
|
+
const matchesExclude = excludeMatchers.some(({ match }) => match(url));
|
|
115
|
+
if (matchesExclude) {
|
|
116
|
+
onSkippedUrl?.(url);
|
|
117
|
+
}
|
|
118
|
+
return !matchesExclude;
|
|
123
119
|
})
|
|
124
|
-
.map((
|
|
125
|
-
if (!
|
|
126
|
-
return
|
|
127
|
-
}
|
|
128
|
-
for (const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const request = typeof opts === 'string'
|
|
132
|
-
? { url: opts, ...requestRegExpOptions, enqueueStrategy: strategy }
|
|
133
|
-
: { ...opts, ...requestRegExpOptions, enqueueStrategy: strategy };
|
|
134
|
-
return new Request(request);
|
|
120
|
+
.map((opts) => {
|
|
121
|
+
if (!includeMatchers) {
|
|
122
|
+
return { ...opts, enqueueStrategy: strategy };
|
|
123
|
+
}
|
|
124
|
+
for (const { match } of includeMatchers) {
|
|
125
|
+
if (match(opts.url)) {
|
|
126
|
+
return { ...opts, enqueueStrategy: strategy };
|
|
135
127
|
}
|
|
136
128
|
}
|
|
137
129
|
// didn't match any positive pattern
|
|
130
|
+
onSkippedUrl?.(opts.url);
|
|
138
131
|
return null;
|
|
139
132
|
})
|
|
140
|
-
.filter((
|
|
141
|
-
}
|
|
142
|
-
export function filterRequestsByPatterns(requests, patterns) {
|
|
143
|
-
if (!patterns?.length) {
|
|
144
|
-
return requests;
|
|
145
|
-
}
|
|
146
|
-
const filtered = [];
|
|
147
|
-
for (const request of requests) {
|
|
148
|
-
for (const urlPatternObject of patterns) {
|
|
149
|
-
const { regexp, glob } = urlPatternObject;
|
|
150
|
-
if ((regexp && request.url.match(regexp)) || (glob && minimatch(request.url, glob, { nocase: true }))) {
|
|
151
|
-
filtered.push(request);
|
|
152
|
-
// Break the pattern loop, as we already matched this request once
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return filtered;
|
|
133
|
+
.filter((opts) => opts !== null);
|
|
158
134
|
}
|
|
159
135
|
/**
|
|
160
136
|
* @ignore
|
|
@@ -184,7 +160,53 @@ export function createRequestOptions(sources, options = {}) {
|
|
|
184
160
|
if (options.skipNavigation) {
|
|
185
161
|
requestOptions.skipNavigation = true;
|
|
186
162
|
}
|
|
163
|
+
if (options.sessionId) {
|
|
164
|
+
requestOptions.sessionId = options.sessionId;
|
|
165
|
+
}
|
|
187
166
|
return requestOptions;
|
|
188
167
|
});
|
|
189
168
|
}
|
|
190
|
-
|
|
169
|
+
/**
|
|
170
|
+
* @ignore
|
|
171
|
+
*/
|
|
172
|
+
function createPatternObjectMatcher(urlPatternObject) {
|
|
173
|
+
const { regexp, glob } = urlPatternObject;
|
|
174
|
+
let match;
|
|
175
|
+
if (regexp) {
|
|
176
|
+
match = (url) => regexp.test(url);
|
|
177
|
+
}
|
|
178
|
+
else if (glob) {
|
|
179
|
+
const m = new Minimatch(glob, { nocase: true });
|
|
180
|
+
match = (url) => m.match(url);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
match = () => false;
|
|
184
|
+
}
|
|
185
|
+
return { match };
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Applies a {@link RequestTransform} function to a list of request options.
|
|
189
|
+
* Options for which the transform returns a falsy value are removed from the list.
|
|
190
|
+
* @param onSkipped Called with the original request options when the transform returns a falsy value (i.e. the request is skipped).
|
|
191
|
+
* @ignore
|
|
192
|
+
* @internal
|
|
193
|
+
*/
|
|
194
|
+
export function applyRequestTransform(requestOptions, transformFn, onSkipped) {
|
|
195
|
+
return requestOptions
|
|
196
|
+
.map((opts) => {
|
|
197
|
+
const transformed = transformFn(opts);
|
|
198
|
+
if (transformed === 'skip') {
|
|
199
|
+
onSkipped?.(opts);
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
if (transformed === 'unchanged') {
|
|
203
|
+
return opts;
|
|
204
|
+
}
|
|
205
|
+
if (!transformed) {
|
|
206
|
+
onSkipped?.(opts);
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
return transformed;
|
|
210
|
+
})
|
|
211
|
+
.filter((r) => r !== null);
|
|
212
|
+
}
|
package/errors.d.ts
CHANGED
|
@@ -14,6 +14,26 @@ export declare class CriticalError extends NonRetryableError {
|
|
|
14
14
|
*/
|
|
15
15
|
export declare class MissingRouteError extends CriticalError {
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Thrown when a request's `userData` does not match the {@link RouteSchemas|Standard Schema} registered for its label.
|
|
19
|
+
*
|
|
20
|
+
* As the `userData` does not change between attempts, this error is non-retryable.
|
|
21
|
+
*/
|
|
22
|
+
export declare class RequestValidationError extends NonRetryableError {
|
|
23
|
+
readonly label: string | symbol;
|
|
24
|
+
readonly issues: readonly {
|
|
25
|
+
readonly message: string;
|
|
26
|
+
readonly path?: readonly (PropertyKey | {
|
|
27
|
+
key: PropertyKey;
|
|
28
|
+
})[];
|
|
29
|
+
}[];
|
|
30
|
+
constructor(label: string | symbol, issues: readonly {
|
|
31
|
+
readonly message: string;
|
|
32
|
+
readonly path?: readonly (PropertyKey | {
|
|
33
|
+
key: PropertyKey;
|
|
34
|
+
})[];
|
|
35
|
+
}[]);
|
|
36
|
+
}
|
|
17
37
|
/**
|
|
18
38
|
* Errors of `RetryRequestError` type will always be retried by the crawler.
|
|
19
39
|
*
|
|
@@ -23,11 +43,40 @@ export declare class RetryRequestError extends Error {
|
|
|
23
43
|
constructor(message?: string);
|
|
24
44
|
}
|
|
25
45
|
/**
|
|
26
|
-
* Errors of `SessionError` type
|
|
46
|
+
* Errors of `SessionError` type retire the session associated with the request and trigger a regular retry.
|
|
27
47
|
*
|
|
28
|
-
*
|
|
48
|
+
* The retry counts towards the `maxRequestRetries` limit, just like any other error.
|
|
29
49
|
*/
|
|
30
|
-
export declare class SessionError extends
|
|
50
|
+
export declare class SessionError extends Error {
|
|
51
|
+
constructor(message?: string);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Thrown when a requested session is not found in the referenced SessionPool.
|
|
55
|
+
*/
|
|
56
|
+
export declare class MissingSessionError extends Error {
|
|
57
|
+
constructor(sessionId?: string);
|
|
58
|
+
}
|
|
59
|
+
export declare class ContextPipelineInterruptedError extends Error {
|
|
31
60
|
constructor(message?: string);
|
|
32
61
|
}
|
|
33
|
-
|
|
62
|
+
export declare class ContextPipelineInitializationError extends Error {
|
|
63
|
+
constructor(error: unknown, options?: ErrorOptions);
|
|
64
|
+
}
|
|
65
|
+
export declare class ContextPipelineCleanupError extends CriticalError {
|
|
66
|
+
constructor(error: unknown, options?: ErrorOptions);
|
|
67
|
+
}
|
|
68
|
+
export declare class RequestHandlerError extends Error {
|
|
69
|
+
constructor(error: unknown, options?: ErrorOptions);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Thrown when attempting to set a different service instance after one has already been retrieved.
|
|
73
|
+
*/
|
|
74
|
+
export declare class ServiceConflictError extends Error {
|
|
75
|
+
constructor(serviceName: string, newValue: unknown, existingValue: unknown);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Thrown by crawlers when `skipNavigation` is used on a request.
|
|
79
|
+
* Subclasses can catch this error to skip their own navigation-dependent logic.
|
|
80
|
+
*/
|
|
81
|
+
export declare class NavigationSkippedError extends NonRetryableError {
|
|
82
|
+
}
|