@crawlee/basic 3.0.0-beta.9 → 3.0.1-beta.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 +75 -133
- package/index.mjs +69 -0
- package/internals/basic-crawler.d.ts +164 -138
- package/internals/basic-crawler.d.ts.map +1 -1
- package/internals/basic-crawler.js +168 -74
- package/internals/basic-crawler.js.map +1 -1
- package/internals/constants.d.ts +3 -2
- package/internals/constants.d.ts.map +1 -1
- package/internals/constants.js +3 -2
- package/internals/constants.js.map +1 -1
- package/package.json +22 -22
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1,168 +1,154 @@
|
|
|
1
|
-
import { Log } from '@apify/log';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { Awaitable } from '@crawlee/
|
|
6
|
-
export interface
|
|
7
|
-
crawler: BasicCrawler;
|
|
8
|
-
enqueueLinks: (options: BasicCrawlerEnqueueLinksOptions) => Promise<QueueOperationInfo[]>;
|
|
9
|
-
sendRequest: (request?: Request) => Promise<GotResponse<string>>;
|
|
10
|
-
}
|
|
11
|
-
export interface BasicCrawlerHandleFailedRequestInput extends CrawlerHandleFailedRequestInput {
|
|
1
|
+
import type { Log } from '@apify/log';
|
|
2
|
+
import type { AutoscaledPoolOptions, EnqueueLinksOptions, EventManager, FinalStatistics, ProxyInfo, Request, RequestList, RequestOptions, RequestQueueOperationOptions, RouterHandler, Session, SessionPoolOptions } from '@crawlee/core';
|
|
3
|
+
import { AutoscaledPool, Configuration, type CrawlingContext, RequestQueue, SessionPool, Statistics } from '@crawlee/core';
|
|
4
|
+
import type { GotOptionsInit, Response as GotResponse } from 'got-scraping';
|
|
5
|
+
import type { ProcessedRequest, Dictionary, Awaitable, BatchAddRequestsResult } from '@crawlee/types';
|
|
6
|
+
export interface BasicCrawlingContext<UserData extends Dictionary = Dictionary> extends CrawlingContext<UserData> {
|
|
12
7
|
crawler: BasicCrawler;
|
|
8
|
+
enqueueLinks: (options: BasicCrawlerEnqueueLinksOptions) => Promise<BatchAddRequestsResult>;
|
|
9
|
+
sendRequest: (overrideOptions?: Partial<GotOptionsInit>) => Promise<GotResponse<string>>;
|
|
13
10
|
}
|
|
14
11
|
/** @internal */
|
|
15
12
|
export declare type BasicCrawlerEnqueueLinksOptions = Omit<EnqueueLinksOptions, 'requestQueue'>;
|
|
16
|
-
export declare type RequestHandler<Context extends CrawlingContext =
|
|
17
|
-
export declare type FailedRequestHandler<
|
|
18
|
-
export interface BasicCrawlerOptions<Context extends CrawlingContext =
|
|
13
|
+
export declare type RequestHandler<Context extends CrawlingContext = BasicCrawlingContext> = (inputs: Context) => Awaitable<void>;
|
|
14
|
+
export declare type FailedRequestHandler<Context extends CrawlingContext = BasicCrawlingContext> = (inputs: Context, error: Error) => Awaitable<void>;
|
|
15
|
+
export interface BasicCrawlerOptions<Context extends CrawlingContext = BasicCrawlingContext> {
|
|
19
16
|
/**
|
|
20
17
|
* User-provided function that performs the logic of the crawler. It is called for each URL to crawl.
|
|
21
18
|
*
|
|
22
|
-
* The function receives the
|
|
23
|
-
*
|
|
24
|
-
* {
|
|
25
|
-
* request: Request,
|
|
26
|
-
* session: Session,
|
|
27
|
-
* crawler: BasicCrawler,
|
|
28
|
-
* }
|
|
29
|
-
* ```
|
|
30
|
-
* where the {@link Request} instance represents the URL to crawl.
|
|
19
|
+
* The function receives the {@link BasicCrawlingContext} as an argument,
|
|
20
|
+
* where the {@link BasicCrawlingContext.request|`request`} represents the URL to crawl.
|
|
31
21
|
*
|
|
32
22
|
* The function must return a promise, which is then awaited by the crawler.
|
|
33
23
|
*
|
|
34
24
|
* If the function throws an exception, the crawler will try to re-crawl the
|
|
35
|
-
* request later, up to
|
|
25
|
+
* request later, up to the {@link BasicCrawlerOptions.maxRequestRetries|`maxRequestRetries`} times.
|
|
36
26
|
* If all the retries fail, the crawler calls the function
|
|
37
|
-
* provided to the `
|
|
38
|
-
* To make this work,
|
|
39
|
-
* let
|
|
27
|
+
* provided to the {@link BasicCrawlerOptions.failedRequestHandler|`failedRequestHandler`} parameter.
|
|
28
|
+
* To make this work, we should **always**
|
|
29
|
+
* let our function throw exceptions rather than catch them.
|
|
40
30
|
* The exceptions are logged to the request using the
|
|
41
|
-
* {@link Request.pushErrorMessage} function.
|
|
31
|
+
* {@link Request.pushErrorMessage|`Request.pushErrorMessage()`} function.
|
|
42
32
|
*/
|
|
43
|
-
requestHandler
|
|
33
|
+
requestHandler?: RequestHandler<Context>;
|
|
44
34
|
/**
|
|
45
35
|
* User-provided function that performs the logic of the crawler. It is called for each URL to crawl.
|
|
46
36
|
*
|
|
47
|
-
* The function receives the
|
|
48
|
-
*
|
|
49
|
-
* {
|
|
50
|
-
* request: Request,
|
|
51
|
-
* session: Session,
|
|
52
|
-
* crawler: BasicCrawler,
|
|
53
|
-
* }
|
|
54
|
-
* ```
|
|
55
|
-
* where the {@link Request} instance represents the URL to crawl.
|
|
37
|
+
* The function receives the {@link BasicCrawlingContext} as an argument,
|
|
38
|
+
* where the {@link BasicCrawlingContext.request|`request`} represents the URL to crawl.
|
|
56
39
|
*
|
|
57
40
|
* The function must return a promise, which is then awaited by the crawler.
|
|
58
41
|
*
|
|
59
42
|
* If the function throws an exception, the crawler will try to re-crawl the
|
|
60
|
-
* request later, up to
|
|
43
|
+
* request later, up to the {@link BasicCrawlerOptions.maxRequestRetries|`maxRequestRetries`} times.
|
|
61
44
|
* If all the retries fail, the crawler calls the function
|
|
62
|
-
* provided to the `
|
|
63
|
-
* To make this work,
|
|
64
|
-
* let
|
|
45
|
+
* provided to the {@link BasicCrawlerOptions.failedRequestHandler|`failedRequestHandler`} parameter.
|
|
46
|
+
* To make this work, we should **always**
|
|
47
|
+
* let our function throw exceptions rather than catch them.
|
|
65
48
|
* The exceptions are logged to the request using the
|
|
66
|
-
* {@link Request.pushErrorMessage} function.
|
|
49
|
+
* {@link Request.pushErrorMessage|`Request.pushErrorMessage()`} function.
|
|
67
50
|
*
|
|
68
51
|
* @deprecated `handleRequestFunction` has been renamed to `requestHandler` and will be removed in a future version.
|
|
52
|
+
* @ignore
|
|
69
53
|
*/
|
|
70
54
|
handleRequestFunction?: RequestHandler<Context>;
|
|
71
55
|
/**
|
|
72
56
|
* Static list of URLs to be processed.
|
|
73
|
-
*
|
|
57
|
+
* If not provided, the crawler will open the default request queue when the {@link BasicCrawler.addRequests|`crawler.addRequests()`} function is called.
|
|
58
|
+
* > Alternatively, `requests` parameter of {@link BasicCrawler.run|`crawler.run()`} could be used to enqueue the initial requests -
|
|
59
|
+
* it is a shortcut for running `crawler.addRequests()` before the `crawler.run()`.
|
|
74
60
|
*/
|
|
75
61
|
requestList?: RequestList;
|
|
76
62
|
/**
|
|
77
63
|
* Dynamic queue of URLs to be processed. This is useful for recursive crawling of websites.
|
|
78
|
-
*
|
|
64
|
+
* If not provided, the crawler will open the default request queue when the {@link BasicCrawler.addRequests|`crawler.addRequests()`} function is called.
|
|
65
|
+
* > Alternatively, `requests` parameter of {@link BasicCrawler.run|`crawler.run()`} could be used to enqueue the initial requests -
|
|
66
|
+
* it is a shortcut for running `crawler.addRequests()` before the `crawler.run()`.
|
|
79
67
|
*/
|
|
80
68
|
requestQueue?: RequestQueue;
|
|
81
69
|
/**
|
|
82
|
-
* Timeout in which the function passed as
|
|
70
|
+
* Timeout in which the function passed as {@link BasicCrawlerOptions.requestHandler|`requestHandler`} needs to finish, in seconds.
|
|
83
71
|
* @default 60
|
|
84
72
|
*/
|
|
85
73
|
requestHandlerTimeoutSecs?: number;
|
|
86
74
|
/**
|
|
87
|
-
* Timeout in which the function passed as
|
|
75
|
+
* Timeout in which the function passed as {@link BasicCrawlerOptions.requestHandler|`requestHandler`} needs to finish, in seconds.
|
|
88
76
|
* @default 60
|
|
89
77
|
* @deprecated `handleRequestTimeoutSecs` has been renamed to `requestHandlerTimeoutSecs` and will be removed in a future version.
|
|
78
|
+
* @ignore
|
|
90
79
|
*/
|
|
91
80
|
handleRequestTimeoutSecs?: number;
|
|
92
81
|
/**
|
|
93
|
-
*
|
|
82
|
+
* User-provided function that allows modifying the request object before it gets retried by the crawler.
|
|
83
|
+
* It's executed before each retry for the requests that failed less than {@link BasicCrawlerOptions.maxRequestRetries|`maxRequestRetries`} times.
|
|
94
84
|
*
|
|
95
|
-
* The function receives the
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* request: Request,
|
|
99
|
-
* error: Error,
|
|
100
|
-
* session: Session,
|
|
101
|
-
* crawler: BasicCrawler,
|
|
102
|
-
* }
|
|
103
|
-
* ```
|
|
104
|
-
* where the {@link Request} instance corresponds to the failed request, and the `Error` instance
|
|
85
|
+
* The function receives the {@link BasicCrawlingContext} as the first argument,
|
|
86
|
+
* where the {@link BasicCrawlingContext.request|`request`} corresponds to the request to be retried.
|
|
87
|
+
* Second argument is the `Error` instance that
|
|
105
88
|
* represents the last error thrown during processing of the request.
|
|
106
|
-
*
|
|
107
|
-
* See
|
|
108
|
-
* [source code](https://github.com/apify/apify-js/blob/master/src/crawlers/basic_crawler.js#L11)
|
|
109
|
-
* for the default implementation of this function.
|
|
110
89
|
*/
|
|
111
|
-
|
|
90
|
+
errorHandler?: FailedRequestHandler<Context>;
|
|
112
91
|
/**
|
|
113
|
-
* A function to handle requests that failed more than
|
|
92
|
+
* A function to handle requests that failed more than {@link BasicCrawlerOptions.maxRequestRetries|`maxRequestRetries`} times.
|
|
114
93
|
*
|
|
115
|
-
* The function receives the
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* request: Request,
|
|
119
|
-
* error: Error,
|
|
120
|
-
* session: Session,
|
|
121
|
-
* crawler: BasicCrawler,
|
|
122
|
-
* }
|
|
123
|
-
* ```
|
|
124
|
-
* where the {@link Request} instance corresponds to the failed request, and the `Error` instance
|
|
94
|
+
* The function receives the {@link BasicCrawlingContext} as the first argument,
|
|
95
|
+
* where the {@link BasicCrawlingContext.request|`request`} corresponds to the failed request.
|
|
96
|
+
* Second argument is the `Error` instance that
|
|
125
97
|
* represents the last error thrown during processing of the request.
|
|
98
|
+
*/
|
|
99
|
+
failedRequestHandler?: FailedRequestHandler<Context>;
|
|
100
|
+
/**
|
|
101
|
+
* A function to handle requests that failed more than {@link BasicCrawlerOptions.maxRequestRetries|`maxRequestRetries`} times.
|
|
126
102
|
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
103
|
+
* The function receives the {@link BasicCrawlingContext} as the first argument,
|
|
104
|
+
* where the {@link BasicCrawlingContext.request|`request`} corresponds to the failed request.
|
|
105
|
+
* Second argument is the `Error` instance that
|
|
106
|
+
* represents the last error thrown during processing of the request.
|
|
130
107
|
*
|
|
131
108
|
* @deprecated `handleFailedRequestFunction` has been renamed to `failedRequestHandler` and will be removed in a future version.
|
|
109
|
+
* @ignore
|
|
132
110
|
*/
|
|
133
|
-
handleFailedRequestFunction?: FailedRequestHandler<
|
|
111
|
+
handleFailedRequestFunction?: FailedRequestHandler<Context>;
|
|
134
112
|
/**
|
|
135
|
-
* Indicates how many times the request is retried if {@link requestHandler}
|
|
113
|
+
* Indicates how many times the request is retried if {@link BasicCrawlerOptions.requestHandler|`requestHandler`} fails.
|
|
136
114
|
* @default 3
|
|
137
115
|
*/
|
|
138
116
|
maxRequestRetries?: number;
|
|
139
117
|
/**
|
|
140
118
|
* Maximum number of pages that the crawler will open. The crawl will stop when this limit is reached.
|
|
141
|
-
*
|
|
142
|
-
*
|
|
119
|
+
* This value should always be set in order to prevent infinite loops in misconfigured crawlers.
|
|
120
|
+
* > *NOTE:* In cases of parallel crawling, the actual number of pages visited might be slightly higher than this value.
|
|
143
121
|
*/
|
|
144
122
|
maxRequestsPerCrawl?: number;
|
|
145
123
|
/**
|
|
146
124
|
* Custom options passed to the underlying {@link AutoscaledPool} constructor.
|
|
147
|
-
*
|
|
125
|
+
* > *NOTE:* The {@link AutoscaledPoolOptions.runTaskFunction|`runTaskFunction`}
|
|
126
|
+
* and {@link AutoscaledPoolOptions.isTaskReadyFunction|`isTaskReadyFunction`} options
|
|
148
127
|
* are provided by the crawler and cannot be overridden.
|
|
149
|
-
* However,
|
|
128
|
+
* However, we can provide a custom implementation of {@link AutoscaledPoolOptions.isFinishedFunction|`isFinishedFunction`}.
|
|
150
129
|
*/
|
|
151
130
|
autoscaledPoolOptions?: AutoscaledPoolOptions;
|
|
152
131
|
/**
|
|
153
|
-
* Sets the minimum concurrency (parallelism) for the crawl. Shortcut
|
|
154
|
-
*
|
|
155
|
-
* *WARNING:* If
|
|
156
|
-
* If
|
|
132
|
+
* Sets the minimum concurrency (parallelism) for the crawl. Shortcut for the
|
|
133
|
+
* AutoscaledPool {@link AutoscaledPoolOptions.minConcurrency|`minConcurrency`} option.
|
|
134
|
+
* > *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.
|
|
135
|
+
* If not sure, it's better to keep the default value and the concurrency will scale up automatically.
|
|
157
136
|
*/
|
|
158
137
|
minConcurrency?: number;
|
|
159
138
|
/**
|
|
160
|
-
* Sets the maximum concurrency (parallelism) for the crawl. Shortcut
|
|
139
|
+
* Sets the maximum concurrency (parallelism) for the crawl. Shortcut for the
|
|
140
|
+
* AutoscaledPool {@link AutoscaledPoolOptions.maxConcurrency|`maxConcurrency`} option.
|
|
161
141
|
*/
|
|
162
142
|
maxConcurrency?: number;
|
|
163
143
|
/**
|
|
164
|
-
*
|
|
165
|
-
*
|
|
144
|
+
* The maximum number of requests per minute the crawler should run.
|
|
145
|
+
* By default, this is set to `Infinity`, but we can pass any positive, non-zero integer.
|
|
146
|
+
* Shortcut for the AutoscaledPool {@link AutoscaledPoolOptions.maxTasksPerMinute|`maxTasksPerMinute`} option.
|
|
147
|
+
*/
|
|
148
|
+
maxRequestsPerMinute?: number;
|
|
149
|
+
/**
|
|
150
|
+
* Basic crawler will initialize the {@link SessionPool} with the corresponding {@link SessionPoolOptions|`sessionPoolOptions`}.
|
|
151
|
+
* The session instance will be than available in the {@link BasicCrawlerOptions.requestHandler|`requestHandler`}.
|
|
166
152
|
*/
|
|
167
153
|
useSessionPool?: boolean;
|
|
168
154
|
/**
|
|
@@ -179,100 +165,103 @@ export interface BasicCrawlerOptions<Context extends CrawlingContext = BasicCraw
|
|
|
179
165
|
*
|
|
180
166
|
* `BasicCrawler` is a low-level tool that requires the user to implement the page
|
|
181
167
|
* download and data extraction functionality themselves.
|
|
182
|
-
* If
|
|
183
|
-
*
|
|
168
|
+
* If we want a crawler that already facilitates this functionality,
|
|
169
|
+
* we should consider using {@link CheerioCrawler}, {@link PuppeteerCrawler} or {@link PlaywrightCrawler}.
|
|
184
170
|
*
|
|
185
|
-
* `BasicCrawler` invokes the user-provided {@link BasicCrawlerOptions.requestHandler}
|
|
171
|
+
* `BasicCrawler` invokes the user-provided {@link BasicCrawlerOptions.requestHandler|`requestHandler`}
|
|
186
172
|
* for each {@link Request} object, which represents a single URL to crawl.
|
|
187
|
-
* The {@link Request} objects are fed from the {@link RequestList} or
|
|
188
|
-
* instances provided by the {@link BasicCrawlerOptions.requestList} or {@link BasicCrawlerOptions.requestQueue}
|
|
189
|
-
* constructor options, respectively.
|
|
173
|
+
* The {@link Request} objects are fed from the {@link RequestList} or {@link RequestQueue}
|
|
174
|
+
* instances provided by the {@link BasicCrawlerOptions.requestList|`requestList`} or {@link BasicCrawlerOptions.requestQueue|`requestQueue`}
|
|
175
|
+
* constructor options, respectively. If neither `requestList` nor `requestQueue` options are provided,
|
|
176
|
+
* the crawler will open the default request queue either when the {@link BasicCrawler.addRequests|`crawler.addRequests()`} function is called,
|
|
177
|
+
* or if `requests` parameter (representing the initial requests) of the {@link BasicCrawler.run|`crawler.run()`} function is provided.
|
|
190
178
|
*
|
|
191
|
-
* If both {@link BasicCrawlerOptions.requestList} and {@link BasicCrawlerOptions.requestQueue} options are used,
|
|
179
|
+
* If both {@link BasicCrawlerOptions.requestList|`requestList`} and {@link BasicCrawlerOptions.requestQueue|`requestQueue`} options are used,
|
|
192
180
|
* the instance first processes URLs from the {@link RequestList} and automatically enqueues all of them
|
|
193
|
-
* to {@link RequestQueue} before it starts their processing. This ensures that a single URL is not crawled multiple times.
|
|
181
|
+
* to the {@link RequestQueue} before it starts their processing. This ensures that a single URL is not crawled multiple times.
|
|
194
182
|
*
|
|
195
183
|
* The crawler finishes if there are no more {@link Request} objects to crawl.
|
|
196
184
|
*
|
|
197
185
|
* New requests are only dispatched when there is enough free CPU and memory available,
|
|
198
186
|
* using the functionality provided by the {@link AutoscaledPool} class.
|
|
199
|
-
* All {@link AutoscaledPool} configuration options can be passed to the
|
|
200
|
-
* parameter of the `BasicCrawler` constructor.
|
|
201
|
-
*
|
|
187
|
+
* All {@link AutoscaledPool} configuration options can be passed to the {@link BasicCrawlerOptions.autoscaledPoolOptions|`autoscaledPoolOptions`}
|
|
188
|
+
* parameter of the `BasicCrawler` constructor.
|
|
189
|
+
* For user convenience, the {@link AutoscaledPoolOptions.minConcurrency|`minConcurrency`} and
|
|
190
|
+
* {@link AutoscaledPoolOptions.maxConcurrency|`maxConcurrency`} options of the
|
|
191
|
+
* underlying {@link AutoscaledPool} constructor are available directly in the `BasicCrawler` constructor.
|
|
202
192
|
*
|
|
203
193
|
* **Example usage:**
|
|
204
194
|
*
|
|
205
195
|
* ```javascript
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
* // Prepare a list of URLs to crawl
|
|
209
|
-
* const requestList = new RequestList({
|
|
210
|
-
* sources: [
|
|
211
|
-
* { url: 'http://www.example.com/page-1' },
|
|
212
|
-
* { url: 'http://www.example.com/page-2' },
|
|
213
|
-
* ],
|
|
214
|
-
* });
|
|
215
|
-
* await requestList.initialize();
|
|
196
|
+
* import { BasicCrawler, Dataset } from 'crawlee';
|
|
216
197
|
*
|
|
217
|
-
* //
|
|
198
|
+
* // Create a crawler instance
|
|
218
199
|
* const crawler = new BasicCrawler({
|
|
219
|
-
*
|
|
220
|
-
* async requestHandler({ request }) {
|
|
200
|
+
* async requestHandler({ request, sendRequest }) {
|
|
221
201
|
* // 'request' contains an instance of the Request class
|
|
222
202
|
* // Here we simply fetch the HTML of the page and store it to a dataset
|
|
223
|
-
* const { body } = await
|
|
203
|
+
* const { body } = await sendRequest({
|
|
224
204
|
* url: request.url,
|
|
225
205
|
* method: request.method,
|
|
226
206
|
* body: request.payload,
|
|
227
207
|
* headers: request.headers,
|
|
228
208
|
* });
|
|
229
209
|
*
|
|
230
|
-
* await
|
|
210
|
+
* await Dataset.pushData({
|
|
231
211
|
* url: request.url,
|
|
232
212
|
* html: body,
|
|
233
213
|
* })
|
|
234
214
|
* },
|
|
235
215
|
* });
|
|
236
216
|
*
|
|
237
|
-
*
|
|
217
|
+
* // Enqueue the initial requests and run the crawler
|
|
218
|
+
* await crawler.run([
|
|
219
|
+
* 'http://www.example.com/page-1',
|
|
220
|
+
* 'http://www.example.com/page-2',
|
|
221
|
+
* ]);
|
|
238
222
|
* ```
|
|
239
223
|
* @category Crawlers
|
|
240
224
|
*/
|
|
241
|
-
export declare class BasicCrawler<Context extends CrawlingContext =
|
|
225
|
+
export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawlingContext> {
|
|
242
226
|
readonly config: Configuration;
|
|
227
|
+
private static readonly CRAWLEE_STATE_KEY;
|
|
243
228
|
/**
|
|
244
|
-
*
|
|
229
|
+
* A reference to the underlying {@link Statistics} class that collects and logs run statistics for requests.
|
|
245
230
|
*/
|
|
246
231
|
readonly stats: Statistics;
|
|
247
232
|
/**
|
|
248
|
-
* A reference to the underlying {@link RequestList} class that manages the crawler's {@link Request}
|
|
249
|
-
* Either `requestList` or `requestQueue` option must be provided (or both).
|
|
233
|
+
* A reference to the underlying {@link RequestList} class that manages the crawler's {@link Request|requests}.
|
|
250
234
|
* Only available if used by the crawler.
|
|
251
235
|
*/
|
|
252
236
|
requestList?: RequestList;
|
|
253
237
|
/**
|
|
254
238
|
* Dynamic queue of URLs to be processed. This is useful for recursive crawling of websites.
|
|
255
|
-
* A reference to the underlying {@link RequestQueue} class that manages the crawler's {@link Request}
|
|
256
|
-
* Either `requestList` or `requestQueue` option must be provided (or both).
|
|
239
|
+
* A reference to the underlying {@link RequestQueue} class that manages the crawler's {@link Request|requests}.
|
|
257
240
|
* Only available if used by the crawler.
|
|
258
241
|
*/
|
|
259
242
|
requestQueue?: RequestQueue;
|
|
260
243
|
/**
|
|
261
|
-
* A reference to the underlying {@link SessionPool} class that manages the crawler's {@link Session}
|
|
244
|
+
* A reference to the underlying {@link SessionPool} class that manages the crawler's {@link Session|sessions}.
|
|
262
245
|
* Only available if used by the crawler.
|
|
263
246
|
*/
|
|
264
247
|
sessionPool?: SessionPool;
|
|
265
248
|
/**
|
|
266
249
|
* A reference to the underlying {@link AutoscaledPool} class that manages the concurrency of the crawler.
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
* to pause the crawler by calling {@link AutoscaledPool.pause}
|
|
270
|
-
* or to abort it by calling {@link AutoscaledPool.abort}.
|
|
250
|
+
* > *NOTE:* This property is only initialized after calling the {@link BasicCrawler.run|`crawler.run()`} function.
|
|
251
|
+
* We can use it to change the concurrency settings on the fly,
|
|
252
|
+
* to pause the crawler by calling {@link AutoscaledPool.pause|`autoscaledPool.pause()`}
|
|
253
|
+
* or to abort it by calling {@link AutoscaledPool.abort|`autoscaledPool.abort()`}.
|
|
271
254
|
*/
|
|
272
255
|
autoscaledPool?: AutoscaledPool;
|
|
256
|
+
/**
|
|
257
|
+
* Default {@link Router} instance that will be used if we don't specify any {@link BasicCrawlerOptions.requestHandler|`requestHandler`}.
|
|
258
|
+
* See {@link Router.addHandler|`router.addHandler()`} and {@link Router.addDefaultHandler|`router.addDefaultHandler()`}.
|
|
259
|
+
*/
|
|
260
|
+
readonly router: RouterHandler<Context>;
|
|
273
261
|
protected log: Log;
|
|
274
262
|
protected requestHandler: RequestHandler<Context>;
|
|
275
|
-
protected
|
|
263
|
+
protected errorHandler?: FailedRequestHandler<Context>;
|
|
264
|
+
protected failedRequestHandler?: FailedRequestHandler<Context>;
|
|
276
265
|
protected requestHandlerTimeoutMillis: number;
|
|
277
266
|
protected internalTimeoutMillis: number;
|
|
278
267
|
protected maxRequestRetries: number;
|
|
@@ -282,6 +271,7 @@ export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawler
|
|
|
282
271
|
protected crawlingContexts: Map<string, Context>;
|
|
283
272
|
protected autoscaledPoolOptions: AutoscaledPoolOptions;
|
|
284
273
|
protected events: EventManager;
|
|
274
|
+
private _closeEvents?;
|
|
285
275
|
protected static optionsShape: {
|
|
286
276
|
requestList: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
287
277
|
requestQueue: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
@@ -289,6 +279,7 @@ export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawler
|
|
|
289
279
|
handleRequestFunction: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
290
280
|
requestHandlerTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
291
281
|
handleRequestTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
282
|
+
errorHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
292
283
|
failedRequestHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
293
284
|
handleFailedRequestFunction: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
294
285
|
maxRequestRetries: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
@@ -298,17 +289,24 @@ export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawler
|
|
|
298
289
|
useSessionPool: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
|
|
299
290
|
minConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
300
291
|
maxConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
292
|
+
maxRequestsPerMinute: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
301
293
|
log: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
302
294
|
};
|
|
303
295
|
/**
|
|
304
296
|
* All `BasicCrawler` parameters are passed via an options object.
|
|
305
297
|
*/
|
|
306
|
-
constructor(options
|
|
298
|
+
constructor(options?: BasicCrawlerOptions<Context>, config?: Configuration);
|
|
307
299
|
/**
|
|
308
300
|
* Runs the crawler. Returns a promise that gets resolved once all the requests are processed.
|
|
301
|
+
* We can use the `requests` parameter to enqueue the initial requests - it is a shortcut for
|
|
302
|
+
* running {@link BasicCrawler.addRequests|`crawler.addRequests()`} before the {@link BasicCrawler.run|`crawler.run()`}.
|
|
303
|
+
*
|
|
304
|
+
* @param [requests] The requests to add
|
|
305
|
+
* @param [options] Options for the request queue
|
|
309
306
|
*/
|
|
310
|
-
run(): Promise<FinalStatistics>;
|
|
307
|
+
run(requests?: (string | Request | RequestOptions)[], options?: CrawlerAddRequestsOptions): Promise<FinalStatistics>;
|
|
311
308
|
getRequestQueue(): Promise<RequestQueue>;
|
|
309
|
+
useState<State extends Dictionary = Dictionary>(defaultValue?: State): Promise<State>;
|
|
312
310
|
/**
|
|
313
311
|
* Adds requests to be processed by the crawler
|
|
314
312
|
* @param requests The requests to add
|
|
@@ -326,7 +324,7 @@ export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawler
|
|
|
326
324
|
* Fetches request from either RequestList or RequestQueue. If request comes from a RequestList
|
|
327
325
|
* and RequestQueue is present then enqueues it to the queue first.
|
|
328
326
|
*/
|
|
329
|
-
protected _fetchNextRequest(): Promise<Request | null>;
|
|
327
|
+
protected _fetchNextRequest(): Promise<Request<Dictionary<any>> | null>;
|
|
330
328
|
/**
|
|
331
329
|
* Wrapper around requestHandler that fetches requests from RequestList/RequestQueue
|
|
332
330
|
* then retries them in a case of an error, etc.
|
|
@@ -349,7 +347,8 @@ export declare class BasicCrawler<Context extends CrawlingContext = BasicCrawler
|
|
|
349
347
|
* Handles errors thrown by user provided requestHandler()
|
|
350
348
|
*/
|
|
351
349
|
protected _requestFunctionErrorHandler(error: Error, crawlingContext: Context, source: RequestList | RequestQueue): Promise<void>;
|
|
352
|
-
protected
|
|
350
|
+
protected _tagUserHandlerError<T>(cb: () => unknown): Promise<T>;
|
|
351
|
+
protected _handleFailedRequestHandler(crawlingContext: Context, error: Error): Promise<void>;
|
|
353
352
|
/**
|
|
354
353
|
* Updates handledRequestsCount from possibly stored counts,
|
|
355
354
|
* usually after worker migration. Since one of the stores
|
|
@@ -376,8 +375,7 @@ export interface CreateContextOptions {
|
|
|
376
375
|
export interface CrawlerAddRequestsOptions extends RequestQueueOperationOptions {
|
|
377
376
|
/**
|
|
378
377
|
* Whether to wait for all the provided requests to be added, instead of waiting just for the initial batch of up to 1000.
|
|
379
|
-
|
|
380
|
-
* By default, this is set to `false`.
|
|
378
|
+
@default false
|
|
381
379
|
*/
|
|
382
380
|
waitForAllRequestsToBeAdded?: boolean;
|
|
383
381
|
}
|
|
@@ -386,13 +384,16 @@ export interface CrawlerAddRequestsResult {
|
|
|
386
384
|
/**
|
|
387
385
|
* A promise which will resolve with the rest of the requests that were added to the queue.
|
|
388
386
|
*
|
|
389
|
-
* @
|
|
387
|
+
* Alternatively, we can set {@link CrawlerAddRequestsOptions.waitForAllRequestsToBeAdded|`waitForAllRequestsToBeAdded`} to `true`
|
|
388
|
+
* in the {@link BasicCrawler.addRequests|`crawler.addRequests()`} options.
|
|
389
|
+
*
|
|
390
|
+
* **Example:**
|
|
391
|
+
*
|
|
390
392
|
* ```ts
|
|
391
393
|
* // Assuming `requests` is a list of requests.
|
|
392
394
|
* const result = await crawler.addRequests(requests);
|
|
393
395
|
*
|
|
394
|
-
* // If
|
|
395
|
-
* // Alternatively, consider setting `waitForAllRequestsToBeAdded` to `true` in the options for `addRequests`.
|
|
396
|
+
* // If we want to wait for the rest of the requests to be added to the queue:
|
|
396
397
|
* await result.waitForAllRequestsToBeAdded;
|
|
397
398
|
* ```
|
|
398
399
|
*/
|
|
@@ -406,5 +407,30 @@ interface HandlePropertyNameChangeData<New, Old> {
|
|
|
406
407
|
propertyKey: string;
|
|
407
408
|
allowUndefined?: boolean;
|
|
408
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* Creates new {@link Router} instance that works based on request labels.
|
|
412
|
+
* This instance can then serve as a {@link BasicCrawlerOptions.requestHandler|`requestHandler`} of our {@link BasicCrawler}.
|
|
413
|
+
* Defaults to the {@link BasicCrawlingContext}.
|
|
414
|
+
*
|
|
415
|
+
* > Serves as a shortcut for using `Router.create<BasicCrawlingContext>()`.
|
|
416
|
+
*
|
|
417
|
+
* ```ts
|
|
418
|
+
* import { BasicCrawler, createBasicRouter } from 'crawlee';
|
|
419
|
+
*
|
|
420
|
+
* const router = createBasicRouter();
|
|
421
|
+
* router.addHandler('label-a', async (ctx) => {
|
|
422
|
+
* ctx.log.info('...');
|
|
423
|
+
* });
|
|
424
|
+
* router.addDefaultHandler(async (ctx) => {
|
|
425
|
+
* ctx.log.info('...');
|
|
426
|
+
* });
|
|
427
|
+
*
|
|
428
|
+
* const crawler = new BasicCrawler({
|
|
429
|
+
* requestHandler: router,
|
|
430
|
+
* });
|
|
431
|
+
* await crawler.run();
|
|
432
|
+
* ```
|
|
433
|
+
*/
|
|
434
|
+
export declare function createBasicRouter<Context extends BasicCrawlingContext = BasicCrawlingContext>(): RouterHandler<Context>;
|
|
409
435
|
export {};
|
|
410
436
|
//# sourceMappingURL=basic-crawler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"basic-crawler.d.ts","sourceRoot":"","sources":["../../src/internals/basic-crawler.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"basic-crawler.d.ts","sourceRoot":"","sources":["../../src/internals/basic-crawler.ts"],"names":[],"mappings":"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"}
|