@crawlee/basic 4.0.0-beta.23 → 4.0.0-beta.231
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 +15 -15
- package/index.d.ts +11 -2
- package/index.js +11 -1
- package/internals/autoscaling/autoscaled-pool.d.ts +176 -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 +378 -369
- package/internals/basic-crawler.js +1449 -863
- 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 +54 -0
- package/internals/request-timeout.js +98 -0
- package/internals/router.d.ts +299 -0
- package/internals/router.js +312 -0
- package/internals/send-request.d.ts +4 -4
- package/internals/send-request.js +4 -3
- 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-pool.d.ts +193 -0
- package/internals/session-pool/session-pool.js +453 -0
- package/internals/session-pool/session.d.ts +151 -0
- package/internals/session-pool/session.js +225 -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 +20 -14
- package/index.d.ts.map +0 -1
- package/index.js.map +0 -1
- package/internals/basic-crawler.d.ts.map +0 -1
- package/internals/basic-crawler.js.map +0 -1
- package/internals/send-request.d.ts.map +0 -1
- package/internals/send-request.js.map +0 -1
|
@@ -1,25 +1,43 @@
|
|
|
1
|
-
import type { AddRequestsBatchedOptions, AddRequestsBatchedResult,
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import type { AddRequestsBatchedOptions, AddRequestsBatchedResult, CrawleeLogger, DatasetExportOptions, IProxyConfiguration, IRequestLoader, IRequestManager, RequestsLike, Source, StorageIdentifier, StorageWritePolicy } from '@crawlee/core';
|
|
2
|
+
import { Configuration, Request, Dataset, EventManager, RequestQueue } from '@crawlee/core';
|
|
3
|
+
import { BaseHttpClient } from '@crawlee/http-client';
|
|
4
|
+
import type { Awaitable, Dictionary, ISessionPool, SetStatusMessageOptions, StorageBackend } from '@crawlee/types';
|
|
4
5
|
import { RobotsTxtFile } from '@crawlee/utils';
|
|
5
|
-
import type { ReadonlyDeep
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
6
|
+
import type { ReadonlyDeep } from 'type-fest';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import type { TaskLoopPredicates } from './autoscaling/autoscaled-pool.js';
|
|
9
|
+
import type { ConcurrencySystemOptions, IConcurrencySystem } from './autoscaling/concurrency-system.js';
|
|
10
|
+
import { ConcurrencySystem } from './autoscaling/concurrency-system.js';
|
|
11
|
+
import type { FinalStatistics } from './autoscaling/system-status.js';
|
|
12
|
+
import { ContextPipeline } from './crawlers/context-pipeline.js';
|
|
13
|
+
import type { CrawlingContext, TypedRequestsLike } from './crawlers/crawler-commons.js';
|
|
14
|
+
import type { IStatistics, StatisticState } from './crawlers/statistics.js';
|
|
15
|
+
import type { EnqueueUrlsOptions, SkippedRequestCallback } from './enqueue-links/index.js';
|
|
16
|
+
import type { GetUserDataFromRequest, RouterHandler, RouterRoutes } from './router.js';
|
|
8
17
|
export interface BasicCrawlingContext<UserData extends Dictionary = Dictionary> extends CrawlingContext<UserData> {
|
|
9
18
|
}
|
|
19
|
+
export { navigationDeadlineKey, remainingNavigationWindowMillis } from './request-timeout.js';
|
|
10
20
|
export type RequestHandler<Context extends CrawlingContext = CrawlingContext> = (inputs: Context) => Awaitable<void>;
|
|
11
|
-
|
|
12
|
-
|
|
21
|
+
/**
|
|
22
|
+
* An error handler receives the crawling context and the error that was thrown while processing the request.
|
|
23
|
+
*
|
|
24
|
+
* Unlike the {@link RequestHandler}, an error handler may run before the context pipeline has finished
|
|
25
|
+
* building the full context (e.g. when navigation or session setup fails). Therefore only `BaseContext` is
|
|
26
|
+
* guaranteed to be present, while the extra properties added by the pipeline and `extendContext` (the
|
|
27
|
+
* difference between `BaseContext` and `ExtendedContext`) are only available as a `Partial`.
|
|
28
|
+
*/
|
|
29
|
+
export type ErrorHandler<BaseContext extends CrawlingContext = CrawlingContext, ExtendedContext extends BaseContext = BaseContext> = (inputs: BaseContext & Partial<ExtendedContext>, error: Error) => Awaitable<void>;
|
|
30
|
+
export interface StatusMessageCallbackParams<Context extends CrawlingContext = BasicCrawlingContext, Crawler extends BasicCrawler<any, any, any, any> = BasicCrawler<Context>> {
|
|
13
31
|
state: StatisticState;
|
|
14
32
|
crawler: Crawler;
|
|
15
33
|
previousState: StatisticState;
|
|
16
34
|
message: string;
|
|
17
35
|
}
|
|
18
|
-
export type StatusMessageCallback<Context extends CrawlingContext = BasicCrawlingContext, Crawler extends BasicCrawler<any> = BasicCrawler<Context>> = (params: StatusMessageCallbackParams<Context, Crawler>) => Awaitable<void>;
|
|
36
|
+
export type StatusMessageCallback<Context extends CrawlingContext = BasicCrawlingContext, Crawler extends BasicCrawler<any, any, any, any> = BasicCrawler<Context>> = (params: StatusMessageCallbackParams<Context, Crawler>) => Awaitable<void>;
|
|
19
37
|
export type RequireContextPipeline<DefaultContextType extends CrawlingContext, FinalContextType extends DefaultContextType> = DefaultContextType extends FinalContextType ? {} : {
|
|
20
38
|
contextPipelineBuilder: () => ContextPipeline<CrawlingContext, FinalContextType>;
|
|
21
39
|
};
|
|
22
|
-
export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingContext, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension> {
|
|
40
|
+
export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingContext, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<Context['request']>>, StatisticStateExtension extends object = {}> {
|
|
23
41
|
/**
|
|
24
42
|
* User-provided function that performs the logic of the crawler. It is called for each URL to crawl.
|
|
25
43
|
*
|
|
@@ -35,11 +53,17 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
|
|
|
35
53
|
* To make this work, we should **always**
|
|
36
54
|
* let our function throw exceptions rather than catch them.
|
|
37
55
|
* The exceptions are logged to the request using the
|
|
38
|
-
* {@link
|
|
56
|
+
* {@link CrawlingRequest.pushErrorMessage|`request.pushErrorMessage()`} function.
|
|
39
57
|
*/
|
|
40
|
-
requestHandler?: RequestHandler<ExtendedContext>;
|
|
58
|
+
requestHandler?: RouterHandler<ExtendedContext, Routes> | RequestHandler<ExtendedContext>;
|
|
41
59
|
/**
|
|
42
|
-
* Allows the user to extend the crawling context
|
|
60
|
+
* Allows the user to extend the crawling context with custom functionality (helpers, references, etc.).
|
|
61
|
+
*
|
|
62
|
+
* `extendContext` runs *before* navigation, so the returned members are visible to the
|
|
63
|
+
* `preNavigationHooks`, `postNavigationHooks`, and the `requestHandler` alike. As a consequence,
|
|
64
|
+
* the `context` passed to `extendContext` is the pre-navigation {@link CrawlingContext} and does
|
|
65
|
+
* **not** include navigation-dependent members (e.g. `page`, `response`, `$`, `body`). If you need
|
|
66
|
+
* those, use a `postNavigationHook` or the `requestHandler` instead.
|
|
43
67
|
*
|
|
44
68
|
* **Example usage:**
|
|
45
69
|
*
|
|
@@ -59,7 +83,7 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
|
|
|
59
83
|
* });
|
|
60
84
|
* ```
|
|
61
85
|
*/
|
|
62
|
-
extendContext?: (context:
|
|
86
|
+
extendContext?: (context: CrawlingContext) => Awaitable<ContextExtension>;
|
|
63
87
|
/**
|
|
64
88
|
* *Intended for BasicCrawler subclasses*. Prepares a context pipeline that transforms the initial crawling context into the shape given by the `Context` type parameter.
|
|
65
89
|
*
|
|
@@ -68,23 +92,25 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
|
|
|
68
92
|
contextPipelineBuilder?: () => ContextPipeline<CrawlingContext, Context>;
|
|
69
93
|
/**
|
|
70
94
|
* Static list of URLs to be processed.
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
95
|
+
*
|
|
96
|
+
* @deprecated Use the `requestManager` option instead. To combine a read-only loader (such as a `RequestList`)
|
|
97
|
+
* with a writable queue, build a tandem with {@link IRequestLoader.toTandem|`requestList.toTandem(requestQueue)`}
|
|
98
|
+
* and pass the result as `requestManager`. When both `requestList` and `requestQueue` are provided, they are
|
|
99
|
+
* combined into a tandem automatically.
|
|
74
100
|
*/
|
|
75
|
-
requestList?:
|
|
101
|
+
requestList?: IRequestLoader;
|
|
76
102
|
/**
|
|
77
103
|
* Dynamic queue of URLs to be processed. This is useful for recursive crawling of websites.
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* it
|
|
104
|
+
*
|
|
105
|
+
* @deprecated Use the `requestManager` option instead. A `RequestQueue` is itself a request manager, so you can
|
|
106
|
+
* pass it directly as `requestManager`.
|
|
81
107
|
*/
|
|
82
|
-
requestQueue?:
|
|
108
|
+
requestQueue?: RequestQueue;
|
|
83
109
|
/**
|
|
84
|
-
*
|
|
110
|
+
* Manager of requests that should be processed by the crawler. Mutually exclusive with the deprecated
|
|
111
|
+
* `requestQueue` and `requestList` options.
|
|
85
112
|
*
|
|
86
|
-
*
|
|
87
|
-
* If using this, the type of `BasicCrawler.requestQueue` may not be fully compatible with the `RequestProvider` class.
|
|
113
|
+
* If not provided, the crawler will open the default {@link RequestQueue} when it is first needed.
|
|
88
114
|
*/
|
|
89
115
|
requestManager?: IRequestManager;
|
|
90
116
|
/**
|
|
@@ -113,27 +139,21 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
|
|
|
113
139
|
failedRequestHandler?: ErrorHandler<CrawlingContext, ExtendedContext>;
|
|
114
140
|
/**
|
|
115
141
|
* Specifies the maximum number of retries allowed for a request if its processing fails.
|
|
116
|
-
* This includes retries due to navigation errors or errors thrown from user-supplied
|
|
117
|
-
* (`requestHandler`, `preNavigationHooks`, `postNavigationHooks`).
|
|
118
|
-
*
|
|
119
|
-
* This limit does not apply to retries triggered by session rotation
|
|
120
|
-
* (see {@link BasicCrawlerOptions.maxSessionRotations|`maxSessionRotations`}).
|
|
142
|
+
* This includes retries due to navigation errors, session/proxy errors, or errors thrown from user-supplied
|
|
143
|
+
* functions (`requestHandler`, `preNavigationHooks`, `postNavigationHooks`).
|
|
121
144
|
* @default 3
|
|
122
145
|
*/
|
|
123
146
|
maxRequestRetries?: number;
|
|
124
147
|
/**
|
|
125
|
-
* Indicates how much time (in seconds) to wait before crawling another same domain request.
|
|
148
|
+
* Indicates how much time (in seconds) to wait before crawling another same domain request. Subdomains are
|
|
149
|
+
* paced together with the site they belong to.
|
|
150
|
+
*
|
|
151
|
+
* Offered to the crawler's request manager as a `minIntervalEverywhere` {@link PacingSignal}; a manager that
|
|
152
|
+
* already paces every domain it dispatches to takes it, so no domain ends up with two clocks. Otherwise the
|
|
153
|
+
* crawler wraps its request manager in a {@link ThrottlingRequestManager} of its own.
|
|
126
154
|
* @default 0
|
|
127
155
|
*/
|
|
128
156
|
sameDomainDelaySecs?: number;
|
|
129
|
-
/**
|
|
130
|
-
* Maximum number of session rotations per request.
|
|
131
|
-
* The crawler will automatically rotate the session in case of a proxy error or if it gets blocked by the website.
|
|
132
|
-
*
|
|
133
|
-
* The session rotations are not counted towards the {@link BasicCrawlerOptions.maxRequestRetries|`maxRequestRetries`} limit.
|
|
134
|
-
* @default 10
|
|
135
|
-
*/
|
|
136
|
-
maxSessionRotations?: number;
|
|
137
157
|
/**
|
|
138
158
|
* Maximum number of pages that the crawler will open. The crawl will stop when this limit is reached.
|
|
139
159
|
* This value should always be set in order to prevent infinite loops in misconfigured crawlers.
|
|
@@ -147,46 +167,82 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
|
|
|
147
167
|
*/
|
|
148
168
|
maxCrawlDepth?: number;
|
|
149
169
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
170
|
+
* Lets you override the predicates that steer the crawler's task loop: `isTaskReadyFunction` (may another request
|
|
171
|
+
* start?) and `isFinishedFunction` (is the crawl over?). The task itself — fetching a request and running it
|
|
172
|
+
* through the pipeline — is owned by the crawler and cannot be overridden.
|
|
173
|
+
*
|
|
174
|
+
* Concurrency is configured elsewhere — through the `minConcurrency`/`maxConcurrency`/`maxRequestsPerMinute`
|
|
175
|
+
* shortcuts, or a {@link BasicCrawlerOptions.concurrencySystem|`concurrencySystem`} for finer control.
|
|
176
|
+
*/
|
|
177
|
+
taskLoopOptions?: TaskLoopPredicates;
|
|
178
|
+
/**
|
|
179
|
+
* A pre-configured concurrency governor — the component that decides whether there is free compute for one more
|
|
180
|
+
* task. Typically a {@link ConcurrencySystem}, though any {@link IConcurrencySystem} is accepted. All
|
|
181
|
+
* scaling configuration (min/max/desired concurrency, scaling ratios, `maxTasksPerMinute`, snapshotter tuning)
|
|
182
|
+
* lives on the instance itself.
|
|
183
|
+
*
|
|
184
|
+
* Inject the *same* instance into several concurrent crawlers to cap their **combined** concurrency against a
|
|
185
|
+
* single budget. Each crawler still builds and drives its own {@link AutoscaledPool}; only the load/scaling
|
|
186
|
+
* accounting is shared.
|
|
187
|
+
*
|
|
188
|
+
* Mutually exclusive with the `minConcurrency`/`maxConcurrency`/`initialConcurrency`/`maxRequestsPerMinute`
|
|
189
|
+
* shortcuts, which configure the default system this one replaces — combining the two throws.
|
|
190
|
+
*
|
|
191
|
+
* You own a supplied system's lifecycle: `start()` it before `run()` (which throws otherwise) and `stop()` it once
|
|
192
|
+
* every crawler borrowing it has finished. The crawler does neither on your behalf.
|
|
155
193
|
*/
|
|
156
|
-
|
|
194
|
+
concurrencySystem?: IConcurrencySystem;
|
|
157
195
|
/**
|
|
158
196
|
* Sets the minimum concurrency (parallelism) for the crawl. Shortcut for the
|
|
159
|
-
*
|
|
197
|
+
* {@link ConcurrencySystemOptions.minConcurrency|`minConcurrency`} option of the crawler's default
|
|
198
|
+
* {@link ConcurrencySystem}.
|
|
160
199
|
* > *WARNING:* If we set this value too high with respect to the available system memory and CPU, our crawler will run extremely slow or crash.
|
|
161
200
|
* If not sure, it's better to keep the default value and the concurrency will scale up automatically.
|
|
162
201
|
*/
|
|
163
202
|
minConcurrency?: number;
|
|
164
203
|
/**
|
|
165
204
|
* Sets the maximum concurrency (parallelism) for the crawl. Shortcut for the
|
|
166
|
-
*
|
|
205
|
+
* {@link ConcurrencySystemOptions.maxConcurrency|`maxConcurrency`} option of the crawler's default
|
|
206
|
+
* {@link ConcurrencySystem}.
|
|
167
207
|
*/
|
|
168
208
|
maxConcurrency?: number;
|
|
209
|
+
/**
|
|
210
|
+
* Sets the concurrency (parallelism) the crawl starts with, before any scaling happens. Shortcut for the
|
|
211
|
+
* {@link ConcurrencySystemOptions.desiredConcurrency|`desiredConcurrency`} option of the crawler's default
|
|
212
|
+
* {@link ConcurrencySystem}. Defaults to `minConcurrency`.
|
|
213
|
+
*/
|
|
214
|
+
initialConcurrency?: number;
|
|
169
215
|
/**
|
|
170
216
|
* The maximum number of requests per minute the crawler should run.
|
|
171
217
|
* By default, this is set to `Infinity`, but we can pass any positive, non-zero integer.
|
|
172
|
-
* Shortcut for the
|
|
218
|
+
* Shortcut for the {@link ConcurrencySystemOptions.maxTasksPerMinute|`maxTasksPerMinute`} option of the
|
|
219
|
+
* crawler's default {@link ConcurrencySystem}.
|
|
173
220
|
*/
|
|
174
221
|
maxRequestsPerMinute?: number;
|
|
175
222
|
/**
|
|
176
223
|
* Allows to keep the crawler alive even if the {@link RequestQueue} gets empty.
|
|
177
224
|
* By default, the `crawler.run()` will resolve once the queue is empty. With `keepAlive: true` it will keep running,
|
|
178
|
-
* waiting for more requests to come.
|
|
225
|
+
* waiting for more requests to come.
|
|
226
|
+
*
|
|
227
|
+
* `crawler.stop()` only stops the crawler from dispatching new requests — it does not wait for or drain
|
|
228
|
+
* requests already sitting in the queue. If this crawler is fed by another crawler or an external producer,
|
|
229
|
+
* calling `stop()` as soon as the producer finishes can abandon requests the producer already enqueued but
|
|
230
|
+
* this crawler had not yet picked up.
|
|
231
|
+
*
|
|
232
|
+
* To shut down only once the queue is genuinely empty and the producer has stopped, override
|
|
233
|
+
* {@link BasicCrawlerOptions.taskLoopOptions|`taskLoopOptions.isFinishedFunction`} to check both
|
|
234
|
+
* `(await requestManager.checkReadiness()).status === 'finished'` and the producer's own running/finished flag.
|
|
179
235
|
*/
|
|
180
236
|
keepAlive?: boolean;
|
|
181
237
|
/**
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
*
|
|
238
|
+
* An existing session pool instance to use. When provided, the crawler will use this pool directly instead of
|
|
239
|
+
* creating a new one, enabling session sharing across multiple crawlers. The crawler will not tear down a shared
|
|
240
|
+
* pool — the caller is responsible for its lifecycle.
|
|
241
|
+
*
|
|
242
|
+
* Accepts the built-in {@link SessionPool} or any object implementing the {@link ISessionPool} interface,
|
|
243
|
+
* so custom session-management strategies can be plugged in.
|
|
188
244
|
*/
|
|
189
|
-
|
|
245
|
+
sessionPool?: ISessionPool;
|
|
190
246
|
/**
|
|
191
247
|
* Defines the length of the interval for calling the `setStatusMessage` in seconds.
|
|
192
248
|
*/
|
|
@@ -208,6 +264,15 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
|
|
|
208
264
|
* ```
|
|
209
265
|
*/
|
|
210
266
|
statusMessageCallback?: StatusMessageCallback;
|
|
267
|
+
/**
|
|
268
|
+
* HTTP status codes that indicate the session should be retired.
|
|
269
|
+
*
|
|
270
|
+
* A 429 from a domain covered by a {@link ThrottlingRequestManager} is handled as a rate limit before
|
|
271
|
+
* this is consulted, so removing 429 here only affects domains that manager does not cover.
|
|
272
|
+
*
|
|
273
|
+
* @default [401, 403, 429]
|
|
274
|
+
*/
|
|
275
|
+
blockedStatusCodes?: number[];
|
|
211
276
|
/**
|
|
212
277
|
* If set to `true`, the crawler will automatically try to bypass any detected bot protection.
|
|
213
278
|
*
|
|
@@ -232,31 +297,64 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
|
|
|
232
297
|
* 1. based on robots.txt file,
|
|
233
298
|
* 2. because they don't match enqueueLinks filters,
|
|
234
299
|
* 3. because they are redirected to a URL that doesn't match the enqueueLinks strategy,
|
|
235
|
-
* 4.
|
|
300
|
+
* 4. because the {@link BasicCrawlerOptions.maxRequestsPerCrawl|`maxRequestsPerCrawl`} limit has been reached,
|
|
301
|
+
* 5. or by {@link RestrictedCrawlingContext.skipRequest|`context.skipRequest()`}.
|
|
236
302
|
*/
|
|
237
303
|
onSkippedRequest?: SkippedRequestCallback;
|
|
238
|
-
/** @internal */
|
|
239
|
-
log?: Log;
|
|
240
304
|
/**
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
*
|
|
247
|
-
*
|
|
305
|
+
* A preconfigured statistics instance. When provided, the crawler records into it instead of building its own and
|
|
306
|
+
* will not `reset()` it between `run()` calls. Accepts the built-in {@link Statistics} or any object
|
|
307
|
+
* implementing {@link IStatistics}.
|
|
308
|
+
*
|
|
309
|
+
* Custom fields declared via {@link StatisticsOptions.stateExtension|`stateExtension`} are carried over to
|
|
310
|
+
* {@link BasicCrawler.statistics|`crawler.statistics.state`}:
|
|
311
|
+
*
|
|
312
|
+
* ```ts
|
|
313
|
+
* const statistics = new Statistics({ stateExtension: { defaultState: { productsFound: 0 } } });
|
|
314
|
+
*
|
|
315
|
+
* const crawler = new BasicCrawler({
|
|
316
|
+
* statistics,
|
|
317
|
+
* requestHandler: async () => {
|
|
318
|
+
* statistics.state.productsFound++;
|
|
319
|
+
* },
|
|
320
|
+
* });
|
|
321
|
+
*
|
|
322
|
+
* await crawler.run();
|
|
323
|
+
* // the custom fields are typed on `crawler.statistics` too
|
|
324
|
+
* console.log(crawler.statistics.state.productsFound);
|
|
325
|
+
* ```
|
|
248
326
|
*/
|
|
249
|
-
|
|
327
|
+
statistics?: IStatistics<StatisticStateExtension>;
|
|
250
328
|
/**
|
|
251
329
|
* HTTP client implementation for the `sendRequest` context helper and for plain HTTP crawling.
|
|
252
|
-
* Defaults to
|
|
330
|
+
* Defaults to {@link ImpitHttpClient} when `@crawlee/impit-client` is installed, otherwise {@link FetchHttpClient}.
|
|
253
331
|
*/
|
|
254
332
|
httpClient?: BaseHttpClient;
|
|
255
333
|
/**
|
|
256
334
|
* If set, the crawler will be configured for all connections to use
|
|
257
335
|
* the Proxy URLs provided and rotated according to the configuration.
|
|
258
336
|
*/
|
|
259
|
-
proxyConfiguration?:
|
|
337
|
+
proxyConfiguration?: IProxyConfiguration;
|
|
338
|
+
/**
|
|
339
|
+
* Custom configuration to use for this crawler.
|
|
340
|
+
* If provided, the crawler will use its own ServiceLocator instance instead of the global one.
|
|
341
|
+
*/
|
|
342
|
+
configuration?: Configuration;
|
|
343
|
+
/**
|
|
344
|
+
* Custom storage backend to use for this crawler.
|
|
345
|
+
* If provided, the crawler will use its own ServiceLocator instance instead of the global one.
|
|
346
|
+
*/
|
|
347
|
+
storageBackend?: StorageBackend;
|
|
348
|
+
/**
|
|
349
|
+
* Custom event manager to use for this crawler.
|
|
350
|
+
* If provided, the crawler will use its own ServiceLocator instance instead of the global one.
|
|
351
|
+
*/
|
|
352
|
+
eventManager?: EventManager;
|
|
353
|
+
/**
|
|
354
|
+
* Custom logger to use for this crawler.
|
|
355
|
+
* If provided, the crawler will use its own ServiceLocator instance instead of the global one.
|
|
356
|
+
*/
|
|
357
|
+
logger?: CrawleeLogger;
|
|
260
358
|
/**
|
|
261
359
|
* A unique identifier for the crawler instance. This ID is used to isolate the state returned by
|
|
262
360
|
* {@link BasicCrawler.useState|`crawler.useState()`} from other crawler instances.
|
|
@@ -269,243 +367,153 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = CrawlingC
|
|
|
269
367
|
*
|
|
270
368
|
*/
|
|
271
369
|
id?: string;
|
|
272
|
-
}
|
|
273
|
-
/**
|
|
274
|
-
* A set of options that you can toggle to enable experimental features in Crawlee.
|
|
275
|
-
*
|
|
276
|
-
* NOTE: These options will not respect semantic versioning and may be removed or changed at any time. Use at your own risk.
|
|
277
|
-
* If you do use these and encounter issues, please report them to us.
|
|
278
|
-
*/
|
|
279
|
-
export interface CrawlerExperiments {
|
|
280
|
-
/**
|
|
281
|
-
* @deprecated This experiment is now enabled by default, and this flag will be removed in a future release.
|
|
282
|
-
* If you encounter issues due to this change, please:
|
|
283
|
-
* - report it to us: https://github.com/apify/crawlee
|
|
284
|
-
* - set `requestLocking` to `false` in the `experiments` option of the crawler
|
|
285
|
-
*/
|
|
286
|
-
requestLocking?: boolean;
|
|
287
|
-
}
|
|
288
|
-
/**
|
|
289
|
-
* Provides a simple framework for parallel crawling of web pages.
|
|
290
|
-
* The URLs to crawl are fed either from a static list of URLs
|
|
291
|
-
* or from a dynamic queue of URLs enabling recursive crawling of websites.
|
|
292
|
-
*
|
|
293
|
-
* `BasicCrawler` is a low-level tool that requires the user to implement the page
|
|
294
|
-
* download and data extraction functionality themselves.
|
|
295
|
-
* If we want a crawler that already facilitates this functionality,
|
|
296
|
-
* we should consider using {@link CheerioCrawler}, {@link PuppeteerCrawler} or {@link PlaywrightCrawler}.
|
|
297
|
-
*
|
|
298
|
-
* `BasicCrawler` invokes the user-provided {@link BasicCrawlerOptions.requestHandler|`requestHandler`}
|
|
299
|
-
* for each {@link Request} object, which represents a single URL to crawl.
|
|
300
|
-
* The {@link Request} objects are fed from the {@link RequestList} or {@link RequestQueue}
|
|
301
|
-
* instances provided by the {@link BasicCrawlerOptions.requestList|`requestList`} or {@link BasicCrawlerOptions.requestQueue|`requestQueue`}
|
|
302
|
-
* constructor options, respectively. If neither `requestList` nor `requestQueue` options are provided,
|
|
303
|
-
* the crawler will open the default request queue either when the {@link BasicCrawler.addRequests|`crawler.addRequests()`} function is called,
|
|
304
|
-
* or if `requests` parameter (representing the initial requests) of the {@link BasicCrawler.run|`crawler.run()`} function is provided.
|
|
305
|
-
*
|
|
306
|
-
* If both {@link BasicCrawlerOptions.requestList|`requestList`} and {@link BasicCrawlerOptions.requestQueue|`requestQueue`} options are used,
|
|
307
|
-
* the instance first processes URLs from the {@link RequestList} and automatically enqueues all of them
|
|
308
|
-
* to the {@link RequestQueue} before it starts their processing. This ensures that a single URL is not crawled multiple times.
|
|
309
|
-
*
|
|
310
|
-
* The crawler finishes if there are no more {@link Request} objects to crawl.
|
|
311
|
-
*
|
|
312
|
-
* New requests are only dispatched when there is enough free CPU and memory available,
|
|
313
|
-
* using the functionality provided by the {@link AutoscaledPool} class.
|
|
314
|
-
* All {@link AutoscaledPool} configuration options can be passed to the {@link BasicCrawlerOptions.autoscaledPoolOptions|`autoscaledPoolOptions`}
|
|
315
|
-
* parameter of the `BasicCrawler` constructor.
|
|
316
|
-
* For user convenience, the {@link AutoscaledPoolOptions.minConcurrency|`minConcurrency`} and
|
|
317
|
-
* {@link AutoscaledPoolOptions.maxConcurrency|`maxConcurrency`} options of the
|
|
318
|
-
* underlying {@link AutoscaledPool} constructor are available directly in the `BasicCrawler` constructor.
|
|
319
|
-
*
|
|
320
|
-
* **Example usage:**
|
|
321
|
-
*
|
|
322
|
-
* ```javascript
|
|
323
|
-
* import { BasicCrawler, Dataset } from 'crawlee';
|
|
324
|
-
*
|
|
325
|
-
* // Create a crawler instance
|
|
326
|
-
* const crawler = new BasicCrawler({
|
|
327
|
-
* async requestHandler({ request, sendRequest }) {
|
|
328
|
-
* // 'request' contains an instance of the Request class
|
|
329
|
-
* // Here we simply fetch the HTML of the page and store it to a dataset
|
|
330
|
-
* const { body } = await sendRequest({
|
|
331
|
-
* url: request.url,
|
|
332
|
-
* method: request.method,
|
|
333
|
-
* body: request.payload,
|
|
334
|
-
* headers: request.headers,
|
|
335
|
-
* });
|
|
336
|
-
*
|
|
337
|
-
* await Dataset.pushData({
|
|
338
|
-
* url: request.url,
|
|
339
|
-
* html: body,
|
|
340
|
-
* })
|
|
341
|
-
* },
|
|
342
|
-
* });
|
|
343
|
-
*
|
|
344
|
-
* // Enqueue the initial requests and run the crawler
|
|
345
|
-
* await crawler.run([
|
|
346
|
-
* 'http://www.example.com/page-1',
|
|
347
|
-
* 'http://www.example.com/page-2',
|
|
348
|
-
* ]);
|
|
349
|
-
* ```
|
|
350
|
-
* @category Crawlers
|
|
351
|
-
*/
|
|
352
|
-
export declare class BasicCrawler<Context extends CrawlingContext = CrawlingContext, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension> {
|
|
353
|
-
readonly config: Configuration;
|
|
354
|
-
protected static readonly CRAWLEE_STATE_KEY = "CRAWLEE_STATE";
|
|
355
370
|
/**
|
|
356
|
-
*
|
|
357
|
-
*
|
|
371
|
+
* Makes the storage writes performed while handling a request atomic with respect to the request
|
|
372
|
+
* succeeding: they are recorded in a {@link StorageTransaction} spanning the whole request
|
|
373
|
+
* lifecycle and only applied when the request handler succeeds, so a thrown handler leaves no partial
|
|
374
|
+
* writes behind and a retry does not double-write. Reads within the handler see its own writes.
|
|
375
|
+
*
|
|
376
|
+
* `false` disables the mechanism entirely; an object overrides the per-storage-type
|
|
377
|
+
* {@link StorageWritePolicy} (e.g. `{ requestQueue: 'deferred' }` for all-or-nothing enqueues).
|
|
378
|
+
* {@link withDirectStorageAccess} is the per-call-site escape hatch; `useState()` is deliberately
|
|
379
|
+
* *not* transactional.
|
|
380
|
+
*
|
|
381
|
+
* @default true
|
|
358
382
|
*/
|
|
359
|
-
|
|
383
|
+
transactionalStorage?: boolean | Partial<StorageWritePolicy>;
|
|
360
384
|
/**
|
|
361
|
-
*
|
|
385
|
+
* An array of HTTP response [Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) to be excluded from error consideration.
|
|
386
|
+
* By default, status codes >= 500 trigger errors.
|
|
362
387
|
*/
|
|
363
|
-
|
|
388
|
+
ignoreHttpErrorStatusCodes?: number[];
|
|
364
389
|
/**
|
|
365
|
-
*
|
|
366
|
-
*
|
|
390
|
+
* An array of additional HTTP response [Status Codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) to be treated as errors.
|
|
391
|
+
* By default, status codes >= 500 trigger errors.
|
|
367
392
|
*/
|
|
368
|
-
|
|
393
|
+
additionalHttpErrorStatusCodes?: number[];
|
|
394
|
+
}
|
|
395
|
+
export declare class BasicCrawler<Context extends CrawlingContext = CrawlingContext, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<Context['request']>>, StatisticStateExtension extends object = {}> {
|
|
396
|
+
#private;
|
|
369
397
|
/**
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
* Only available if used by the crawler.
|
|
398
|
+
* The statistics instance collecting the crawler's run statistics - either the injected `statistics` option or a
|
|
399
|
+
* crawler-built default. Typed as {@link IStatistics} so custom implementations can be plugged in.
|
|
373
400
|
*/
|
|
374
|
-
|
|
401
|
+
get statistics(): IStatistics<StatisticStateExtension>;
|
|
375
402
|
/**
|
|
376
|
-
* The main request-handling component of the crawler. It
|
|
403
|
+
* The main request-handling component of the crawler. It manages the requests that the crawler processes,
|
|
404
|
+
* combining any provided request loader and/or queue. It's initialized during the crawler startup or lazily
|
|
405
|
+
* via {@link BasicCrawler.getRequestManager|`getRequestManager()`}.
|
|
377
406
|
*/
|
|
378
|
-
protected requestManager
|
|
407
|
+
protected get requestManager(): IRequestManager | undefined;
|
|
379
408
|
/**
|
|
380
|
-
* A reference to the underlying
|
|
381
|
-
*
|
|
409
|
+
* A reference to the underlying session pool that manages the crawler's {@link Session|sessions}. Typed as
|
|
410
|
+
* {@link ISessionPool} so custom implementations can be plugged in via the `sessionPool` constructor option.
|
|
382
411
|
*/
|
|
383
|
-
sessionPool
|
|
412
|
+
get sessionPool(): ISessionPool;
|
|
413
|
+
/** Whether a {@link BasicCrawler.run|`run()`} is in progress on this instance. */
|
|
414
|
+
get running(): boolean;
|
|
384
415
|
/**
|
|
385
|
-
*
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
*
|
|
389
|
-
*
|
|
416
|
+
* The concurrency governor the run in progress is booking its requests against — either the
|
|
417
|
+
* {@link BasicCrawlerOptions.concurrencySystem|`concurrencySystem`} that was injected, or the default the
|
|
418
|
+
* crawler built for itself. Read it for telemetry: `desiredConcurrency`, `currentConcurrency`, `isRunning`.
|
|
419
|
+
*
|
|
420
|
+
* > *NOTE:* `undefined` outside a run, and a crawler-owned default is rebuilt for every run — so read it
|
|
421
|
+
* during a run rather than caching it across runs.
|
|
422
|
+
*
|
|
423
|
+
* {@link IConcurrencySystem} is deliberately read-only. Tuning concurrency *while a crawl is running* means
|
|
424
|
+
* owning the instance: build a {@link ConcurrencySystem} yourself and inject it, then set
|
|
425
|
+
* `minConcurrency`/`maxConcurrency`/`desiredConcurrency` on your own reference.
|
|
390
426
|
*/
|
|
391
|
-
|
|
427
|
+
get concurrencySystem(): IConcurrencySystem | undefined;
|
|
392
428
|
/**
|
|
393
|
-
* A reference to the underlying {@link
|
|
429
|
+
* A reference to the underlying {@link IProxyConfiguration} instance that manages the crawler's proxies.
|
|
394
430
|
* Only available if used by the crawler.
|
|
395
431
|
*/
|
|
396
|
-
proxyConfiguration?:
|
|
432
|
+
readonly proxyConfiguration?: IProxyConfiguration;
|
|
397
433
|
/**
|
|
398
434
|
* Default {@link Router} instance that will be used if we don't specify any {@link BasicCrawlerOptions.requestHandler|`requestHandler`}.
|
|
399
435
|
* See {@link Router.addHandler|`router.addHandler()`} and {@link Router.addDefaultHandler|`router.addDefaultHandler()`}.
|
|
400
436
|
*/
|
|
401
|
-
readonly router: RouterHandler<Context>;
|
|
402
|
-
|
|
403
|
-
private _contextPipeline?;
|
|
437
|
+
readonly router: RouterHandler<Context, Routes>;
|
|
438
|
+
/** @internal */
|
|
404
439
|
get contextPipeline(): ContextPipeline<CrawlingContext, ExtendedContext>;
|
|
405
|
-
|
|
406
|
-
hasFinishedBefore: boolean;
|
|
407
|
-
|
|
408
|
-
protected requestHandler: RequestHandler<ExtendedContext>;
|
|
409
|
-
protected
|
|
410
|
-
protected
|
|
411
|
-
protected
|
|
412
|
-
protected
|
|
413
|
-
protected
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
protected maxSessionRotations: number;
|
|
418
|
-
protected maxRequestsPerCrawl?: number;
|
|
419
|
-
protected handledRequestsCount: number;
|
|
420
|
-
protected statusMessageLoggingInterval: number;
|
|
421
|
-
protected statusMessageCallback?: StatusMessageCallback;
|
|
422
|
-
protected sessionPoolOptions: SessionPoolOptions;
|
|
423
|
-
protected useSessionPool: boolean;
|
|
424
|
-
protected autoscaledPoolOptions: AutoscaledPoolOptions;
|
|
425
|
-
protected events: EventManager;
|
|
426
|
-
protected httpClient: BaseHttpClient;
|
|
427
|
-
protected retryOnBlocked: boolean;
|
|
428
|
-
protected respectRobotsTxtFile: boolean | {
|
|
429
|
-
userAgent?: string;
|
|
430
|
-
};
|
|
431
|
-
protected onSkippedRequest?: SkippedRequestCallback;
|
|
432
|
-
private _closeEvents?;
|
|
433
|
-
private shouldLogMaxProcessedRequestsExceeded;
|
|
434
|
-
private shouldLogMaxEnqueuedRequestsExceeded;
|
|
435
|
-
private experiments;
|
|
436
|
-
private readonly robotsTxtFileCache;
|
|
437
|
-
private _experimentWarnings;
|
|
438
|
-
private readonly crawlerId;
|
|
439
|
-
private readonly hasExplicitId;
|
|
440
|
+
/** Whether a `run()` on this instance has already finished - a repeated one continues where it left off. */
|
|
441
|
+
get hasFinishedBefore(): boolean;
|
|
442
|
+
get log(): CrawleeLogger;
|
|
443
|
+
protected readonly requestHandler: RequestHandler<ExtendedContext>;
|
|
444
|
+
protected readonly internalTimeoutMillis: number;
|
|
445
|
+
protected blockedStatusCodes: Set<number>;
|
|
446
|
+
protected readonly additionalHttpErrorStatusCodes: Set<number>;
|
|
447
|
+
protected readonly httpClient: BaseHttpClient;
|
|
448
|
+
protected readonly retryOnBlocked: boolean;
|
|
449
|
+
/**
|
|
450
|
+
* @internal
|
|
451
|
+
*/
|
|
440
452
|
protected static optionsShape: {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
onSkippedRequest: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
485
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
486
|
-
httpClient: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
487
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
488
|
-
minConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
489
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
490
|
-
maxConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
491
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
492
|
-
maxRequestsPerMinute: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
493
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
494
|
-
keepAlive: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
|
|
495
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
496
|
-
log: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
497
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
498
|
-
experiments: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
499
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
500
|
-
statisticsOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
501
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
502
|
-
id: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
|
|
453
|
+
contextPipelineBuilder: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
454
|
+
extendContext: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
455
|
+
requestList: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
456
|
+
requestQueue: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
457
|
+
requestManager: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
458
|
+
requestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
459
|
+
requestHandlerTimeoutSecs: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
460
|
+
errorHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
461
|
+
failedRequestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
462
|
+
maxRequestRetries: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
463
|
+
sameDomainDelaySecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
464
|
+
maxRequestsPerCrawl: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
465
|
+
maxCrawlDepth: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
466
|
+
taskLoopOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
467
|
+
concurrencySystem: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
468
|
+
sessionPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
469
|
+
proxyConfiguration: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
470
|
+
statusMessageLoggingInterval: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
471
|
+
statusMessageCallback: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
472
|
+
additionalHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
473
|
+
ignoreHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
474
|
+
blockedStatusCodes: z.ZodOptional<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
475
|
+
retryOnBlocked: z.ZodDefault<z.ZodBoolean>;
|
|
476
|
+
respectRobotsTxtFile: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCustom<Dictionary, Dictionary>]>>;
|
|
477
|
+
transactionalStorage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
478
|
+
requestQueue: z.ZodOptional<z.ZodEnum<{
|
|
479
|
+
deferred: "deferred";
|
|
480
|
+
writeThrough: "writeThrough";
|
|
481
|
+
}>>;
|
|
482
|
+
}, z.core.$strict>]>>;
|
|
483
|
+
onSkippedRequest: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
484
|
+
httpClient: z.ZodOptional<z.ZodInstanceOf<BaseHttpClient>>;
|
|
485
|
+
configuration: z.ZodOptional<z.ZodInstanceOf<Configuration>>;
|
|
486
|
+
storageBackend: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
487
|
+
eventManager: z.ZodOptional<z.ZodInstanceOf<EventManager>>;
|
|
488
|
+
logger: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
489
|
+
minConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
490
|
+
maxConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
491
|
+
initialConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
492
|
+
maxRequestsPerMinute: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
493
|
+
keepAlive: z.ZodOptional<z.ZodBoolean>;
|
|
494
|
+
statistics: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
495
|
+
id: z.ZodOptional<z.ZodString>;
|
|
503
496
|
};
|
|
504
497
|
/**
|
|
505
498
|
* All `BasicCrawler` parameters are passed via an options object.
|
|
506
499
|
*/
|
|
507
|
-
constructor(options?: BasicCrawlerOptions<Context, ContextExtension, ExtendedContext> & RequireContextPipeline<CrawlingContext, Context
|
|
508
|
-
|
|
500
|
+
constructor(options?: BasicCrawlerOptions<Context, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> & RequireContextPipeline<CrawlingContext, Context>);
|
|
501
|
+
/**
|
|
502
|
+
* Builds the crawler-owned default {@link ConcurrencySystem} from the resolved
|
|
503
|
+
* `minConcurrency`/`maxConcurrency`/`initialConcurrency`/`maxRequestsPerMinute` shortcuts. Not called when a
|
|
504
|
+
* {@link BasicCrawlerOptions.concurrencySystem|`concurrencySystem`} was injected.
|
|
505
|
+
*
|
|
506
|
+
* Subclasses may override this to tune the default system (e.g. {@link HttpCrawler} raises the starting
|
|
507
|
+
* concurrency and relaxes the event loop signal) while still honouring the user's shortcuts.
|
|
508
|
+
*/
|
|
509
|
+
protected createDefaultConcurrencySystem(options: ConcurrencySystemOptions): ConcurrencySystem;
|
|
510
|
+
/**
|
|
511
|
+
* Determines if the given HTTP status code is an error status code given
|
|
512
|
+
* the default behaviour and user-set preferences.
|
|
513
|
+
* @param status
|
|
514
|
+
* @returns `true` if the status code is considered an error, `false` otherwise
|
|
515
|
+
*/
|
|
516
|
+
protected isErrorStatusCode(status: number): boolean;
|
|
509
517
|
/**
|
|
510
518
|
* Checks if the given error is a proxy error by comparing its message to a list of known proxy error messages.
|
|
511
519
|
* Used for retrying requests that failed due to proxy errors.
|
|
@@ -514,21 +522,31 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
|
|
|
514
522
|
*/
|
|
515
523
|
protected isProxyError(error: Error): boolean;
|
|
516
524
|
/**
|
|
525
|
+
* Sets the status message for the current crawler run.
|
|
526
|
+
*
|
|
517
527
|
* This method is periodically called by the crawler, every `statusMessageLoggingInterval` seconds.
|
|
528
|
+
*
|
|
529
|
+
* The message is logged and broadcast via the {@link EventType.STATUS_MESSAGE|`statusMessage`}
|
|
530
|
+
* event. Integrations such as the Apify SDK subscribe to that event and forward the message to
|
|
531
|
+
* their status-reporting backend (e.g. the Apify platform).
|
|
518
532
|
*/
|
|
519
|
-
setStatusMessage(message: string, options?: SetStatusMessageOptions):
|
|
520
|
-
private getPeriodicLogger;
|
|
533
|
+
setStatusMessage(message: string, options?: SetStatusMessageOptions): void;
|
|
521
534
|
/**
|
|
522
|
-
* Runs the crawler. Returns a promise that resolves once
|
|
523
|
-
*
|
|
535
|
+
* Runs the crawler. Returns a promise that resolves once every request has been processed and the crawler's
|
|
536
|
+
* finished-check ({@link BasicCrawlerOptions.taskLoopOptions|`taskLoopOptions.isFinishedFunction`}, or the
|
|
537
|
+
* default "the request manager is empty") reports that the crawl is over.
|
|
524
538
|
*
|
|
525
539
|
* We can use the `requests` parameter to enqueue the initial requests — it is a shortcut for
|
|
526
540
|
* running {@link BasicCrawler.addRequests|`crawler.addRequests()`} before {@link BasicCrawler.run|`crawler.run()`}.
|
|
527
541
|
*
|
|
542
|
+
* Calling `run()` again on the same instance keeps crawling the same request manager - requests the previous
|
|
543
|
+
* run handled (a failed one counts as handled) are not processed again. Purge the queue or open a fresh one
|
|
544
|
+
* if that is what you want.
|
|
545
|
+
*
|
|
528
546
|
* @param [requests] The requests to add.
|
|
529
|
-
* @param [options] Options for the
|
|
547
|
+
* @param [options] Options for adding the initial requests.
|
|
530
548
|
*/
|
|
531
|
-
run(requests?:
|
|
549
|
+
run(requests?: TypedRequestsLike<Routes>, options?: CrawlerRunOptions): Promise<FinalStatistics>;
|
|
532
550
|
/**
|
|
533
551
|
* Gracefully stops the current run of the crawler.
|
|
534
552
|
*
|
|
@@ -536,32 +554,57 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
|
|
|
536
554
|
*
|
|
537
555
|
* To stop the crawler immediately, use {@link BasicCrawler.teardown|`crawler.teardown()`} instead.
|
|
538
556
|
*/
|
|
539
|
-
stop(
|
|
540
|
-
|
|
557
|
+
stop(reason?: string): void;
|
|
558
|
+
/**
|
|
559
|
+
* Stops dispatching new requests, letting the in-progress ones finish. Resolves once they have settled, or rejects
|
|
560
|
+
* after `timeoutSecs` if they take too long. Unlike {@link BasicCrawler.stop|`stop()`}, this does not end the
|
|
561
|
+
* run — {@link BasicCrawler.run|`run()`} stays pending until {@link BasicCrawler.resume|`resume()`}.
|
|
562
|
+
*
|
|
563
|
+
* > *NOTE:* The {@link BasicCrawler.concurrencySystem|concurrency system} keeps monitoring and autoscaling
|
|
564
|
+
* throughout, since a shared one may still be serving other crawlers.
|
|
565
|
+
*/
|
|
566
|
+
pause(timeoutSecs?: number): Promise<void>;
|
|
567
|
+
/**
|
|
568
|
+
* Resumes a run suspended with {@link BasicCrawler.pause|`pause()`}, letting the crawler dispatch requests
|
|
569
|
+
* again. A no-op on a crawler that is not paused.
|
|
570
|
+
*/
|
|
571
|
+
resume(): void;
|
|
572
|
+
/**
|
|
573
|
+
* Returns the crawler's {@link IRequestManager|request manager}, opening the default {@link RequestQueue}
|
|
574
|
+
* if none has been configured or opened yet.
|
|
575
|
+
*/
|
|
576
|
+
getRequestManager(): Promise<IRequestManager>;
|
|
577
|
+
/**
|
|
578
|
+
* @deprecated Use {@link BasicCrawler.getRequestManager|`getRequestManager()`} instead. This returns the
|
|
579
|
+
* crawler's request manager, which is no longer guaranteed to be a {@link RequestQueue}.
|
|
580
|
+
*/
|
|
581
|
+
getRequestQueue(): Promise<IRequestManager>;
|
|
541
582
|
useState<State extends Dictionary = Dictionary>(defaultValue?: State): Promise<State>;
|
|
542
|
-
protected get pendingRequestCountApproximation(): number;
|
|
543
|
-
protected calculateEnqueuedRequestLimit(explicitLimit?: number): number | undefined;
|
|
544
|
-
protected handleSkippedRequest(options: Parameters<SkippedRequestCallback>[0]): Promise<void>;
|
|
545
583
|
/**
|
|
546
584
|
* Adds requests to the queue in batches. By default, it will resolve after the initial batch is added, and continue
|
|
547
585
|
* adding the rest in background. You can configure the batch size via `batchSize` option and the sleep time in between
|
|
548
586
|
* the batches via `waitBetweenBatchesMillis`. If you want to wait for all batches to be added to the queue, you can use
|
|
549
587
|
* the `waitForAllRequestsToBeAdded` promise you get in the response object.
|
|
550
588
|
*
|
|
589
|
+
* Optionally, the requests can be filtered using `include`/`exclude` glob or regexp patterns and an
|
|
590
|
+
* enqueue `strategy` (both AND-ed together, same as {@link CrawlingContext.enqueueLinks|`enqueueLinks`}),
|
|
591
|
+
* relative to `baseUrl`. Unlike `enqueueLinks`, there is no implicit "current page" to anchor the strategy
|
|
592
|
+
* to, so `strategy` defaults to {@link EnqueueStrategy.All|`all`} here.
|
|
593
|
+
*
|
|
551
594
|
* This is an alias for calling `addRequestsBatched()` on the implicit `RequestQueue` for this crawler instance.
|
|
552
595
|
*
|
|
553
596
|
* @param requests The requests to add
|
|
554
597
|
* @param options Options for the request queue
|
|
555
598
|
*/
|
|
556
|
-
addRequests(requests: ReadonlyDeep<
|
|
599
|
+
addRequests(requests: ReadonlyDeep<TypedRequestsLike<Routes>>, options?: CrawlerAddRequestsOptions): Promise<CrawlerAddRequestsResult>;
|
|
557
600
|
/**
|
|
558
601
|
* Pushes data to the specified {@link Dataset}, or the default crawler {@link Dataset} by calling {@link Dataset.pushData}.
|
|
559
602
|
*/
|
|
560
|
-
pushData(data: Parameters<Dataset['pushData']>[0],
|
|
603
|
+
pushData(data: Parameters<Dataset['pushData']>[0], datasetIdentifier?: string | StorageIdentifier): Promise<void>;
|
|
561
604
|
/**
|
|
562
605
|
* Retrieves the specified {@link Dataset}, or the default crawler {@link Dataset}.
|
|
563
606
|
*/
|
|
564
|
-
getDataset(
|
|
607
|
+
getDataset(identifier?: string | StorageIdentifier): Promise<Dataset>;
|
|
565
608
|
/**
|
|
566
609
|
* Retrieves data from the default crawler {@link Dataset} by calling {@link Dataset.getData}.
|
|
567
610
|
*/
|
|
@@ -574,112 +617,78 @@ export declare class BasicCrawler<Context extends CrawlingContext = CrawlingCont
|
|
|
574
617
|
/**
|
|
575
618
|
* Initializes the crawler.
|
|
576
619
|
*/
|
|
577
|
-
protected
|
|
578
|
-
protected runRequestHandler(crawlingContext: CrawlingContext): Promise<void>;
|
|
579
|
-
/**
|
|
580
|
-
* Handles blocked request
|
|
581
|
-
*/
|
|
582
|
-
protected _throwOnBlockedRequest(session: Session, statusCode: number): void;
|
|
583
|
-
private isAllowedBasedOnRobotsTxtFile;
|
|
584
|
-
protected getRobotsTxtFileForUrl(url: string): Promise<RobotsTxtFile | undefined>;
|
|
585
|
-
protected _pauseOnMigration(): Promise<void>;
|
|
620
|
+
protected init(): Promise<void>;
|
|
586
621
|
/**
|
|
587
|
-
*
|
|
622
|
+
* The navigation timeout (pre-navigation hooks, navigation, and post-navigation hooks) in milliseconds, used
|
|
623
|
+
* to size the internal request timeout. `BasicCrawler` has no navigation phase, so this is 0; the HTTP and
|
|
624
|
+
* browser crawlers override it with their `navigationTimeoutSecs`.
|
|
588
625
|
*/
|
|
589
|
-
|
|
626
|
+
protected getNavigationTimeoutMillis(): number;
|
|
627
|
+
protected runRequestHandler(crawlingContext: ExtendedContext): Promise<void>;
|
|
590
628
|
/**
|
|
591
|
-
*
|
|
629
|
+
* Runs `callback` inside a {@link StorageTransaction}, unless transactional storage is disabled.
|
|
630
|
+
* Deliberately does **not** commit on return - the pipeline hands failures to `handleRequestFailure`, so a
|
|
631
|
+
* normal return says nothing about success. `handleRequest` commits on success.
|
|
592
632
|
*/
|
|
593
|
-
|
|
633
|
+
private runInStorageTransaction;
|
|
594
634
|
/**
|
|
595
|
-
*
|
|
596
|
-
* adding it back to the queue after the timeout passes. Returns `true` if the request
|
|
597
|
-
* should be ignored and will be reclaimed to the queue once ready.
|
|
598
|
-
*/
|
|
599
|
-
protected delayRequest(request: Request, source: IRequestList | RequestProvider | IRequestManager): boolean;
|
|
600
|
-
/**
|
|
601
|
-
* Wrapper around requestHandler that fetches requests from RequestList/RequestQueue
|
|
602
|
-
* then retries them in a case of an error, etc.
|
|
635
|
+
* Handles blocked request
|
|
603
636
|
*/
|
|
604
|
-
protected
|
|
637
|
+
protected throwOnBlockedRequest(statusCode: number): void;
|
|
605
638
|
/**
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
*
|
|
610
|
-
*
|
|
639
|
+
* Records an HTTP 429 against the URL's domain so the request manager can hold the retry back.
|
|
640
|
+
*
|
|
641
|
+
* @param retryAfterHeader The raw `Retry-After` response header, if the server sent one.
|
|
642
|
+
* @returns `true` if the manager took responsibility for the delay, in which case the caller should throw
|
|
643
|
+
* {@link RequestThrottledError} rather than treating the response as a blocked session.
|
|
611
644
|
*/
|
|
612
|
-
protected
|
|
645
|
+
protected recordDomainRateLimit(url: string, retryAfterHeader?: string | null): boolean;
|
|
646
|
+
/** @internal */
|
|
647
|
+
protected getRobotsTxtFileForUrl(url: string): Promise<RobotsTxtFile | undefined>;
|
|
648
|
+
/** Runs the request handler and marks the request as handled. Failures are left to `handleRequestFailure`. */
|
|
649
|
+
private handleRequest;
|
|
613
650
|
/**
|
|
614
651
|
* Generator function that yields requests injected with the given crawl depth.
|
|
615
652
|
* @internal
|
|
616
653
|
*/
|
|
617
654
|
protected addCrawlDepthRequestGenerator(requests: RequestsLike, newRequestDepth: number): AsyncGenerator<Source, void, undefined>;
|
|
618
|
-
/**
|
|
619
|
-
* Run async callback with given timeout and retry. Returns the result of the callback.
|
|
620
|
-
* @ignore
|
|
621
|
-
*/
|
|
622
|
-
protected _timeoutAndRetry<T>(handler: () => Promise<T>, timeout: number, error: Error | string, maxRetries?: number, retried?: number): Promise<T>;
|
|
623
|
-
/**
|
|
624
|
-
* Returns true if either RequestList or RequestQueue have a request ready for processing.
|
|
625
|
-
*/
|
|
626
|
-
protected _isTaskReadyFunction(): Promise<boolean>;
|
|
627
|
-
/**
|
|
628
|
-
* Returns true if both RequestList and RequestQueue have all requests finished.
|
|
629
|
-
*/
|
|
630
|
-
protected _defaultIsFinishedFunction(): Promise<boolean>;
|
|
631
|
-
private _rotateSession;
|
|
632
|
-
/**
|
|
633
|
-
* Unwraps errors thrown by the context pipeline to get the actual user error.
|
|
634
|
-
* RequestHandlerError and ContextPipelineInitializationError wrap the actual error.
|
|
635
|
-
*/
|
|
636
|
-
private unwrapError;
|
|
637
655
|
/**
|
|
638
656
|
* Handles errors thrown by user provided requestHandler()
|
|
657
|
+
*
|
|
658
|
+
* @param request The request object, passed separately to circumvent potential dynamic logic in crawlingContext.request
|
|
639
659
|
*/
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
protected _handleFailedRequestHandler(crawlingContext: CrawlingContext, error: Error): Promise<void>;
|
|
660
|
+
private requestFunctionErrorHandler;
|
|
661
|
+
private handleFailedRequestHandler;
|
|
643
662
|
/**
|
|
644
663
|
* Resolves the most verbose error message from a thrown error
|
|
645
664
|
* @param error The error received
|
|
646
665
|
* @returns The message to be logged
|
|
647
666
|
*/
|
|
648
|
-
protected
|
|
649
|
-
protected _canRequestBeRetried(request: Request, error: Error): boolean;
|
|
667
|
+
protected getMessageFromError(error: Error, forceStack?: boolean): string;
|
|
650
668
|
/**
|
|
651
|
-
*
|
|
652
|
-
*/
|
|
653
|
-
protected _loadHandledRequestCount(): Promise<void>;
|
|
654
|
-
protected _executeHooks<HookLike extends (...args: any[]) => Awaitable<void>>(hooks: HookLike[], ...args: Parameters<HookLike>): Promise<void>;
|
|
655
|
-
/**
|
|
656
|
-
* Stops the crawler immediately.
|
|
669
|
+
* Ends the run in progress immediately, without waiting for the requests already in flight.
|
|
657
670
|
*
|
|
658
|
-
* This
|
|
671
|
+
* This runs at the end of every {@link BasicCrawler.run|`run()`}, so what it releases is per-run only, and
|
|
672
|
+
* a repeated `run()` has to find everything it needs either intact or re-establishable. What outlives a run is
|
|
673
|
+
* released by {@link BasicCrawler.destroy|`destroy()`} instead.
|
|
659
674
|
*
|
|
660
675
|
* To stop the crawler gracefully (waiting for all running requests to finish), use {@link BasicCrawler.stop|`crawler.stop()`} instead.
|
|
661
676
|
*/
|
|
662
677
|
teardown(): Promise<void>;
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
678
|
+
/**
|
|
679
|
+
* Releases what the crawler owns beyond a single run — in the browser crawlers, the browser pool. A finished
|
|
680
|
+
* `run()` has already released everything a run owns, so this is only needed before dropping a crawler you
|
|
681
|
+
* could otherwise have run again.
|
|
682
|
+
*/
|
|
683
|
+
destroy(): Promise<void>;
|
|
684
|
+
[Symbol.asyncDispose](): Promise<void>;
|
|
685
|
+
protected getCookieHeaderFromRequest(request: Request): string;
|
|
671
686
|
}
|
|
672
|
-
export interface CrawlerAddRequestsOptions extends AddRequestsBatchedOptions {
|
|
687
|
+
export interface CrawlerAddRequestsOptions extends AddRequestsBatchedOptions, EnqueueUrlsOptions {
|
|
673
688
|
}
|
|
674
689
|
export interface CrawlerAddRequestsResult extends AddRequestsBatchedResult {
|
|
675
690
|
}
|
|
676
691
|
export interface CrawlerRunOptions extends CrawlerAddRequestsOptions {
|
|
677
|
-
/**
|
|
678
|
-
* Whether to purge the RequestQueue before running the crawler again. Defaults to true, so it is possible to reprocess failed requests.
|
|
679
|
-
* When disabled, only new requests will be considered. Note that even a failed request is considered as handled.
|
|
680
|
-
* @default true
|
|
681
|
-
*/
|
|
682
|
-
purgeRequestQueue?: boolean;
|
|
683
692
|
}
|
|
684
693
|
/**
|
|
685
694
|
* Creates new {@link Router} instance that works based on request labels.
|
|
@@ -705,5 +714,5 @@ export interface CrawlerRunOptions extends CrawlerAddRequestsOptions {
|
|
|
705
714
|
* await crawler.run();
|
|
706
715
|
* ```
|
|
707
716
|
*/
|
|
708
|
-
export declare function createBasicRouter<Context extends BasicCrawlingContext = BasicCrawlingContext,
|
|
709
|
-
|
|
717
|
+
export declare function createBasicRouter<Context extends BasicCrawlingContext = BasicCrawlingContext, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<Context['request']>>>(routes?: RouterRoutes<Context, Routes>): RouterHandler<Context, Routes>;
|
|
718
|
+
export declare function createBasicRouter<Context extends BasicCrawlingContext = BasicCrawlingContext, UserData extends Dictionary = GetUserDataFromRequest<Context['request']>>(routes?: RouterRoutes<Context, Record<string, UserData>>): RouterHandler<Context, Record<string, UserData>>;
|