@crawlee/browser 3.0.0-beta.9 → 3.0.0
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 +7 -0
- package/internals/browser-crawler.d.ts +109 -135
- package/internals/browser-crawler.d.ts.map +1 -1
- package/internals/browser-crawler.js +39 -28
- package/internals/browser-crawler.js.map +1 -1
- package/internals/browser-launcher.d.ts +10 -8
- package/internals/browser-launcher.d.ts.map +1 -1
- package/internals/browser-launcher.js +13 -10
- package/internals/browser-launcher.js.map +1 -1
- package/package.json +17 -14
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1,171 +1,141 @@
|
|
|
1
|
-
import { EnqueueLinksOptions,
|
|
2
|
-
import {
|
|
3
|
-
import { Awaitable, Dictionary } from '@crawlee/
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
1
|
+
import type { EnqueueLinksOptions, CrawlingContext, ProxyConfiguration, RequestQueue } from '@crawlee/core';
|
|
2
|
+
import { Configuration } from '@crawlee/core';
|
|
3
|
+
import type { BasicCrawlerOptions, Awaitable, Dictionary } from '@crawlee/basic';
|
|
4
|
+
import { BasicCrawler } from '@crawlee/basic';
|
|
5
|
+
import type { BrowserController, BrowserPlugin, BrowserPoolHooks, BrowserPoolOptions, CommonPage, InferBrowserPluginArray, LaunchContext } from '@crawlee/browser-pool';
|
|
6
|
+
import { BrowserPool } from '@crawlee/browser-pool';
|
|
7
|
+
import type { GotOptionsInit, Response as GotResponse } from 'got-scraping';
|
|
8
|
+
import type { BatchAddRequestsResult } from '@crawlee/types';
|
|
9
|
+
import type { BrowserLaunchContext } from './browser-launcher';
|
|
10
|
+
export interface BrowserCrawlingContext<Page extends CommonPage = CommonPage, Response = Dictionary, ProvidedController = BrowserController, UserData extends Dictionary = Dictionary> extends CrawlingContext<UserData> {
|
|
8
11
|
browserController: ProvidedController;
|
|
9
12
|
page: Page;
|
|
10
13
|
response?: Response;
|
|
11
14
|
crawler: BrowserCrawler;
|
|
12
15
|
enqueueLinks: (options?: BrowserCrawlerEnqueueLinksOptions) => Promise<BatchAddRequestsResult>;
|
|
16
|
+
sendRequest: (overrideOptions?: Partial<GotOptionsInit>) => Promise<GotResponse<string>>;
|
|
13
17
|
}
|
|
14
|
-
export interface BrowserCrawlerHandleFailedRequestInput extends CrawlerHandleFailedRequestInput {
|
|
15
|
-
crawler: BrowserCrawler;
|
|
16
|
-
}
|
|
17
|
-
export declare type BrowserCrawlerHandleFailedRequest = (inputs: BrowserCrawlerHandleFailedRequestInput) => Awaitable<void>;
|
|
18
18
|
export declare type BrowserCrawlerHandleRequest<Context extends BrowserCrawlingContext = BrowserCrawlingContext> = (inputs: Context) => Awaitable<void>;
|
|
19
|
+
export declare type BrowserCrawlerHandleFailedRequest<Context extends BrowserCrawlingContext = BrowserCrawlingContext> = (inputs: Context, error: Error) => Awaitable<void>;
|
|
19
20
|
export declare type BrowserCrawlerEnqueueLinksOptions = Omit<EnqueueLinksOptions, 'requestQueue' | 'urls'>;
|
|
20
21
|
export declare type BrowserHook<Context = BrowserCrawlingContext, GoToOptions extends Record<PropertyKey, any> | undefined = Dictionary> = (crawlingContext: Context, gotoOptions: GoToOptions) => Awaitable<void>;
|
|
21
|
-
export interface BrowserCrawlerOptions<Context extends BrowserCrawlingContext = BrowserCrawlingContext, InternalBrowserPoolOptions extends BrowserPoolOptions = BrowserPoolOptions, __BrowserPlugins extends BrowserPlugin[] = InferBrowserPluginArray<InternalBrowserPoolOptions['browserPlugins']>, __BrowserControllerReturn extends BrowserController = ReturnType<__BrowserPlugins[number]['createController']>, __LaunchContextReturn extends LaunchContext = ReturnType<__BrowserPlugins[number]['createLaunchContext']>> extends Omit<BasicCrawlerOptions, 'requestHandler' | 'handleRequestFunction' | 'failedRequestHandler' | 'handleFailedRequestFunction'> {
|
|
22
|
+
export interface BrowserCrawlerOptions<Context extends BrowserCrawlingContext = BrowserCrawlingContext, InternalBrowserPoolOptions extends BrowserPoolOptions = BrowserPoolOptions, __BrowserPlugins extends BrowserPlugin[] = InferBrowserPluginArray<InternalBrowserPoolOptions['browserPlugins']>, __BrowserControllerReturn extends BrowserController = ReturnType<__BrowserPlugins[number]['createController']>, __LaunchContextReturn extends LaunchContext = ReturnType<__BrowserPlugins[number]['createLaunchContext']>> extends Omit<BasicCrawlerOptions, 'requestHandler' | 'handleRequestFunction' | 'failedRequestHandler' | 'handleFailedRequestFunction' | 'errorHandler'> {
|
|
22
23
|
launchContext?: BrowserLaunchContext<any, any>;
|
|
23
24
|
/**
|
|
24
25
|
* Function that is called to process each request.
|
|
25
|
-
* It is passed an object with the following fields:
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
27
|
+
* The function receives the {@link BrowserCrawlingContext}
|
|
28
|
+
* (actual context will be enhanced with the crawler specific properties) as an argument, where:
|
|
29
|
+
* - {@link BrowserCrawlingContext.request|`request`} is an instance of the {@link Request} object
|
|
30
|
+
* with details about the URL to open, HTTP method etc;
|
|
31
|
+
* - {@link BrowserCrawlingContext.page|`page`} is an instance of the
|
|
32
|
+
* Puppeteer [Page](https://pptr.dev/api/puppeteer.page) or
|
|
33
|
+
* Playwright [Page](https://playwright.dev/docs/api/class-page);
|
|
34
|
+
* - {@link BrowserCrawlingContext.browserController|`browserController`} is an instance of the {@link BrowserController};
|
|
35
|
+
* - {@link BrowserCrawlingContext.response|`response`} is an instance of the
|
|
36
|
+
* Puppeteer [Response](https://pptr.dev/api/puppeteer.httpresponse) or
|
|
37
|
+
* Playwright [Response](https://playwright.dev/docs/api/class-response),
|
|
38
|
+
* which is the main resource response as returned by the respective `page.goto()` function.
|
|
38
39
|
*
|
|
39
|
-
* `request` is an instance of the {@link Request} object with details about the URL to open, HTTP method etc.
|
|
40
|
-
* `page` is an instance of the `Puppeteer`
|
|
41
|
-
* [`Page`](https://pptr.dev/#?product=Puppeteer&show=api-class-page) or `Playwright`
|
|
42
|
-
* [`Page`](https://playwright.dev/docs/api/class-page)
|
|
43
|
-
* `browserPool` is an instance of the
|
|
44
|
-
* [`BrowserPool`](https://github.com/apify/browser-pool#BrowserPool),
|
|
45
|
-
* `browserController` is an instance of the
|
|
46
|
-
* [`BrowserController`](https://github.com/apify/browser-pool#browsercontroller),
|
|
47
|
-
* `response` is an instance of the `Puppeteer`
|
|
48
|
-
* [`Response`](https://pptr.dev/#?product=Puppeteer&show=api-class-response) or `Playwright`
|
|
49
|
-
* [`Response`](https://playwright.dev/docs/api/class-response),
|
|
50
|
-
* which is the main resource response as returned by `page.goto(request.url)`.
|
|
51
40
|
* The function must return a promise, which is then awaited by the crawler.
|
|
52
41
|
*
|
|
53
42
|
* If the function throws an exception, the crawler will try to re-crawl the
|
|
54
|
-
* request later, up to
|
|
43
|
+
* request later, up to the {@link BrowserCrawlerOptions.maxRequestRetries|`maxRequestRetries`} times.
|
|
55
44
|
* If all the retries fail, the crawler calls the function
|
|
56
|
-
* provided to the `
|
|
57
|
-
* To make this work,
|
|
58
|
-
* let
|
|
45
|
+
* provided to the {@link BrowserCrawlerOptions.failedRequestHandler|`failedRequestHandler`} parameter.
|
|
46
|
+
* To make this work, we should **always**
|
|
47
|
+
* let our function throw exceptions rather than catch them.
|
|
59
48
|
* The exceptions are logged to the request using the
|
|
60
|
-
* {@link Request.pushErrorMessage} function.
|
|
49
|
+
* {@link Request.pushErrorMessage|`Request.pushErrorMessage()`} function.
|
|
61
50
|
*/
|
|
62
|
-
requestHandler
|
|
51
|
+
requestHandler?: BrowserCrawlerHandleRequest<Context>;
|
|
63
52
|
/**
|
|
64
53
|
* Function that is called to process each request.
|
|
65
|
-
* It is passed an object with the following fields:
|
|
66
54
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
55
|
+
* The function receives the {@link BrowserCrawlingContext}
|
|
56
|
+
* (actual context will be enhanced with the crawler specific properties) as an argument, where:
|
|
57
|
+
* - {@link BrowserCrawlingContext.request|`request`} is an instance of the {@link Request} object
|
|
58
|
+
* with details about the URL to open, HTTP method etc;
|
|
59
|
+
* - {@link BrowserCrawlingContext.page|`page`} is an instance of the
|
|
60
|
+
* Puppeteer [Page](https://pptr.dev/api/puppeteer.page) or
|
|
61
|
+
* Playwright [Page](https://playwright.dev/docs/api/class-page);
|
|
62
|
+
* - {@link BrowserCrawlingContext.browserController|`browserController`} is an instance of the {@link BrowserController};
|
|
63
|
+
* - {@link BrowserCrawlingContext.response|`response`} is an instance of the
|
|
64
|
+
* Puppeteer [Response](https://pptr.dev/api/puppeteer.httpresponse) or
|
|
65
|
+
* Playwright [Response](https://playwright.dev/docs/api/class-response),
|
|
66
|
+
* which is the main resource response as returned by the respective `page.goto()` function.
|
|
78
67
|
*
|
|
79
|
-
* `request` is an instance of the {@link Request} object with details about the URL to open, HTTP method etc.
|
|
80
|
-
* `page` is an instance of the `Puppeteer`
|
|
81
|
-
* [`Page`](https://pptr.dev/#?product=Puppeteer&show=api-class-page) or `Playwright`
|
|
82
|
-
* [`Page`](https://playwright.dev/docs/api/class-page)
|
|
83
|
-
* `browserPool` is an instance of the
|
|
84
|
-
* [`BrowserPool`](https://github.com/apify/browser-pool#BrowserPool),
|
|
85
|
-
* `browserController` is an instance of the
|
|
86
|
-
* [`BrowserController`](https://github.com/apify/browser-pool#browsercontroller),
|
|
87
|
-
* `response` is an instance of the `Puppeteer`
|
|
88
|
-
* [`Response`](https://pptr.dev/#?product=Puppeteer&show=api-class-response) or `Playwright`
|
|
89
|
-
* [`Response`](https://playwright.dev/docs/api/class-response),
|
|
90
|
-
* which is the main resource response as returned by `page.goto(request.url)`.
|
|
91
68
|
* The function must return a promise, which is then awaited by the crawler.
|
|
92
69
|
*
|
|
93
70
|
* If the function throws an exception, the crawler will try to re-crawl the
|
|
94
|
-
* request later, up to
|
|
71
|
+
* request later, up to the {@link BrowserCrawlerOptions.maxRequestRetries|`maxRequestRetries`} times.
|
|
95
72
|
* If all the retries fail, the crawler calls the function
|
|
96
|
-
* provided to the `
|
|
97
|
-
* To make this work,
|
|
98
|
-
* let
|
|
73
|
+
* provided to the {@link BrowserCrawlerOptions.failedRequestHandler|`failedRequestHandler`} parameter.
|
|
74
|
+
* To make this work, we should **always**
|
|
75
|
+
* let our function throw exceptions rather than catch them.
|
|
99
76
|
* The exceptions are logged to the request using the
|
|
100
|
-
* {@link Request.pushErrorMessage} function.
|
|
77
|
+
* {@link Request.pushErrorMessage|`Request.pushErrorMessage()`} function.
|
|
101
78
|
*
|
|
102
79
|
* @deprecated `handlePageFunction` has been renamed to `requestHandler` and will be removed in a future version.
|
|
103
80
|
*/
|
|
104
81
|
handlePageFunction?: BrowserCrawlerHandleRequest<Context>;
|
|
105
82
|
/**
|
|
106
|
-
*
|
|
83
|
+
* User-provided function that allows modifying the request object before it gets retried by the crawler.
|
|
84
|
+
* It's executed before each retry for the requests that failed less than {@link BrowserCrawlerOptions.maxRequestRetries|`maxRequestRetries`} times.
|
|
107
85
|
*
|
|
108
|
-
* The function receives the
|
|
109
|
-
*
|
|
110
|
-
* {
|
|
111
|
-
*
|
|
112
|
-
* response: Response,
|
|
113
|
-
* page: Page,
|
|
114
|
-
* browserPool: BrowserPool,
|
|
115
|
-
* autoscaledPool: AutoscaledPool,
|
|
116
|
-
* session: Session,
|
|
117
|
-
* browserController: BrowserController,
|
|
118
|
-
* proxyInfo: ProxyInfo,
|
|
119
|
-
* }
|
|
120
|
-
* ```
|
|
121
|
-
* Where the {@link Request} instance corresponds to the failed request, and the `Error` instance
|
|
86
|
+
* The function receives the {@link BrowserCrawlingContext}
|
|
87
|
+
* (actual context will be enhanced with the crawler specific properties) as the first argument,
|
|
88
|
+
* where the {@link BrowserCrawlingContext.request|`request`} corresponds to the request to be retried.
|
|
89
|
+
* Second argument is the `Error` instance that
|
|
122
90
|
* represents the last error thrown during processing of the request.
|
|
91
|
+
*/
|
|
92
|
+
errorHandler?: BrowserCrawlerHandleFailedRequest<Context>;
|
|
93
|
+
/**
|
|
94
|
+
* A function to handle requests that failed more than `option.maxRequestRetries` times.
|
|
123
95
|
*
|
|
96
|
+
* The function receives the {@link BrowserCrawlingContext}
|
|
97
|
+
* (actual context will be enhanced with the crawler specific properties) as the first argument,
|
|
98
|
+
* where the {@link BrowserCrawlingContext.request|`request`} corresponds to the failed request.
|
|
99
|
+
* Second argument is the `Error` instance that
|
|
100
|
+
* represents the last error thrown during processing of the request.
|
|
124
101
|
*/
|
|
125
|
-
failedRequestHandler?: BrowserCrawlerHandleFailedRequest
|
|
102
|
+
failedRequestHandler?: BrowserCrawlerHandleFailedRequest<Context>;
|
|
126
103
|
/**
|
|
127
104
|
* A function to handle requests that failed more than `option.maxRequestRetries` times.
|
|
128
105
|
*
|
|
129
|
-
* The function receives the
|
|
130
|
-
*
|
|
131
|
-
* {
|
|
132
|
-
*
|
|
133
|
-
* response: Response,
|
|
134
|
-
* page: Page,
|
|
135
|
-
* browserPool: BrowserPool,
|
|
136
|
-
* autoscaledPool: AutoscaledPool,
|
|
137
|
-
* session: Session,
|
|
138
|
-
* browserController: BrowserController,
|
|
139
|
-
* proxyInfo: ProxyInfo,
|
|
140
|
-
* }
|
|
141
|
-
* ```
|
|
142
|
-
* Where the {@link Request} instance corresponds to the failed request, and the `Error` instance
|
|
106
|
+
* The function receives the {@link BrowserCrawlingContext}
|
|
107
|
+
* (actual context will be enhanced with the crawler specific properties) as the first argument,
|
|
108
|
+
* where the {@link BrowserCrawlingContext.request|`request`} corresponds to the failed request.
|
|
109
|
+
* Second argument is the `Error` instance that
|
|
143
110
|
* represents the last error thrown during processing of the request.
|
|
144
111
|
*
|
|
145
112
|
* @deprecated `handleFailedRequestFunction` has been renamed to `failedRequestHandler` and will be removed in a future version.
|
|
146
113
|
*/
|
|
147
|
-
handleFailedRequestFunction?: BrowserCrawlerHandleFailedRequest
|
|
114
|
+
handleFailedRequestFunction?: BrowserCrawlerHandleFailedRequest<Context>;
|
|
148
115
|
/**
|
|
149
|
-
* Custom options passed to the underlying
|
|
150
|
-
*
|
|
116
|
+
* Custom options passed to the underlying {@link BrowserPool} constructor.
|
|
117
|
+
* We can tweak those to fine-tune browser management.
|
|
151
118
|
*/
|
|
152
119
|
browserPoolOptions?: Partial<BrowserPoolOptions> & Partial<BrowserPoolHooks<__BrowserControllerReturn, __LaunchContextReturn>>;
|
|
153
120
|
/**
|
|
154
121
|
* If set, the crawler will be configured for all connections to use
|
|
155
|
-
*
|
|
156
|
-
* For more information, see the [documentation](https://docs.apify.com/proxy).
|
|
122
|
+
* the Proxy URLs provided and rotated according to the configuration.
|
|
157
123
|
*/
|
|
158
124
|
proxyConfiguration?: ProxyConfiguration;
|
|
159
125
|
/**
|
|
160
126
|
* Async functions that are sequentially evaluated before the navigation. Good for setting additional cookies
|
|
161
127
|
* or browser properties before navigation. The function accepts two parameters, `crawlingContext` and `gotoOptions`,
|
|
162
128
|
* which are passed to the `page.goto()` function the crawler calls to navigate.
|
|
163
|
-
*
|
|
164
|
-
*
|
|
129
|
+
*
|
|
130
|
+
* **Example:**
|
|
131
|
+
*
|
|
132
|
+
* ```js
|
|
165
133
|
* preNavigationHooks: [
|
|
166
134
|
* async (crawlingContext, gotoOptions) => {
|
|
167
135
|
* const { page } = crawlingContext;
|
|
168
136
|
* await page.evaluate((attr) => { window.foo = attr; }, 'bar');
|
|
137
|
+
* gotoOptions.timeout = 60_000;
|
|
138
|
+
* gotoOptions.waitUntil = 'domcontentloaded';
|
|
169
139
|
* },
|
|
170
140
|
* ]
|
|
171
141
|
* ```
|
|
@@ -174,13 +144,15 @@ export interface BrowserCrawlerOptions<Context extends BrowserCrawlingContext =
|
|
|
174
144
|
/**
|
|
175
145
|
* Async functions that are sequentially evaluated after the navigation. Good for checking if the navigation was successful.
|
|
176
146
|
* The function accepts `crawlingContext` as the only parameter.
|
|
177
|
-
*
|
|
178
|
-
*
|
|
147
|
+
*
|
|
148
|
+
* **Example:**
|
|
149
|
+
*
|
|
150
|
+
* ```js
|
|
179
151
|
* postNavigationHooks: [
|
|
180
152
|
* async (crawlingContext) => {
|
|
181
153
|
* const { page } = crawlingContext;
|
|
182
154
|
* if (hasCaptcha(page)) {
|
|
183
|
-
* await solveCaptcha
|
|
155
|
+
* await solveCaptcha(page);
|
|
184
156
|
* }
|
|
185
157
|
* },
|
|
186
158
|
* ]
|
|
@@ -192,7 +164,7 @@ export interface BrowserCrawlerOptions<Context extends BrowserCrawlingContext =
|
|
|
192
164
|
*/
|
|
193
165
|
navigationTimeoutSecs?: number;
|
|
194
166
|
/**
|
|
195
|
-
*
|
|
167
|
+
* Defines whether the cookies should be persisted for sessions.
|
|
196
168
|
* This can only be used when `useSessionPool` is set to `true`.
|
|
197
169
|
*/
|
|
198
170
|
persistCookiesPerSession?: boolean;
|
|
@@ -204,46 +176,47 @@ export interface BrowserCrawlerOptions<Context extends BrowserCrawlingContext =
|
|
|
204
176
|
* The URLs to crawl are fed either from a static list of URLs
|
|
205
177
|
* or from a dynamic queue of URLs enabling recursive crawling of websites.
|
|
206
178
|
*
|
|
207
|
-
* Since `BrowserCrawler` uses headless or even
|
|
179
|
+
* Since `BrowserCrawler` uses headless (or even headful) browsers to download web pages and extract data,
|
|
208
180
|
* it is useful for crawling of websites that require to execute JavaScript.
|
|
209
|
-
* If the target website doesn't need JavaScript, consider using {@link CheerioCrawler},
|
|
181
|
+
* If the target website doesn't need JavaScript, we should consider using the {@link CheerioCrawler},
|
|
210
182
|
* which downloads the pages using raw HTTP requests and is about 10x faster.
|
|
211
183
|
*
|
|
212
|
-
* The source URLs are represented
|
|
213
|
-
*
|
|
214
|
-
*
|
|
184
|
+
* The source URLs are represented by the {@link Request} objects that are fed from the {@link RequestList} or {@link RequestQueue} instances
|
|
185
|
+
* provided by the {@link BrowserCrawlerOptions.requestList|`requestList`} or {@link BrowserCrawlerOptions.requestQueue|`requestQueue`}
|
|
186
|
+
* constructor options, respectively. If neither `requestList` nor `requestQueue` options are provided,
|
|
187
|
+
* the crawler will open the default request queue either when the {@link BrowserCrawler.addRequests|`crawler.addRequests()`} function is called,
|
|
188
|
+
* or if `requests` parameter (representing the initial requests) of the {@link BrowserCrawler.run|`crawler.run()`} function is provided.
|
|
215
189
|
*
|
|
216
|
-
* If both {@link BrowserCrawlerOptions.requestList} and {@link BrowserCrawlerOptions.requestQueue} are used,
|
|
190
|
+
* If both {@link BrowserCrawlerOptions.requestList|`requestList`} and {@link BrowserCrawlerOptions.requestQueue|`requestQueue`} options are used,
|
|
217
191
|
* the instance first processes URLs from the {@link RequestList} and automatically enqueues all of them
|
|
218
|
-
* to {@link RequestQueue} before it starts their processing. This ensures that a single URL is not crawled multiple times.
|
|
192
|
+
* to the {@link RequestQueue} before it starts their processing. This ensures that a single URL is not crawled multiple times.
|
|
219
193
|
*
|
|
220
194
|
* The crawler finishes when there are no more {@link Request} objects to crawl.
|
|
221
195
|
*
|
|
222
196
|
* `BrowserCrawler` opens a new browser page (i.e. tab or window) for each {@link Request} object to crawl
|
|
223
|
-
* and then calls the function provided by user as the {@link BrowserCrawlerOptions.
|
|
197
|
+
* and then calls the function provided by user as the {@link BrowserCrawlerOptions.requestHandler|`requestHandler`} option.
|
|
224
198
|
*
|
|
225
199
|
* New pages are only opened when there is enough free CPU and memory available,
|
|
226
200
|
* using the functionality provided by the {@link AutoscaledPool} class.
|
|
227
|
-
* All {@link AutoscaledPool} configuration options can be passed to the {@link BrowserCrawlerOptions.autoscaledPoolOptions}
|
|
228
|
-
* parameter of the `BrowserCrawler` constructor.
|
|
229
|
-
* {@link AutoscaledPoolOptions}
|
|
201
|
+
* All {@link AutoscaledPool} configuration options can be passed to the {@link BrowserCrawlerOptions.autoscaledPoolOptions|`autoscaledPoolOptions`}
|
|
202
|
+
* parameter of the `BrowserCrawler` constructor.
|
|
203
|
+
* For user convenience, the {@link AutoscaledPoolOptions.minConcurrency|`minConcurrency`} and
|
|
204
|
+
* {@link AutoscaledPoolOptions.maxConcurrency|`maxConcurrency`} options of the
|
|
205
|
+
* underlying {@link AutoscaledPool} constructor are available directly in the `BrowserCrawler` constructor.
|
|
206
|
+
*
|
|
207
|
+
* > *NOTE:* the pool of browser instances is internally managed by the {@link BrowserPool} class.
|
|
230
208
|
*
|
|
231
|
-
* Note that the pool of browser instances is internally managed by the [BrowserPool](https://github.com/apify/browser-pool) class.
|
|
232
|
-
* ```js
|
|
233
|
-
* await crawler.run();
|
|
234
|
-
* ```
|
|
235
209
|
* @category Crawlers
|
|
236
210
|
*/
|
|
237
211
|
export declare abstract class BrowserCrawler<InternalBrowserPoolOptions extends BrowserPoolOptions = BrowserPoolOptions, LaunchOptions = Dictionary, Context extends BrowserCrawlingContext = BrowserCrawlingContext, GoToOptions extends Record<PropertyKey, any> = Dictionary> extends BasicCrawler<Context> {
|
|
212
|
+
readonly config: Configuration;
|
|
238
213
|
/**
|
|
239
214
|
* A reference to the underlying {@link ProxyConfiguration} class that manages the crawler's proxies.
|
|
240
215
|
* Only available if used by the crawler.
|
|
241
216
|
*/
|
|
242
217
|
proxyConfiguration?: ProxyConfiguration;
|
|
243
218
|
/**
|
|
244
|
-
* A reference to the underlying
|
|
245
|
-
* For more information about it, see the [`browser-pool` module](https://github.com/apify/browser-pool).
|
|
246
|
-
* @todo the type is almost unusable with so many generic arguments, what should go there? we need inference
|
|
219
|
+
* A reference to the underlying {@link BrowserPool} class that manages the crawler's browsers.
|
|
247
220
|
*/
|
|
248
221
|
browserPool: BrowserPool<InternalBrowserPoolOptions>;
|
|
249
222
|
launchContext?: BrowserLaunchContext<LaunchOptions, unknown>;
|
|
@@ -269,6 +242,7 @@ export declare abstract class BrowserCrawler<InternalBrowserPoolOptions extends
|
|
|
269
242
|
handleRequestFunction: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
270
243
|
requestHandlerTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
271
244
|
handleRequestTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
245
|
+
errorHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
272
246
|
failedRequestHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
273
247
|
handleFailedRequestFunction: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
274
248
|
maxRequestRetries: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
@@ -276,14 +250,15 @@ export declare abstract class BrowserCrawler<InternalBrowserPoolOptions extends
|
|
|
276
250
|
autoscaledPoolOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
277
251
|
minConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
278
252
|
maxConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
253
|
+
maxRequestsPerMinute: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
279
254
|
log: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
280
255
|
};
|
|
281
256
|
/**
|
|
282
257
|
* All `BrowserCrawler` parameters are passed via an options object.
|
|
283
258
|
*/
|
|
284
|
-
protected constructor(options
|
|
259
|
+
protected constructor(options?: BrowserCrawlerOptions<Context>, config?: Configuration);
|
|
285
260
|
/**
|
|
286
|
-
* Wrapper around
|
|
261
|
+
* Wrapper around requestHandler that opens and closes pages etc.
|
|
287
262
|
*/
|
|
288
263
|
protected _runRequestHandler(crawlingContext: Context): Promise<void>;
|
|
289
264
|
protected _enhanceCrawlingContextWithPageInfo(crawlingContext: Context, page: CommonPage, useIncognitoPages?: boolean): void;
|
|
@@ -292,17 +267,16 @@ export declare abstract class BrowserCrawler<InternalBrowserPoolOptions extends
|
|
|
292
267
|
/**
|
|
293
268
|
* Marks session bad in case of navigation timeout.
|
|
294
269
|
*/
|
|
295
|
-
protected _handleNavigationTimeout(crawlingContext: Context, error: Error): void
|
|
270
|
+
protected _handleNavigationTimeout(crawlingContext: Context, error: Error): Promise<void>;
|
|
296
271
|
protected abstract _navigationHandler(crawlingContext: Context, gotoOptions: GoToOptions): Promise<Context['response'] | null | undefined>;
|
|
297
272
|
/**
|
|
298
273
|
* Should be overridden in case of different automation library that does not support this response API.
|
|
299
|
-
* @todo: This can be also done as a postNavigation hook except the loadedUrl marking.
|
|
300
274
|
*/
|
|
301
275
|
protected _responseHandler(crawlingContext: Context): Promise<void>;
|
|
302
276
|
protected _extendLaunchContext(_pageId: string, launchContext: LaunchContext): Promise<void>;
|
|
303
277
|
protected _maybeAddSessionRetiredListener(_pageId: string, browserController: Context['browserController']): void;
|
|
304
278
|
/**
|
|
305
|
-
* Function for cleaning up after all
|
|
279
|
+
* Function for cleaning up after all requests are processed.
|
|
306
280
|
* @ignore
|
|
307
281
|
*/
|
|
308
282
|
teardown(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser-crawler.d.ts","sourceRoot":"","sources":["../../src/internals/browser-crawler.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"browser-crawler.d.ts","sourceRoot":"","sources":["../../src/internals/browser-crawler.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,41 +15,43 @@ const tough_cookie_1 = require("tough-cookie");
|
|
|
15
15
|
* The URLs to crawl are fed either from a static list of URLs
|
|
16
16
|
* or from a dynamic queue of URLs enabling recursive crawling of websites.
|
|
17
17
|
*
|
|
18
|
-
* Since `BrowserCrawler` uses headless or even
|
|
18
|
+
* Since `BrowserCrawler` uses headless (or even headful) browsers to download web pages and extract data,
|
|
19
19
|
* it is useful for crawling of websites that require to execute JavaScript.
|
|
20
|
-
* If the target website doesn't need JavaScript, consider using {@link CheerioCrawler},
|
|
20
|
+
* If the target website doesn't need JavaScript, we should consider using the {@link CheerioCrawler},
|
|
21
21
|
* which downloads the pages using raw HTTP requests and is about 10x faster.
|
|
22
22
|
*
|
|
23
|
-
* The source URLs are represented
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* The source URLs are represented by the {@link Request} objects that are fed from the {@link RequestList} or {@link RequestQueue} instances
|
|
24
|
+
* provided by the {@link BrowserCrawlerOptions.requestList|`requestList`} or {@link BrowserCrawlerOptions.requestQueue|`requestQueue`}
|
|
25
|
+
* constructor options, respectively. If neither `requestList` nor `requestQueue` options are provided,
|
|
26
|
+
* the crawler will open the default request queue either when the {@link BrowserCrawler.addRequests|`crawler.addRequests()`} function is called,
|
|
27
|
+
* or if `requests` parameter (representing the initial requests) of the {@link BrowserCrawler.run|`crawler.run()`} function is provided.
|
|
26
28
|
*
|
|
27
|
-
* If both {@link BrowserCrawlerOptions.requestList} and {@link BrowserCrawlerOptions.requestQueue} are used,
|
|
29
|
+
* If both {@link BrowserCrawlerOptions.requestList|`requestList`} and {@link BrowserCrawlerOptions.requestQueue|`requestQueue`} options are used,
|
|
28
30
|
* the instance first processes URLs from the {@link RequestList} and automatically enqueues all of them
|
|
29
|
-
* to {@link RequestQueue} before it starts their processing. This ensures that a single URL is not crawled multiple times.
|
|
31
|
+
* to the {@link RequestQueue} before it starts their processing. This ensures that a single URL is not crawled multiple times.
|
|
30
32
|
*
|
|
31
33
|
* The crawler finishes when there are no more {@link Request} objects to crawl.
|
|
32
34
|
*
|
|
33
35
|
* `BrowserCrawler` opens a new browser page (i.e. tab or window) for each {@link Request} object to crawl
|
|
34
|
-
* and then calls the function provided by user as the {@link BrowserCrawlerOptions.
|
|
36
|
+
* and then calls the function provided by user as the {@link BrowserCrawlerOptions.requestHandler|`requestHandler`} option.
|
|
35
37
|
*
|
|
36
38
|
* New pages are only opened when there is enough free CPU and memory available,
|
|
37
39
|
* using the functionality provided by the {@link AutoscaledPool} class.
|
|
38
|
-
* All {@link AutoscaledPool} configuration options can be passed to the {@link BrowserCrawlerOptions.autoscaledPoolOptions}
|
|
39
|
-
* parameter of the `BrowserCrawler` constructor.
|
|
40
|
-
* {@link AutoscaledPoolOptions}
|
|
40
|
+
* All {@link AutoscaledPool} configuration options can be passed to the {@link BrowserCrawlerOptions.autoscaledPoolOptions|`autoscaledPoolOptions`}
|
|
41
|
+
* parameter of the `BrowserCrawler` constructor.
|
|
42
|
+
* For user convenience, the {@link AutoscaledPoolOptions.minConcurrency|`minConcurrency`} and
|
|
43
|
+
* {@link AutoscaledPoolOptions.maxConcurrency|`maxConcurrency`} options of the
|
|
44
|
+
* underlying {@link AutoscaledPool} constructor are available directly in the `BrowserCrawler` constructor.
|
|
45
|
+
*
|
|
46
|
+
* > *NOTE:* the pool of browser instances is internally managed by the {@link BrowserPool} class.
|
|
41
47
|
*
|
|
42
|
-
* Note that the pool of browser instances is internally managed by the [BrowserPool](https://github.com/apify/browser-pool) class.
|
|
43
|
-
* ```js
|
|
44
|
-
* await crawler.run();
|
|
45
|
-
* ```
|
|
46
48
|
* @category Crawlers
|
|
47
49
|
*/
|
|
48
50
|
class BrowserCrawler extends basic_1.BasicCrawler {
|
|
49
51
|
/**
|
|
50
52
|
* All `BrowserCrawler` parameters are passed via an options object.
|
|
51
53
|
*/
|
|
52
|
-
constructor(options) {
|
|
54
|
+
constructor(options = {}, config = core_1.Configuration.getGlobalConfig()) {
|
|
53
55
|
(0, ow_1.default)(options, 'BrowserCrawlerOptions', ow_1.default.object.exactShape(BrowserCrawler.optionsShape));
|
|
54
56
|
const { navigationTimeoutSecs = 60, requestHandlerTimeoutSecs = 60, persistCookiesPerSession, proxyConfiguration, launchContext, browserPoolOptions, preNavigationHooks = [], postNavigationHooks = [],
|
|
55
57
|
// Ignored
|
|
@@ -58,6 +60,12 @@ class BrowserCrawler extends basic_1.BasicCrawler {
|
|
|
58
60
|
...basicCrawlerOptions,
|
|
59
61
|
requestHandler: (...args) => this._runRequestHandler(...args),
|
|
60
62
|
requestHandlerTimeoutSecs: navigationTimeoutSecs + requestHandlerTimeoutSecs + basic_1.BASIC_CRAWLER_TIMEOUT_BUFFER_SECS,
|
|
63
|
+
}, config);
|
|
64
|
+
Object.defineProperty(this, "config", {
|
|
65
|
+
enumerable: true,
|
|
66
|
+
configurable: true,
|
|
67
|
+
writable: true,
|
|
68
|
+
value: config
|
|
61
69
|
});
|
|
62
70
|
/**
|
|
63
71
|
* A reference to the underlying {@link ProxyConfiguration} class that manages the crawler's proxies.
|
|
@@ -70,9 +78,7 @@ class BrowserCrawler extends basic_1.BasicCrawler {
|
|
|
70
78
|
value: void 0
|
|
71
79
|
});
|
|
72
80
|
/**
|
|
73
|
-
* A reference to the underlying
|
|
74
|
-
* For more information about it, see the [`browser-pool` module](https://github.com/apify/browser-pool).
|
|
75
|
-
* @todo the type is almost unusable with so many generic arguments, what should go there? we need inference
|
|
81
|
+
* A reference to the underlying {@link BrowserPool} class that manages the crawler's browsers.
|
|
76
82
|
*/
|
|
77
83
|
Object.defineProperty(this, "browserPool", {
|
|
78
84
|
enumerable: true,
|
|
@@ -122,7 +128,11 @@ class BrowserCrawler extends basic_1.BasicCrawler {
|
|
|
122
128
|
propertyKey: 'userProvidedRequestHandler',
|
|
123
129
|
newProperty: userProvidedRequestHandler,
|
|
124
130
|
oldProperty: handlePageFunction,
|
|
131
|
+
allowUndefined: true, // fallback to the default router
|
|
125
132
|
});
|
|
133
|
+
if (!this.userProvidedRequestHandler) {
|
|
134
|
+
this.userProvidedRequestHandler = this.router;
|
|
135
|
+
}
|
|
126
136
|
this._handlePropertyNameChange({
|
|
127
137
|
newName: 'failedRequestHandler',
|
|
128
138
|
oldName: 'handleFailedRequestFunction',
|
|
@@ -147,8 +157,9 @@ class BrowserCrawler extends basic_1.BasicCrawler {
|
|
|
147
157
|
this.persistCookiesPerSession = false;
|
|
148
158
|
}
|
|
149
159
|
if (launchContext?.userAgent) {
|
|
160
|
+
if (browserPoolOptions.useFingerprints)
|
|
161
|
+
this.log.info('Custom user agent provided, disabling automatic browser fingerprint injection!');
|
|
150
162
|
browserPoolOptions.useFingerprints = false;
|
|
151
|
-
this.log.info('Disabling automatic fingerprint injection because custom user agent has been provided.');
|
|
152
163
|
}
|
|
153
164
|
const { preLaunchHooks = [], postLaunchHooks = [], ...rest } = browserPoolOptions;
|
|
154
165
|
this.browserPool = new browser_pool_1.BrowserPool({
|
|
@@ -164,7 +175,7 @@ class BrowserCrawler extends basic_1.BasicCrawler {
|
|
|
164
175
|
});
|
|
165
176
|
}
|
|
166
177
|
/**
|
|
167
|
-
* Wrapper around
|
|
178
|
+
* Wrapper around requestHandler that opens and closes pages etc.
|
|
168
179
|
*/
|
|
169
180
|
async _runRequestHandler(crawlingContext) {
|
|
170
181
|
const newPageOptions = {
|
|
@@ -205,7 +216,7 @@ class BrowserCrawler extends basic_1.BasicCrawler {
|
|
|
205
216
|
if (this.persistCookiesPerSession) {
|
|
206
217
|
const cookies = await crawlingContext.browserController.getCookies(page);
|
|
207
218
|
(0, timeout_1.tryCancel)();
|
|
208
|
-
session?.
|
|
219
|
+
session?.setCookies(cookies, request.loadedUrl);
|
|
209
220
|
}
|
|
210
221
|
}
|
|
211
222
|
await (0, timeout_1.addTimeoutToPromise)(() => Promise.resolve(this.userProvidedRequestHandler(crawlingContext)), this.requestHandlerTimeoutMillis, `requestHandler timed out after ${this.requestHandlerTimeoutMillis / 1000} seconds.`);
|
|
@@ -214,7 +225,7 @@ class BrowserCrawler extends basic_1.BasicCrawler {
|
|
|
214
225
|
session.markGood();
|
|
215
226
|
}
|
|
216
227
|
finally {
|
|
217
|
-
page.close().catch((error) => this.log.debug('Error while closing page', { error }));
|
|
228
|
+
await page.close().catch((error) => this.log.debug('Error while closing page', { error }));
|
|
218
229
|
}
|
|
219
230
|
}
|
|
220
231
|
_enhanceCrawlingContextWithPageInfo(crawlingContext, page, useIncognitoPages) {
|
|
@@ -252,14 +263,14 @@ class BrowserCrawler extends basic_1.BasicCrawler {
|
|
|
252
263
|
crawlingContext.response = await this._navigationHandler(crawlingContext, gotoOptions) ?? undefined;
|
|
253
264
|
}
|
|
254
265
|
catch (error) {
|
|
255
|
-
this._handleNavigationTimeout(crawlingContext, error);
|
|
266
|
+
await this._handleNavigationTimeout(crawlingContext, error);
|
|
256
267
|
throw error;
|
|
257
268
|
}
|
|
258
269
|
(0, timeout_1.tryCancel)();
|
|
259
270
|
await this._executeHooks(this.postNavigationHooks, crawlingContext, gotoOptions);
|
|
260
271
|
}
|
|
261
272
|
async _applyCookies({ session, request, page, browserController }, preHooksCookies, postHooksCookies) {
|
|
262
|
-
const sessionCookie = session?.
|
|
273
|
+
const sessionCookie = session?.getCookies(request.url) ?? [];
|
|
263
274
|
const parsedPreHooksCookies = preHooksCookies.split(/ *; */).map((c) => tough_cookie_1.Cookie.parse(c)?.toJSON());
|
|
264
275
|
const parsedPostHooksCookies = postHooksCookies.split(/ *; */).map((c) => tough_cookie_1.Cookie.parse(c)?.toJSON());
|
|
265
276
|
await browserController.setCookies(page, [
|
|
@@ -271,15 +282,15 @@ class BrowserCrawler extends basic_1.BasicCrawler {
|
|
|
271
282
|
/**
|
|
272
283
|
* Marks session bad in case of navigation timeout.
|
|
273
284
|
*/
|
|
274
|
-
_handleNavigationTimeout(crawlingContext, error) {
|
|
285
|
+
async _handleNavigationTimeout(crawlingContext, error) {
|
|
275
286
|
const { session } = crawlingContext;
|
|
276
287
|
if (error && error.constructor.name === 'TimeoutError') {
|
|
277
288
|
(0, core_1.handleRequestTimeout)({ session, errorMessage: error.message });
|
|
278
289
|
}
|
|
290
|
+
await crawlingContext.page.close();
|
|
279
291
|
}
|
|
280
292
|
/**
|
|
281
293
|
* Should be overridden in case of different automation library that does not support this response API.
|
|
282
|
-
* @todo: This can be also done as a postNavigation hook except the loadedUrl marking.
|
|
283
294
|
*/
|
|
284
295
|
async _responseHandler(crawlingContext) {
|
|
285
296
|
const { response, session, request, page } = crawlingContext;
|
|
@@ -328,7 +339,7 @@ class BrowserCrawler extends basic_1.BasicCrawler {
|
|
|
328
339
|
}
|
|
329
340
|
}
|
|
330
341
|
/**
|
|
331
|
-
* Function for cleaning up after all
|
|
342
|
+
* Function for cleaning up after all requests are processed.
|
|
332
343
|
* @ignore
|
|
333
344
|
*/
|
|
334
345
|
async teardown() {
|