@crawlee/basic 4.0.0-beta.99 → 4.0.0-rc.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 +1 -1
- package/index.d.ts +11 -1
- package/index.js +11 -0
- package/internals/autoscaling/autoscaled_pool.d.ts +178 -0
- package/internals/autoscaling/autoscaled_pool.js +387 -0
- package/internals/autoscaling/concurrency_system.d.ts +235 -0
- package/internals/autoscaling/concurrency_system.js +357 -0
- package/internals/autoscaling/cpu_load_signal.d.ts +43 -0
- package/internals/autoscaling/cpu_load_signal.js +46 -0
- package/internals/autoscaling/event_loop_load_signal.d.ts +51 -0
- package/internals/autoscaling/event_loop_load_signal.js +60 -0
- package/internals/autoscaling/index.d.ts +9 -0
- package/internals/autoscaling/index.js +9 -0
- package/internals/autoscaling/load_signal.d.ts +98 -0
- package/internals/autoscaling/load_signal.js +103 -0
- package/internals/autoscaling/memory_load_signal.d.ts +45 -0
- package/internals/autoscaling/memory_load_signal.js +104 -0
- package/internals/autoscaling/snapshotter.d.ts +84 -0
- package/internals/autoscaling/snapshotter.js +67 -0
- package/internals/autoscaling/storage_backend_load_signal.d.ts +56 -0
- package/internals/autoscaling/storage_backend_load_signal.js +73 -0
- package/internals/autoscaling/system_status.d.ts +112 -0
- package/internals/autoscaling/system_status.js +139 -0
- package/internals/autoscaling/weighted_avg.d.ts +5 -0
- package/internals/autoscaling/weighted_avg.js +14 -0
- package/internals/basic-crawler.d.ts +185 -389
- package/internals/basic-crawler.js +982 -684
- package/internals/cookie_utils.d.ts +40 -0
- package/internals/cookie_utils.js +122 -0
- package/internals/crawler-run.d.ts +76 -0
- package/internals/crawler-run.js +142 -0
- package/internals/crawlers/context_pipeline.d.ts +75 -0
- package/internals/crawlers/context_pipeline.js +109 -0
- package/internals/crawlers/crawler_commons.d.ts +216 -0
- package/internals/crawlers/crawler_commons.js +1 -0
- package/internals/crawlers/error_snapshotter.d.ts +29 -0
- package/internals/crawlers/error_snapshotter.js +116 -0
- package/internals/crawlers/error_tracker.d.ts +51 -0
- package/internals/crawlers/error_tracker.js +316 -0
- package/internals/crawlers/index.d.ts +4 -0
- package/internals/crawlers/index.js +3 -0
- package/internals/crawlers/internals/types.d.ts +7 -0
- package/internals/crawlers/internals/types.js +1 -0
- package/internals/crawlers/statistics.d.ts +316 -0
- package/internals/crawlers/statistics.js +525 -0
- package/internals/crawling_request.d.ts +86 -0
- package/internals/crawling_request.js +127 -0
- package/internals/enqueue_links/enqueue_links.d.ts +152 -0
- package/internals/enqueue_links/enqueue_links.js +76 -0
- package/internals/enqueue_links/index.d.ts +3 -0
- package/internals/enqueue_links/index.js +3 -0
- package/internals/enqueue_links/shared.d.ts +106 -0
- package/internals/enqueue_links/shared.js +258 -0
- package/internals/errors.d.ts +68 -0
- package/internals/errors.js +83 -0
- package/internals/http.d.ts +9 -0
- package/internals/http.js +28 -0
- package/internals/request-timeout.d.ts +6 -0
- package/internals/request-timeout.js +27 -2
- package/internals/router.d.ts +299 -0
- package/internals/router.js +312 -0
- package/internals/send-request.d.ts +2 -1
- package/internals/send-request.js +1 -0
- package/internals/session_pool/consts.d.ts +1 -0
- package/internals/session_pool/consts.js +1 -0
- package/internals/session_pool/errors.d.ts +7 -0
- package/internals/session_pool/errors.js +11 -0
- package/internals/session_pool/fingerprint.d.ts +9 -0
- package/internals/session_pool/fingerprint.js +30 -0
- package/internals/session_pool/index.d.ts +4 -0
- package/internals/session_pool/index.js +4 -0
- package/internals/session_pool/session.d.ts +151 -0
- package/internals/session_pool/session.js +225 -0
- package/internals/session_pool/session_pool.d.ts +193 -0
- package/internals/session_pool/session_pool.js +453 -0
- package/internals/sitemap_request_loader.d.ts +158 -0
- package/internals/sitemap_request_loader.js +432 -0
- package/internals/throttling_request_manager.d.ts +229 -0
- package/internals/throttling_request_manager.js +843 -0
- package/package.json +17 -14
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import util from 'node:util';
|
|
2
|
+
import { Request } from '@crawlee/core';
|
|
3
|
+
export var RequestState;
|
|
4
|
+
(function (RequestState) {
|
|
5
|
+
RequestState[RequestState["UNPROCESSED"] = 0] = "UNPROCESSED";
|
|
6
|
+
RequestState[RequestState["BEFORE_NAV"] = 1] = "BEFORE_NAV";
|
|
7
|
+
RequestState[RequestState["AFTER_NAV"] = 2] = "AFTER_NAV";
|
|
8
|
+
RequestState[RequestState["REQUEST_HANDLER"] = 3] = "REQUEST_HANDLER";
|
|
9
|
+
RequestState[RequestState["DONE"] = 4] = "DONE";
|
|
10
|
+
RequestState[RequestState["ERROR_HANDLER"] = 5] = "ERROR_HANDLER";
|
|
11
|
+
RequestState[RequestState["ERROR"] = 6] = "ERROR";
|
|
12
|
+
RequestState[RequestState["SKIPPED"] = 7] = "SKIPPED";
|
|
13
|
+
})(RequestState || (RequestState = {}));
|
|
14
|
+
/**
|
|
15
|
+
* A {@link Request} as seen by a crawler: the same stored record, with the crawler's own per-request state
|
|
16
|
+
* (`userData.__crawlee`) exposed as properties. This is what `request` is in every request handler.
|
|
17
|
+
*
|
|
18
|
+
* Requests fetched from a request manager are plain {@link Request}s; {@link BasicCrawler} rebuilds them
|
|
19
|
+
* as `CrawlingRequest`s before handing them to the pipeline.
|
|
20
|
+
* @category Sources
|
|
21
|
+
*/
|
|
22
|
+
export class CrawlingRequest extends Request {
|
|
23
|
+
static fromSchema(schema) {
|
|
24
|
+
return super.fromSchema(schema);
|
|
25
|
+
}
|
|
26
|
+
get #crawleeData() {
|
|
27
|
+
return (this.userData.__crawlee ??= {});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Tells the crawler processing this request to skip the navigation and process the request directly.
|
|
31
|
+
*
|
|
32
|
+
* When this is set to `true`, the crawling context will not contain the results of the navigation
|
|
33
|
+
* (e.g. `response`, `body`, `contentType`, `$` or `request.loadedUrl`).
|
|
34
|
+
* Accessing these properties will throw a {@link NavigationSkippedError} at runtime.
|
|
35
|
+
*/
|
|
36
|
+
get skipNavigation() {
|
|
37
|
+
return this.#crawleeData.skipNavigation ?? false;
|
|
38
|
+
}
|
|
39
|
+
set skipNavigation(value) {
|
|
40
|
+
this.#crawleeData.skipNavigation = value;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Depth of the request in the current crawl tree.
|
|
44
|
+
* Note that this is dependent on the crawler setup and might produce unexpected results when used with multiple crawlers.
|
|
45
|
+
*/
|
|
46
|
+
get crawlDepth() {
|
|
47
|
+
return this.#crawleeData.crawlDepth ?? 0;
|
|
48
|
+
}
|
|
49
|
+
set crawlDepth(value) {
|
|
50
|
+
this.#crawleeData.crawlDepth = value;
|
|
51
|
+
}
|
|
52
|
+
/** ID of a session to use for this request. When set, the crawler will fetch this session from the session pool instead of creating a new one. */
|
|
53
|
+
get sessionId() {
|
|
54
|
+
return this.#crawleeData.sessionId;
|
|
55
|
+
}
|
|
56
|
+
set sessionId(value) {
|
|
57
|
+
this.#crawleeData.sessionId = value;
|
|
58
|
+
}
|
|
59
|
+
/** Maximum number of retries for this request. Allows to override the global `maxRequestRetries` option of `BasicCrawler`. */
|
|
60
|
+
get maxRetries() {
|
|
61
|
+
return this.#crawleeData.maxRetries;
|
|
62
|
+
}
|
|
63
|
+
set maxRetries(value) {
|
|
64
|
+
this.#crawleeData.maxRetries = value;
|
|
65
|
+
}
|
|
66
|
+
/** Describes the request's current lifecycle state. */
|
|
67
|
+
get state() {
|
|
68
|
+
return this.#crawleeData.state ?? RequestState.UNPROCESSED;
|
|
69
|
+
}
|
|
70
|
+
set state(value) {
|
|
71
|
+
this.#crawleeData.state = value;
|
|
72
|
+
}
|
|
73
|
+
/** The strategy the request was enqueued under, if it came from `enqueueLinks`. @internal */
|
|
74
|
+
get enqueueStrategy() {
|
|
75
|
+
return this.#crawleeData.enqueueStrategy;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Stores information about an error that occurred during processing of this request.
|
|
79
|
+
*
|
|
80
|
+
* You should always use Error instances when throwing errors in JavaScript.
|
|
81
|
+
*
|
|
82
|
+
* Nevertheless, to improve the debugging experience when using third party libraries
|
|
83
|
+
* that may not always throw an Error instance, the function performs a type
|
|
84
|
+
* inspection of the passed argument and attempts to extract as much information
|
|
85
|
+
* as possible, since just throwing a bad type error makes any debugging rather difficult.
|
|
86
|
+
*
|
|
87
|
+
* @param errorOrMessage Error object or error message to be stored in the request.
|
|
88
|
+
* @param [options]
|
|
89
|
+
*/
|
|
90
|
+
pushErrorMessage(errorOrMessage, options = {}) {
|
|
91
|
+
const { omitStack } = options;
|
|
92
|
+
let message;
|
|
93
|
+
const type = typeof errorOrMessage;
|
|
94
|
+
if (type === 'object') {
|
|
95
|
+
if (!errorOrMessage) {
|
|
96
|
+
message = 'null';
|
|
97
|
+
}
|
|
98
|
+
else if (errorOrMessage instanceof Error) {
|
|
99
|
+
message = omitStack
|
|
100
|
+
? errorOrMessage.message
|
|
101
|
+
: // .stack includes the message
|
|
102
|
+
errorOrMessage.stack;
|
|
103
|
+
}
|
|
104
|
+
else if (Reflect.has(Object(errorOrMessage), 'message')) {
|
|
105
|
+
message = Reflect.get(Object(errorOrMessage), 'message');
|
|
106
|
+
}
|
|
107
|
+
else if (errorOrMessage.toString() !== '[object Object]') {
|
|
108
|
+
message = errorOrMessage.toString();
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
try {
|
|
112
|
+
message = util.inspect(errorOrMessage);
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
message = 'Unable to extract any message from the received object.';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (type === 'undefined') {
|
|
120
|
+
message = 'undefined';
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
message = errorOrMessage.toString();
|
|
124
|
+
}
|
|
125
|
+
this.errorMessages.push(message);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import type { Dictionary } from '@crawlee/types';
|
|
2
|
+
import type { EnqueueStrategyOption, RequestQueueOperationOptions } from '@crawlee/core';
|
|
3
|
+
import type { RequestTransform, SkippedRequestCallback, UrlPatternInput, UrlPatternObject } from './shared.js';
|
|
4
|
+
/**
|
|
5
|
+
* Options shared by the `extractLinks()` context helper across crawler types.
|
|
6
|
+
*/
|
|
7
|
+
export interface ExtractLinksOptions {
|
|
8
|
+
/** A CSS selector matching links to be extracted. */
|
|
9
|
+
selector?: string;
|
|
10
|
+
/**
|
|
11
|
+
* A base URL that will be used to resolve relative URLs when using Cheerio. Ignored when using Puppeteer,
|
|
12
|
+
* since the relative URL resolution is done inside the browser automatically.
|
|
13
|
+
*/
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Options accepted by the `enqueueUrls()` context helper exposed by `BasicCrawler`.
|
|
18
|
+
*/
|
|
19
|
+
export interface EnqueueUrlsOptions extends RequestQueueOperationOptions {
|
|
20
|
+
/** Limit the amount of actually enqueued URLs to this number. Useful for testing across the entire crawling scope. */
|
|
21
|
+
limit?: number;
|
|
22
|
+
/** Sets {@link Request.userData} for newly enqueued requests. */
|
|
23
|
+
userData?: Dictionary;
|
|
24
|
+
/**
|
|
25
|
+
* Sets {@link Request.label} for newly enqueued requests.
|
|
26
|
+
*
|
|
27
|
+
* Can be overwritten by `transformRequestFunction`.
|
|
28
|
+
*/
|
|
29
|
+
label?: string;
|
|
30
|
+
/** Sets {@link Request.sessionId} for newly enqueued requests. */
|
|
31
|
+
sessionId?: string;
|
|
32
|
+
/**
|
|
33
|
+
* If set to `true`, tells the crawler to skip navigation and process the request directly.
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
skipNavigation?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* A base URL that will be used to resolve relative URLs.
|
|
39
|
+
*/
|
|
40
|
+
baseUrl?: string;
|
|
41
|
+
/**
|
|
42
|
+
* An array of URL patterns that URLs must match to be enqueued.
|
|
43
|
+
*
|
|
44
|
+
* Accepts glob pattern strings, `{ glob: string }` objects, `RegExp` instances, or `{ regexp: RegExp }` objects.
|
|
45
|
+
*
|
|
46
|
+
* Glob matching is always case-insensitive.
|
|
47
|
+
* If you need case-sensitive matching, use a `RegExp`.
|
|
48
|
+
*
|
|
49
|
+
* The patterns are combined with the {@link EnqueueUrlsOptions.strategy|`strategy`} using AND logic - a URL
|
|
50
|
+
* must match at least one `include` pattern **and** satisfy the strategy to be enqueued. To match URLs across
|
|
51
|
+
* hostnames, pass an explicit {@link EnqueueStrategy.All} strategy.
|
|
52
|
+
*
|
|
53
|
+
* If `undefined`, the links are enqueued based on the {@link EnqueueUrlsOptions.strategy|`strategy`} alone.
|
|
54
|
+
* Passing an empty array is not allowed.
|
|
55
|
+
*/
|
|
56
|
+
include?: readonly UrlPatternInput[];
|
|
57
|
+
/**
|
|
58
|
+
* An array of URL patterns. Matching URLs will **not** be enqueued.
|
|
59
|
+
*
|
|
60
|
+
* Accepts glob pattern strings, `{ glob: string }` objects, `RegExp` instances, or `{ regexp: RegExp }` objects.
|
|
61
|
+
*
|
|
62
|
+
* Glob matching is always case-insensitive.
|
|
63
|
+
* If you need case-sensitive matching, use a `RegExp`.
|
|
64
|
+
*/
|
|
65
|
+
exclude?: readonly UrlPatternInput[];
|
|
66
|
+
/**
|
|
67
|
+
* After request options are filtered by `include`/`exclude` patterns, this function can be used
|
|
68
|
+
* to remove them or modify their contents such as `userData`, `payload` or, most importantly `uniqueKey`. This is useful
|
|
69
|
+
* when you need to enqueue multiple `Requests` to the queue that share the same URL, but differ in methods or payloads,
|
|
70
|
+
* or to dynamically update or create `userData`.
|
|
71
|
+
*
|
|
72
|
+
* For example: by adding `keepUrlFragment: true` to the request options, URL fragments will not be removed
|
|
73
|
+
* when `uniqueKey` is computed.
|
|
74
|
+
*
|
|
75
|
+
* **Example:**
|
|
76
|
+
* ```javascript
|
|
77
|
+
* {
|
|
78
|
+
* transformRequestFunction: (request) => {
|
|
79
|
+
* request.userData.foo = 'bar';
|
|
80
|
+
* request.keepUrlFragment = true;
|
|
81
|
+
* return request;
|
|
82
|
+
* }
|
|
83
|
+
* }
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* Note that `transformRequestFunction` has the highest priority and can overwrite
|
|
87
|
+
* the global `label` option.
|
|
88
|
+
*
|
|
89
|
+
* The function receives a {@link RequestOptions} object and can return either:
|
|
90
|
+
* - The modified {@link RequestOptions} object
|
|
91
|
+
* - `'unchanged'` to keep the original options as-is
|
|
92
|
+
* - A falsy value or `'skip'` to exclude the request from the queue
|
|
93
|
+
*/
|
|
94
|
+
transformRequestFunction?: RequestTransform;
|
|
95
|
+
/**
|
|
96
|
+
* The strategy to use when enqueueing the urls.
|
|
97
|
+
*
|
|
98
|
+
* Depending on the strategy you select, we will only check certain parts of the URLs found. Here is a diagram of each URL part and their name:
|
|
99
|
+
*
|
|
100
|
+
* ```md
|
|
101
|
+
* Protocol Domain
|
|
102
|
+
* ┌────┐ ┌─────────┐
|
|
103
|
+
* https://example.crawlee.dev/...
|
|
104
|
+
* │ └─────────────────┤
|
|
105
|
+
* │ Hostname │
|
|
106
|
+
* │ │
|
|
107
|
+
* └─────────────────────────┘
|
|
108
|
+
* Origin
|
|
109
|
+
*```
|
|
110
|
+
*
|
|
111
|
+
* @default EnqueueStrategy.SameHostname
|
|
112
|
+
*/
|
|
113
|
+
strategy?: EnqueueStrategyOption;
|
|
114
|
+
/**
|
|
115
|
+
* By default, only the first batch (1000) of found requests will be added to the queue before resolving the call.
|
|
116
|
+
* You can use this option to wait for adding all of them.
|
|
117
|
+
*/
|
|
118
|
+
waitForAllRequestsToBeAdded?: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* When a request is skipped for some reason, you can use this callback to act on it.
|
|
121
|
+
* This is currently fired for requests skipped
|
|
122
|
+
* 1. based on robots.txt file,
|
|
123
|
+
* 2. because they don't match enqueueLinks filters,
|
|
124
|
+
* 3. or because the maxRequestsPerCrawl limit has been reached
|
|
125
|
+
*/
|
|
126
|
+
onSkippedRequest?: SkippedRequestCallback;
|
|
127
|
+
}
|
|
128
|
+
/** The combined options accepted by a crawler context's `enqueueLinks()` helper: `extractLinks()` + `enqueueUrls()`. */
|
|
129
|
+
export type EnqueueLinksOptions = ExtractLinksOptions & EnqueueUrlsOptions;
|
|
130
|
+
/**
|
|
131
|
+
* @internal
|
|
132
|
+
* This method helps resolve the baseUrl that will be used for filtering in {@link enqueueLinks}.
|
|
133
|
+
* - If a user provides a base url, we always return it
|
|
134
|
+
* - If a user specifies {@link EnqueueStrategy.All} strategy, they do not care if the newly found urls are on the original
|
|
135
|
+
* request domain, or a redirected one
|
|
136
|
+
* - In all other cases, we return the domain of the original request as that's the one we need to use for filtering
|
|
137
|
+
*/
|
|
138
|
+
export declare function resolveBaseUrlForEnqueueLinksFiltering({ enqueueStrategy, finalRequestUrl, originalRequestUrl, userProvidedBaseUrl, }: ResolveBaseUrl): string;
|
|
139
|
+
/**
|
|
140
|
+
* @internal
|
|
141
|
+
*/
|
|
142
|
+
export interface ResolveBaseUrl {
|
|
143
|
+
userProvidedBaseUrl?: string;
|
|
144
|
+
enqueueStrategy?: EnqueueStrategyOption;
|
|
145
|
+
originalRequestUrl: string;
|
|
146
|
+
finalRequestUrl?: string;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* @internal
|
|
150
|
+
* Builds the glob patterns a URL must match to satisfy the given enqueue `strategy`, anchored at `baseUrl`.
|
|
151
|
+
*/
|
|
152
|
+
export declare function buildEnqueueStrategyPatterns(baseUrl: string, strategy: EnqueueStrategyOption): UrlPatternObject[];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { EnqueueStrategy } from '@crawlee/utils';
|
|
2
|
+
import { getDomain } from 'tldts';
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
* This method helps resolve the baseUrl that will be used for filtering in {@link enqueueLinks}.
|
|
6
|
+
* - If a user provides a base url, we always return it
|
|
7
|
+
* - If a user specifies {@link EnqueueStrategy.All} strategy, they do not care if the newly found urls are on the original
|
|
8
|
+
* request domain, or a redirected one
|
|
9
|
+
* - In all other cases, we return the domain of the original request as that's the one we need to use for filtering
|
|
10
|
+
*/
|
|
11
|
+
export function resolveBaseUrlForEnqueueLinksFiltering({ enqueueStrategy, finalRequestUrl, originalRequestUrl, userProvidedBaseUrl, }) {
|
|
12
|
+
// User provided base url takes priority
|
|
13
|
+
if (userProvidedBaseUrl) {
|
|
14
|
+
return userProvidedBaseUrl;
|
|
15
|
+
}
|
|
16
|
+
const originalUrlOrigin = new URL(originalRequestUrl).origin;
|
|
17
|
+
const finalUrlOrigin = new URL(finalRequestUrl ?? originalRequestUrl).origin;
|
|
18
|
+
// We can assume users want to go off the domain in this case
|
|
19
|
+
if (enqueueStrategy === EnqueueStrategy.All) {
|
|
20
|
+
return finalUrlOrigin;
|
|
21
|
+
}
|
|
22
|
+
// If the user wants to ensure the same domain is accessed, regardless of subdomains, we check to ensure the domains match
|
|
23
|
+
// If they don't (we went off domain via a redirect), we keep filtering against the original domain - returning undefined would disable the filtering entirely
|
|
24
|
+
if (enqueueStrategy === EnqueueStrategy.SameDomain) {
|
|
25
|
+
const originalHostname = getDomain(originalUrlOrigin, { mixedInputs: false });
|
|
26
|
+
const finalHostname = getDomain(finalUrlOrigin, { mixedInputs: false });
|
|
27
|
+
if (originalHostname === finalHostname) {
|
|
28
|
+
return finalUrlOrigin;
|
|
29
|
+
}
|
|
30
|
+
return originalUrlOrigin;
|
|
31
|
+
}
|
|
32
|
+
// Always enqueue urls that are from the same origin in all other cases, as the filtering happens on the original request url, even if there was a redirect
|
|
33
|
+
// before actually finding the urls
|
|
34
|
+
return originalUrlOrigin;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* @internal
|
|
38
|
+
* Builds the glob patterns a URL must match to satisfy the given enqueue `strategy`, anchored at `baseUrl`.
|
|
39
|
+
*/
|
|
40
|
+
export function buildEnqueueStrategyPatterns(baseUrl, strategy) {
|
|
41
|
+
const url = new URL(baseUrl);
|
|
42
|
+
switch (strategy) {
|
|
43
|
+
case EnqueueStrategy.SameHostname:
|
|
44
|
+
// We need to get the origin of the passed in domain in the event someone sets baseUrl
|
|
45
|
+
// to an url like https://example.com/deep/default/path and one of the found urls is an
|
|
46
|
+
// absolute relative path (/path/to/page)
|
|
47
|
+
return [{ glob: ignoreHttpSchema(`${url.origin}/**`) }];
|
|
48
|
+
case EnqueueStrategy.SameDomain: {
|
|
49
|
+
// Get the actual hostname from the base url
|
|
50
|
+
const baseUrlHostname = getDomain(url.hostname, { mixedInputs: false });
|
|
51
|
+
if (baseUrlHostname) {
|
|
52
|
+
// We have a hostname, so we can use it to match all links on the page that point to it and any subdomains of it
|
|
53
|
+
url.hostname = baseUrlHostname;
|
|
54
|
+
return [
|
|
55
|
+
{ glob: ignoreHttpSchema(`${url.origin.replace(baseUrlHostname, `*.${baseUrlHostname}`)}/**`) },
|
|
56
|
+
{ glob: ignoreHttpSchema(`${url.origin}/**`) },
|
|
57
|
+
];
|
|
58
|
+
}
|
|
59
|
+
// We don't have a hostname (can happen for ips for instance), so reproduce the same behavior
|
|
60
|
+
// as SameDomainAndSubdomain
|
|
61
|
+
return [{ glob: ignoreHttpSchema(`${url.origin}/**`) }];
|
|
62
|
+
}
|
|
63
|
+
case EnqueueStrategy.SameOrigin:
|
|
64
|
+
// The same behavior as SameHostname, but respecting the protocol of the URL
|
|
65
|
+
return [{ glob: `${url.origin}/**` }];
|
|
66
|
+
case EnqueueStrategy.All:
|
|
67
|
+
default:
|
|
68
|
+
return [{ glob: `http{s,}://**` }];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Internal function that changes the enqueue glob patterns to match both http and https
|
|
73
|
+
*/
|
|
74
|
+
function ignoreHttpSchema(pattern) {
|
|
75
|
+
return pattern.replace(/^(https?):\/\//, 'http{s,}://');
|
|
76
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export * from './enqueue_links.js';
|
|
2
|
+
export { applyRequestTransform, constructGlobObjectsFromGlobs, constructRegExpObjectsFromRegExps, constructUrlPatternObjects, createRequestOptions, createSkippedRequestArgs, filterRequestOptionsByPatterns, updateEnqueueLinksPatternCache, urlPatternSchema, validateGlobPattern, } from './shared.js';
|
|
3
|
+
export type { GlobInput, GlobObject, RegExpInput, RegExpObject, RequestTransform, SkippedRequestCallback, UrlPatternInput, } from './shared.js';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export * from './enqueue_links.js';
|
|
2
|
+
// Not `export *`: keeps the internal `UrlPatternObject` off the public surface.
|
|
3
|
+
export { applyRequestTransform, constructGlobObjectsFromGlobs, constructRegExpObjectsFromRegExps, constructUrlPatternObjects, createRequestOptions, createSkippedRequestArgs, filterRequestOptionsByPatterns, updateEnqueueLinksPatternCache, urlPatternSchema, validateGlobPattern, } from './shared.js';
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { Awaitable, Dictionary } from '@crawlee/types';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { EnqueueStrategyOption, RequestOptions, Source } from '@crawlee/core';
|
|
4
|
+
import { Request } from '@crawlee/core';
|
|
5
|
+
import type { SkippedRequestReason } from '../crawling_request.js';
|
|
6
|
+
export interface GlobObject {
|
|
7
|
+
glob: string;
|
|
8
|
+
}
|
|
9
|
+
export type GlobInput = string | GlobObject;
|
|
10
|
+
export interface RegExpObject {
|
|
11
|
+
regexp: RegExp;
|
|
12
|
+
}
|
|
13
|
+
export type RegExpInput = RegExp | RegExpObject;
|
|
14
|
+
/** Unified URL pattern input — accepts glob strings, glob objects, RegExp instances, or regexp objects. */
|
|
15
|
+
export type UrlPatternInput = GlobInput | RegExpInput;
|
|
16
|
+
/**
|
|
17
|
+
* Accepts one {@link UrlPatternInput} — a glob string, a RegExp instance, or a `{ glob }` / `{ regexp }` object.
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export declare const urlPatternSchema: z.ZodType<UrlPatternInput>;
|
|
21
|
+
export type SkippedRequestCallback = (args: {
|
|
22
|
+
request: Request;
|
|
23
|
+
reason: SkippedRequestReason;
|
|
24
|
+
/** The `message` passed to {@link RestrictedCrawlingContext.skipRequest|`context.skipRequest()`}, if any. */
|
|
25
|
+
message?: string;
|
|
26
|
+
}) => Awaitable<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Builds the `{ request, reason }` argument passed to a {@link SkippedRequestCallback}, constructing the
|
|
29
|
+
* `Request` lazily on first access to `request` (and caching it) since most skips are never observed by a
|
|
30
|
+
* real callback and building a `Request` isn't free.
|
|
31
|
+
* @ignore
|
|
32
|
+
*/
|
|
33
|
+
export declare function createSkippedRequestArgs(source: string | Source, reason: SkippedRequestReason): Parameters<SkippedRequestCallback>[0];
|
|
34
|
+
/**
|
|
35
|
+
* @ignore
|
|
36
|
+
*/
|
|
37
|
+
export declare function updateEnqueueLinksPatternCache(item: GlobInput | RegExpInput, pattern: RegExpObject | GlobObject): void;
|
|
38
|
+
/**
|
|
39
|
+
* Helper factory used in the `enqueueLinks()` and enqueueLinksByClickingElements() function
|
|
40
|
+
* to construct Glob objects from Glob pattern strings.
|
|
41
|
+
* @ignore
|
|
42
|
+
*/
|
|
43
|
+
export declare function constructGlobObjectsFromGlobs(globs: readonly GlobInput[]): GlobObject[];
|
|
44
|
+
/**
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
export declare function validateGlobPattern(glob: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* Helper factory used in the `enqueueLinks()` and enqueueLinksByClickingElements() function
|
|
50
|
+
* to check RegExps input and return valid RegExps.
|
|
51
|
+
* @ignore
|
|
52
|
+
*/
|
|
53
|
+
export declare function constructRegExpObjectsFromRegExps(regexps: readonly RegExpInput[]): RegExpObject[];
|
|
54
|
+
/**
|
|
55
|
+
* The compiled form of a {@link UrlPatternInput}, produced by {@link constructUrlPatternObjects}. Deliberately
|
|
56
|
+
* not re-exported from the package entry point — it is an implementation detail of the pattern matching helpers.
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
export interface UrlPatternObject {
|
|
60
|
+
glob?: string;
|
|
61
|
+
regexp?: RegExp;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Helper factory used in the `enqueueLinks()` function to construct UrlPatternObjects
|
|
65
|
+
* from a mixed array of glob strings, glob objects, RegExp instances, and regexp objects.
|
|
66
|
+
* @ignore
|
|
67
|
+
*/
|
|
68
|
+
export declare function constructUrlPatternObjects(patterns: readonly UrlPatternInput[]): UrlPatternObject[];
|
|
69
|
+
/**
|
|
70
|
+
* Filters request options by URL patterns.
|
|
71
|
+
*
|
|
72
|
+
* When `includePatterns` is empty/undefined, all options pass through (only exclude filtering applies).
|
|
73
|
+
* @ignore
|
|
74
|
+
*/
|
|
75
|
+
export declare function filterRequestOptionsByPatterns(requestOptions: RequestOptions[], includePatterns: UrlPatternObject[] | undefined, excludePatterns?: UrlPatternObject[], strategy?: EnqueueStrategyOption, onSkippedRequestOptions?: (options: RequestOptions) => void): RequestOptions[];
|
|
76
|
+
/**
|
|
77
|
+
* @ignore
|
|
78
|
+
*/
|
|
79
|
+
export declare function createRequestOptions(sources: readonly (string | Record<string, unknown>)[], options?: {
|
|
80
|
+
label?: string;
|
|
81
|
+
userData?: Dictionary;
|
|
82
|
+
baseUrl?: string;
|
|
83
|
+
skipNavigation?: boolean;
|
|
84
|
+
sessionId?: string;
|
|
85
|
+
strategy?: EnqueueStrategyOption;
|
|
86
|
+
}): RequestOptions[];
|
|
87
|
+
/**
|
|
88
|
+
* Takes a {@link RequestOptions} object and changes its attributes in a desired way. This user-function is used
|
|
89
|
+
* by {@link enqueueLinks} to modify request options before they are converted to {@link Request} instances.
|
|
90
|
+
*/
|
|
91
|
+
export interface RequestTransform {
|
|
92
|
+
/**
|
|
93
|
+
* @param original Request options to be modified.
|
|
94
|
+
* @returns The modified request options to enqueue, `'unchanged'` to keep the original options as-is,
|
|
95
|
+
* or a falsy value / `'skip'` to exclude the request from the queue.
|
|
96
|
+
*/
|
|
97
|
+
(original: RequestOptions): RequestOptions | false | undefined | null | 'skip' | 'unchanged';
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Applies a {@link RequestTransform} function to a list of request options.
|
|
101
|
+
* Options for which the transform returns a falsy value are removed from the list.
|
|
102
|
+
* @param onSkipped Called with the original request options when the transform returns a falsy value (i.e. the request is skipped).
|
|
103
|
+
* @ignore
|
|
104
|
+
* @internal
|
|
105
|
+
*/
|
|
106
|
+
export declare function applyRequestTransform(requestOptions: RequestOptions[], transformFn: RequestTransform, onSkipped?: (requestOptions: RequestOptions) => void): RequestOptions[];
|