@crawlee/browser 4.0.0-beta.80 → 4.0.0-beta.82
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.
|
@@ -31,8 +31,8 @@ export interface BrowserCrawlingContext<Page extends CommonPage = CommonPage, Re
|
|
|
31
31
|
*/
|
|
32
32
|
enqueueLinks: (options?: EnqueueLinksOptions) => Promise<BatchAddRequestsResult>;
|
|
33
33
|
}
|
|
34
|
-
export type BrowserHook<Context = BrowserCrawlingContext> = (crawlingContext: Context) => Awaitable<void | Partial<Context>>;
|
|
35
|
-
export interface BrowserCrawlerOptions<Page extends CommonPage = CommonPage, Response extends BaseResponse = BaseResponse, Context extends BrowserCrawlingContext<Page, Response, Dictionary> = BrowserCrawlingContext<Page, Response, Dictionary>, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension, 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<Context, ExtendedContext>, 'requestHandler' | 'failedRequestHandler' | 'errorHandler'> {
|
|
34
|
+
export type BrowserHook<Context = BrowserCrawlingContext, ContextExtension = {}> = (crawlingContext: Context & ContextExtension) => Awaitable<void | Partial<Context>>;
|
|
35
|
+
export interface BrowserCrawlerOptions<Page extends CommonPage = CommonPage, Response extends BaseResponse = BaseResponse, Context extends BrowserCrawlingContext<Page, Response, Dictionary> = BrowserCrawlingContext<Page, Response, Dictionary>, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension, 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<Context, ContextExtension, ExtendedContext>, 'requestHandler' | 'failedRequestHandler' | 'errorHandler'> {
|
|
36
36
|
launchContext?: BrowserLaunchContext<any, any>;
|
|
37
37
|
/**
|
|
38
38
|
* An existing browser pool instance to use. When provided, the crawler will use this pool directly instead of
|
|
@@ -124,8 +124,13 @@ export interface BrowserCrawlerOptions<Page extends CommonPage = CommonPage, Res
|
|
|
124
124
|
*
|
|
125
125
|
* A hook may optionally return a partial object whose properties are merged into the crawling context,
|
|
126
126
|
* allowing the hook to override context members for subsequent hooks and pipeline stages.
|
|
127
|
+
*
|
|
128
|
+
* The context is built up in the following order: base context (`request`, `session`, helpers, ...) ->
|
|
129
|
+
* `extendContext` -> `preNavigationHooks` -> navigation -> `postNavigationHooks` -> `requestHandler`.
|
|
130
|
+
* This means the members added by `extendContext` are already available here, but navigation-dependent
|
|
131
|
+
* members (e.g. `page`, `response`) are not.
|
|
127
132
|
*/
|
|
128
|
-
preNavigationHooks?: BrowserHook<Context>[];
|
|
133
|
+
preNavigationHooks?: BrowserHook<Context, ContextExtension>[];
|
|
129
134
|
/**
|
|
130
135
|
* Async functions that are sequentially evaluated after the navigation. Good for checking if the navigation was successful.
|
|
131
136
|
* The function accepts `crawlingContext` as the only parameter.
|
|
@@ -151,7 +156,7 @@ export interface BrowserCrawlerOptions<Page extends CommonPage = CommonPage, Res
|
|
|
151
156
|
* ]
|
|
152
157
|
* ```
|
|
153
158
|
*/
|
|
154
|
-
postNavigationHooks?: BrowserHook<Context>[];
|
|
159
|
+
postNavigationHooks?: BrowserHook<Context, ContextExtension>[];
|
|
155
160
|
/**
|
|
156
161
|
* Timeout in which page navigation needs to finish, in seconds.
|
|
157
162
|
*/
|
|
@@ -233,10 +238,10 @@ export declare abstract class BrowserCrawler<Page extends CommonPage = CommonPag
|
|
|
233
238
|
launchContext: BrowserLaunchContext<LaunchOptions, unknown>;
|
|
234
239
|
protected readonly ignoreShadowRoots: boolean;
|
|
235
240
|
protected readonly ignoreIframes: boolean;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
241
|
+
private readonly navigationTimeoutMillis;
|
|
242
|
+
private readonly preNavigationHooks;
|
|
243
|
+
private readonly postNavigationHooks;
|
|
244
|
+
private readonly saveResponseCookies;
|
|
240
245
|
protected static optionsShape: {
|
|
241
246
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
242
247
|
navigationTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
@@ -333,22 +338,22 @@ export declare abstract class BrowserCrawler<Page extends CommonPage = CommonPag
|
|
|
333
338
|
});
|
|
334
339
|
protected buildContextPipeline(): ContextPipeline<CrawlingContext, BrowserCrawlingContext<Page, Response, Dictionary>>;
|
|
335
340
|
private containsSelectors;
|
|
336
|
-
|
|
341
|
+
private isRequestBlocked;
|
|
337
342
|
private preparePage;
|
|
338
343
|
private prepareNavigation;
|
|
339
344
|
private navigate;
|
|
340
345
|
private finalizeNavigation;
|
|
341
346
|
private handleBlockedRequestByContent;
|
|
342
347
|
private restoreRequestState;
|
|
343
|
-
|
|
348
|
+
private applyCookies;
|
|
344
349
|
/**
|
|
345
350
|
* Marks session bad on navigation timeout, and stops in-flight page loading on any navigation error.
|
|
346
351
|
*/
|
|
347
|
-
|
|
352
|
+
private handleNavigationTimeout;
|
|
348
353
|
/**
|
|
349
354
|
* Transforms proxy-related errors to `SessionError`.
|
|
350
355
|
*/
|
|
351
|
-
|
|
356
|
+
private throwIfProxyError;
|
|
352
357
|
protected abstract _navigationHandler(crawlingContext: BrowserCrawlingContext<Page, Response>, gotoOptions: GoToOptions): Promise<Context['response'] | null | undefined>;
|
|
353
358
|
private processResponse;
|
|
354
359
|
/**
|
|
@@ -104,10 +104,13 @@ export class BrowserCrawler extends BasicCrawler {
|
|
|
104
104
|
.compose({ action: this.handleBlockedRequestByContent.bind(this) })
|
|
105
105
|
.compose({ action: this.restoreRequestState.bind(this) });
|
|
106
106
|
},
|
|
107
|
-
extendContext
|
|
107
|
+
extendContext,
|
|
108
108
|
});
|
|
109
109
|
this.launchContext = launchContext;
|
|
110
110
|
this.navigationTimeoutMillis = navigationTimeoutSecs * 1000;
|
|
111
|
+
// The public option hooks are extension-aware; internal storage uses the base context type
|
|
112
|
+
// (the pipeline composes hooks against the concrete context, which does not statically carry
|
|
113
|
+
// `ContextExtension`). The extension members are present at runtime regardless.
|
|
111
114
|
this.preNavigationHooks = preNavigationHooks;
|
|
112
115
|
this.postNavigationHooks = postNavigationHooks;
|
|
113
116
|
this.ignoreIframes = ignoreIframes;
|
|
@@ -247,15 +250,15 @@ export class BrowserCrawler extends BasicCrawler {
|
|
|
247
250
|
const gotoOptions = crawlingContext.gotoOptions;
|
|
248
251
|
const cookiesBeforeHooks = readContextField(crawlingContext, COOKIES_BEFORE_HOOKS);
|
|
249
252
|
const cookiesAfterHooks = this._getCookieHeaderFromRequest(crawlingContext.request);
|
|
250
|
-
await this.
|
|
253
|
+
await this.applyCookies(crawlingContext, cookiesBeforeHooks, cookiesAfterHooks);
|
|
251
254
|
let response;
|
|
252
255
|
try {
|
|
253
256
|
response = (await this._navigationHandler(crawlingContext, gotoOptions)) ?? undefined;
|
|
254
257
|
}
|
|
255
258
|
catch (error) {
|
|
256
|
-
await this.
|
|
259
|
+
await this.handleNavigationTimeout(crawlingContext, error);
|
|
257
260
|
crawlingContext.request.state = RequestState.ERROR;
|
|
258
|
-
this.
|
|
261
|
+
this.throwIfProxyError(error);
|
|
259
262
|
throw error;
|
|
260
263
|
}
|
|
261
264
|
tryCancel();
|
|
@@ -304,7 +307,7 @@ export class BrowserCrawler extends BasicCrawler {
|
|
|
304
307
|
crawlingContext.request.state = RequestState.REQUEST_HANDLER;
|
|
305
308
|
return {};
|
|
306
309
|
}
|
|
307
|
-
async
|
|
310
|
+
async applyCookies({ session, request, page }, preHooksCookies, postHooksCookies) {
|
|
308
311
|
const sessionCookie = session?.cookieJar.getCookiesSync(request.url).map(toughCookieToBrowserPoolCookie) ?? [];
|
|
309
312
|
const parsedPreHooksCookies = preHooksCookies.split(/ *; */).map((c) => cookieStringToToughCookie(c));
|
|
310
313
|
const parsedPostHooksCookies = postHooksCookies.split(/ *; */).map((c) => cookieStringToToughCookie(c));
|
|
@@ -316,7 +319,7 @@ export class BrowserCrawler extends BasicCrawler {
|
|
|
316
319
|
/**
|
|
317
320
|
* Marks session bad on navigation timeout, and stops in-flight page loading on any navigation error.
|
|
318
321
|
*/
|
|
319
|
-
async
|
|
322
|
+
async handleNavigationTimeout(crawlingContext, error) {
|
|
320
323
|
const { session, page } = crawlingContext;
|
|
321
324
|
if (error?.constructor.name === 'TimeoutError') {
|
|
322
325
|
handleRequestTimeout({ session, errorMessage: error.message });
|
|
@@ -328,7 +331,7 @@ export class BrowserCrawler extends BasicCrawler {
|
|
|
328
331
|
/**
|
|
329
332
|
* Transforms proxy-related errors to `SessionError`.
|
|
330
333
|
*/
|
|
331
|
-
|
|
334
|
+
throwIfProxyError(error) {
|
|
332
335
|
if (this.isProxyError(error)) {
|
|
333
336
|
throw new SessionError(this._getMessageFromError(error));
|
|
334
337
|
}
|
|
@@ -110,11 +110,11 @@ export declare abstract class BrowserLauncher<Plugin extends BrowserPlugin, Laun
|
|
|
110
110
|
*/
|
|
111
111
|
launch(): LaunchResult;
|
|
112
112
|
createLaunchOptions(): Dictionary;
|
|
113
|
-
protected
|
|
114
|
-
|
|
113
|
+
protected getDefaultHeadlessOption(): boolean;
|
|
114
|
+
private getChromeExecutablePath;
|
|
115
115
|
/**
|
|
116
116
|
* Gets a typical path to Chrome executable, depending on the current operating system.
|
|
117
117
|
*/
|
|
118
|
-
|
|
119
|
-
|
|
118
|
+
private getTypicalChromeExecutablePath;
|
|
119
|
+
private validateProxyUrlProtocol;
|
|
120
120
|
}
|
|
@@ -54,7 +54,7 @@ export class BrowserLauncher {
|
|
|
54
54
|
constructor(launchContext, config = Configuration.getGlobalConfig()) {
|
|
55
55
|
this.config = config;
|
|
56
56
|
const { launcher, proxyUrl, useChrome, userAgent, launchOptions = {}, ...otherLaunchContextProps } = launchContext;
|
|
57
|
-
this.
|
|
57
|
+
this.validateProxyUrlProtocol(proxyUrl);
|
|
58
58
|
// those need to be reassigned otherwise they are {} in types
|
|
59
59
|
this.launcher = launcher;
|
|
60
60
|
this.proxyUrl = proxyUrl;
|
|
@@ -95,23 +95,23 @@ export class BrowserLauncher {
|
|
|
95
95
|
launchOptions.args.push(`--user-agent=${this.userAgent}`);
|
|
96
96
|
}
|
|
97
97
|
if (launchOptions.headless == null) {
|
|
98
|
-
launchOptions.headless = this.
|
|
98
|
+
launchOptions.headless = this.getDefaultHeadlessOption();
|
|
99
99
|
}
|
|
100
100
|
if (this.useChrome && !launchOptions.executablePath) {
|
|
101
|
-
launchOptions.executablePath = this.
|
|
101
|
+
launchOptions.executablePath = this.getChromeExecutablePath();
|
|
102
102
|
}
|
|
103
103
|
return launchOptions;
|
|
104
104
|
}
|
|
105
|
-
|
|
105
|
+
getDefaultHeadlessOption() {
|
|
106
106
|
return this.config.headless && !this.config.xvfb;
|
|
107
107
|
}
|
|
108
|
-
|
|
109
|
-
return this.config.chromeExecutablePath ?? this.
|
|
108
|
+
getChromeExecutablePath() {
|
|
109
|
+
return this.config.chromeExecutablePath ?? this.getTypicalChromeExecutablePath();
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
112
|
* Gets a typical path to Chrome executable, depending on the current operating system.
|
|
113
113
|
*/
|
|
114
|
-
|
|
114
|
+
getTypicalChromeExecutablePath() {
|
|
115
115
|
/**
|
|
116
116
|
* Returns path of Chrome executable by its OS environment variable to deal with non-english language OS.
|
|
117
117
|
* Taking also into account the old [chrome 380177 issue](https://bugs.chromium.org/p/chromium/issues/detail?id=380177).
|
|
@@ -139,7 +139,7 @@ export class BrowserLauncher {
|
|
|
139
139
|
return '/usr/bin/google-chrome';
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
-
|
|
142
|
+
validateProxyUrlProtocol(proxyUrl) {
|
|
143
143
|
if (!proxyUrl)
|
|
144
144
|
return;
|
|
145
145
|
if (!/^(http|https|socks4|socks5)/i.test(proxyUrl)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crawlee/browser",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.82",
|
|
4
4
|
"description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@apify/timeout": "^0.3.2",
|
|
51
|
-
"@crawlee/basic": "4.0.0-beta.
|
|
52
|
-
"@crawlee/browser-pool": "4.0.0-beta.
|
|
53
|
-
"@crawlee/types": "4.0.0-beta.
|
|
54
|
-
"@crawlee/utils": "4.0.0-beta.
|
|
51
|
+
"@crawlee/basic": "4.0.0-beta.82",
|
|
52
|
+
"@crawlee/browser-pool": "4.0.0-beta.82",
|
|
53
|
+
"@crawlee/types": "4.0.0-beta.82",
|
|
54
|
+
"@crawlee/utils": "4.0.0-beta.82",
|
|
55
55
|
"ow": "^2.0.0",
|
|
56
56
|
"tslib": "^2.8.1",
|
|
57
57
|
"type-fest": "^4.41.0"
|
|
@@ -75,5 +75,5 @@
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
},
|
|
78
|
-
"gitHead": "
|
|
78
|
+
"gitHead": "eb1096f7c7743d124375ef011fbbadb19476822e"
|
|
79
79
|
}
|