@crawlee/browser 4.0.0-beta.81 → 4.0.0-beta.83
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/internals/browser-crawler.d.ts +12 -11
- package/internals/browser-crawler.js +37 -37
- package/package.json +6 -6
|
@@ -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
|
*/
|
|
@@ -219,17 +224,13 @@ export interface BrowserCrawlerOptions<Page extends CommonPage = CommonPage, Res
|
|
|
219
224
|
* @category Crawlers
|
|
220
225
|
*/
|
|
221
226
|
export declare abstract class BrowserCrawler<Page extends CommonPage = CommonPage, Response extends BaseResponse = BaseResponse, InternalBrowserPoolOptions extends BrowserPoolOptions = BrowserPoolOptions, LaunchOptions extends Dictionary | undefined = Dictionary, Context extends BrowserCrawlingContext<Page, Response, Dictionary> = BrowserCrawlingContext<Page, Response, Dictionary>, ContextExtension = Dictionary<never>, ExtendedContext extends Context = Context & ContextExtension, GoToOptions extends Dictionary = Dictionary> extends BasicCrawler<Context, ContextExtension, ExtendedContext> {
|
|
227
|
+
/** Backs the {@link BrowserCrawler.browserPool|`browserPool`} getter. */
|
|
228
|
+
private browserPoolDep;
|
|
222
229
|
/**
|
|
223
230
|
* A reference to the underlying browser pool that manages the crawler's browsers. Typed as
|
|
224
231
|
* {@link IBrowserPool} so custom implementations can be plugged in via the `browserPool` constructor option.
|
|
225
232
|
*/
|
|
226
|
-
browserPool: IBrowserPool<Page>;
|
|
227
|
-
/**
|
|
228
|
-
* Set when the crawler constructed its own pool (a {@link BrowserPool}, or a {@link RemoteBrowserPool}
|
|
229
|
-
* built from the `remoteBrowser` option). Holds the same instance as `browserPool` but is the only reference
|
|
230
|
-
* the crawler tears down — a user-supplied `browserPool` is never owned and never destroyed by the crawler.
|
|
231
|
-
*/
|
|
232
|
-
private ownedBrowserPool?;
|
|
233
|
+
get browserPool(): IBrowserPool<Page>;
|
|
233
234
|
launchContext: BrowserLaunchContext<LaunchOptions, unknown>;
|
|
234
235
|
protected readonly ignoreShadowRoots: boolean;
|
|
235
236
|
protected readonly ignoreIframes: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BasicCrawler, browserPoolCookieToToughCookie, ContextPipeline, cookieStringToToughCookie, enqueueLinks, handleRequestTimeout, NavigationSkippedError, RequestState, resolveBaseUrlForEnqueueLinksFiltering, SessionError, toughCookieToBrowserPoolCookie, tryAbsoluteURL, validators, } from '@crawlee/basic';
|
|
1
|
+
import { BasicCrawler, browserPoolCookieToToughCookie, ContextPipeline, cookieStringToToughCookie, enqueueLinks, handleRequestTimeout, NavigationSkippedError, OwnedOrInjected, RequestState, resolveBaseUrlForEnqueueLinksFiltering, SessionError, toughCookieToBrowserPoolCookie, tryAbsoluteURL, validators, } from '@crawlee/basic';
|
|
2
2
|
import { BrowserPool, RemoteBrowserPool } from '@crawlee/browser-pool';
|
|
3
3
|
import { CLOUDFLARE_RETRY_CSS_SELECTORS, RETRY_CSS_SELECTORS, sleep } from '@crawlee/utils';
|
|
4
4
|
import ow from 'ow';
|
|
@@ -48,17 +48,15 @@ const readContextField = (ctx, key) => ctx[key];
|
|
|
48
48
|
* @category Crawlers
|
|
49
49
|
*/
|
|
50
50
|
export class BrowserCrawler extends BasicCrawler {
|
|
51
|
+
/** Backs the {@link BrowserCrawler.browserPool|`browserPool`} getter. */
|
|
52
|
+
browserPoolDep;
|
|
51
53
|
/**
|
|
52
54
|
* A reference to the underlying browser pool that manages the crawler's browsers. Typed as
|
|
53
55
|
* {@link IBrowserPool} so custom implementations can be plugged in via the `browserPool` constructor option.
|
|
54
56
|
*/
|
|
55
|
-
browserPool
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
* built from the `remoteBrowser` option). Holds the same instance as `browserPool` but is the only reference
|
|
59
|
-
* the crawler tears down — a user-supplied `browserPool` is never owned and never destroyed by the crawler.
|
|
60
|
-
*/
|
|
61
|
-
ownedBrowserPool;
|
|
57
|
+
get browserPool() {
|
|
58
|
+
return this.browserPoolDep.value;
|
|
59
|
+
}
|
|
62
60
|
launchContext;
|
|
63
61
|
ignoreShadowRoots;
|
|
64
62
|
ignoreIframes;
|
|
@@ -104,10 +102,13 @@ export class BrowserCrawler extends BasicCrawler {
|
|
|
104
102
|
.compose({ action: this.handleBlockedRequestByContent.bind(this) })
|
|
105
103
|
.compose({ action: this.restoreRequestState.bind(this) });
|
|
106
104
|
},
|
|
107
|
-
extendContext
|
|
105
|
+
extendContext,
|
|
108
106
|
});
|
|
109
107
|
this.launchContext = launchContext;
|
|
110
108
|
this.navigationTimeoutMillis = navigationTimeoutSecs * 1000;
|
|
109
|
+
// The public option hooks are extension-aware; internal storage uses the base context type
|
|
110
|
+
// (the pipeline composes hooks against the concrete context, which does not statically carry
|
|
111
|
+
// `ContextExtension`). The extension members are present at runtime regardless.
|
|
111
112
|
this.preNavigationHooks = preNavigationHooks;
|
|
112
113
|
this.postNavigationHooks = postNavigationHooks;
|
|
113
114
|
this.ignoreIframes = ignoreIframes;
|
|
@@ -117,35 +118,34 @@ export class BrowserCrawler extends BasicCrawler {
|
|
|
117
118
|
this.launchContext.launchOptions.headless = headless;
|
|
118
119
|
}
|
|
119
120
|
this.saveResponseCookies = saveResponseCookies;
|
|
120
|
-
// `browserPool` wins over `remoteBrowser` — a passed-in pool is used as-is, the sugar is ignored.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
121
|
+
// `browserPool` wins over `remoteBrowser` — a passed-in pool is used as-is (borrowed), the sugar is ignored.
|
|
122
|
+
// The default is only built when no pool was injected, so all the option/launchContext fiddling below stays
|
|
123
|
+
// inside the factory.
|
|
124
|
+
this.browserPoolDep = OwnedOrInjected.resolve(browserPool, () => {
|
|
125
|
+
const resolvedBrowserPoolOptions = browserPoolOptions ?? {};
|
|
126
|
+
if (launchContext?.userAgent) {
|
|
127
|
+
if (resolvedBrowserPoolOptions.useFingerprints)
|
|
128
|
+
this.log.info('Custom user agent provided, disabling automatic browser fingerprint injection!');
|
|
129
|
+
resolvedBrowserPoolOptions.useFingerprints = false;
|
|
130
|
+
}
|
|
131
|
+
if (remoteBrowser) {
|
|
132
|
+
// The crawler already built the right plugin for its browser — hand it to a RemoteBrowserPool so the
|
|
133
|
+
// remote connection is always for the matching browser (no plugin to construct, no way to mismatch).
|
|
134
|
+
const { browserPlugins, ...remoteBrowserPoolOptions } = resolvedBrowserPoolOptions;
|
|
135
|
+
return new RemoteBrowserPool({
|
|
136
|
+
browserPlugins: browserPlugins,
|
|
137
|
+
...remoteBrowser,
|
|
138
|
+
browserPoolOptions: remoteBrowserPoolOptions,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
// Double cast: `BrowserPool` implements `IBrowserPool<PageReturn>`, where `PageReturn` is derived from the
|
|
142
|
+
// plugin/controller generics and doesn't overlap with the crawler's free `Page` type param, so TS won't
|
|
143
|
+
// narrow it directly. The concrete pool does satisfy the `Page`/`destroy` contract at runtime — this is the
|
|
144
|
+
// long-standing `Page` variance gap, not a `destroy`-related hole.
|
|
145
|
+
return new BrowserPool({
|
|
146
|
+
...resolvedBrowserPoolOptions,
|
|
139
147
|
});
|
|
140
|
-
this.ownedBrowserPool = remotePool;
|
|
141
|
-
this.browserPool = remotePool;
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
const ownedBrowserPool = new BrowserPool({
|
|
145
|
-
...resolvedBrowserPoolOptions,
|
|
146
148
|
});
|
|
147
|
-
this.ownedBrowserPool = ownedBrowserPool;
|
|
148
|
-
this.browserPool = ownedBrowserPool;
|
|
149
149
|
}
|
|
150
150
|
buildContextPipeline() {
|
|
151
151
|
return ContextPipeline.create().compose({
|
|
@@ -360,7 +360,7 @@ export class BrowserCrawler extends BasicCrawler {
|
|
|
360
360
|
* @ignore
|
|
361
361
|
*/
|
|
362
362
|
async teardown() {
|
|
363
|
-
await this.
|
|
363
|
+
await this.browserPoolDep.ifOwned((pool) => pool.destroy());
|
|
364
364
|
await super.teardown();
|
|
365
365
|
}
|
|
366
366
|
}
|
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.83",
|
|
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.83",
|
|
52
|
+
"@crawlee/browser-pool": "4.0.0-beta.83",
|
|
53
|
+
"@crawlee/types": "4.0.0-beta.83",
|
|
54
|
+
"@crawlee/utils": "4.0.0-beta.83",
|
|
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": "5f25b90c4914d7e097732cf761e440aeba799137"
|
|
79
79
|
}
|