@crawlee/playwright 4.0.0-beta.98 → 4.0.0-rc.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/index.d.ts +1 -0
- package/index.js +1 -0
- package/internals/adaptive-playwright-crawler.d.ts +45 -52
- package/internals/adaptive-playwright-crawler.js +151 -176
- package/internals/enqueue-links/click-elements.d.ts +18 -54
- package/internals/enqueue-links/click-elements.js +27 -51
- package/internals/playwright-browser-pool.d.ts +71 -0
- package/internals/playwright-browser-pool.js +61 -0
- package/internals/playwright-crawler.d.ts +130 -109
- package/internals/playwright-crawler.js +19 -24
- package/internals/playwright-launcher.d.ts +24 -15
- package/internals/playwright-launcher.js +10 -8
- package/internals/utils/playwright-utils.d.ts +5 -7
- package/internals/utils/playwright-utils.js +53 -50
- package/internals/utils/rendering-type-prediction.d.ts +1 -1
- package/internals/utils/rendering-type-prediction.js +44 -27
- package/package.json +11 -12
|
@@ -1,8 +1,24 @@
|
|
|
1
1
|
import { URL } from 'node:url';
|
|
2
|
-
import { applyRequestTransform,
|
|
3
|
-
import
|
|
2
|
+
import { applyRequestTransform, constructUrlPatternObjects, createRequestOptions, filterRequestOptionsByPatterns, parseArgument, urlPatternSchema, Request as CrawleeRequest, schemas, serviceLocator, } from '@crawlee/browser';
|
|
3
|
+
import { z } from 'zod';
|
|
4
4
|
const STARTING_Z_INDEX = 2147400000;
|
|
5
5
|
const getLog = () => serviceLocator.getChildLog('Playwright Click Elements');
|
|
6
|
+
const enqueueLinksByClickingElementsOptionsSchema = z.strictObject({
|
|
7
|
+
page: schemas.objectWithKeys(['goto', 'evaluate']),
|
|
8
|
+
requestManager: schemas.objectWithKeys(['fetchNextRequest', 'addRequestsBatched']),
|
|
9
|
+
selector: z.string(),
|
|
10
|
+
userData: schemas.anyObject.optional(),
|
|
11
|
+
clickOptions: schemas.anyObject.optional(),
|
|
12
|
+
include: schemas.arrayOf(urlPatternSchema, 'URL patterns').optional(),
|
|
13
|
+
exclude: schemas.arrayOf(urlPatternSchema, 'URL patterns').optional(),
|
|
14
|
+
transformRequestFunction: schemas.anyFunction.optional(),
|
|
15
|
+
waitForPageIdleSecs: schemas.anyNumber.default(1),
|
|
16
|
+
maxWaitForPageIdleSecs: schemas.anyNumber.default(5),
|
|
17
|
+
label: z.string().optional(),
|
|
18
|
+
forefront: z.boolean().optional(),
|
|
19
|
+
skipNavigation: z.boolean().optional(),
|
|
20
|
+
onSkippedRequest: schemas.anyFunction.optional(),
|
|
21
|
+
});
|
|
6
22
|
/**
|
|
7
23
|
* The function finds elements matching a specific CSS selector in a Playwright page,
|
|
8
24
|
* clicks all those elements using a mouse move and a left mouse button click and intercepts
|
|
@@ -12,8 +28,7 @@ const getLog = () => serviceLocator.getChildLog('Playwright Click Elements');
|
|
|
12
28
|
* in `href` elements, but rather navigations are triggered in click handlers.
|
|
13
29
|
* If you're looking to find URLs in `href` attributes of the page, see {@link enqueueLinks}.
|
|
14
30
|
*
|
|
15
|
-
* Optionally, the function allows you to filter the target links' URLs using an array of
|
|
16
|
-
* and override settings of the enqueued {@link Request} objects.
|
|
31
|
+
* Optionally, the function allows you to filter the target links' URLs using an array of glob or regexp patterns.
|
|
17
32
|
*
|
|
18
33
|
* **IMPORTANT**: To be able to do this, this function uses various mutations on the page,
|
|
19
34
|
* such as changing the Z-index of elements being clicked and their visibility. Therefore,
|
|
@@ -35,9 +50,9 @@ const getLog = () => serviceLocator.getChildLog('Playwright Click Elements');
|
|
|
35
50
|
* page,
|
|
36
51
|
* requestManager,
|
|
37
52
|
* selector: 'a.product-detail',
|
|
38
|
-
*
|
|
39
|
-
* 'https://www.example.com/handbags
|
|
40
|
-
* 'https://www.example.com/purses
|
|
53
|
+
* include: [
|
|
54
|
+
* 'https://www.example.com/handbags/*',
|
|
55
|
+
* 'https://www.example.com/purses/*',
|
|
41
56
|
* ],
|
|
42
57
|
* });
|
|
43
58
|
* ```
|
|
@@ -45,51 +60,12 @@ const getLog = () => serviceLocator.getChildLog('Playwright Click Elements');
|
|
|
45
60
|
* @returns Promise that resolves to {@link BatchAddRequestsResult} object.
|
|
46
61
|
*/
|
|
47
62
|
export async function enqueueLinksByClickingElements(options) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
requestManager: ow.object.hasKeys('fetchNextRequest', 'addRequestsBatched'),
|
|
51
|
-
selector: ow.string,
|
|
52
|
-
userData: ow.optional.object,
|
|
53
|
-
clickOptions: ow.optional.object,
|
|
54
|
-
pseudoUrls: ow.optional.array.ofType(ow.any(ow.string, ow.object.hasKeys('purl'))),
|
|
55
|
-
globs: ow.optional.array.ofType(ow.any(ow.string, ow.object.hasKeys('glob'))),
|
|
56
|
-
regexps: ow.optional.array.ofType(ow.any(ow.regExp, ow.object.hasKeys('regexp'))),
|
|
57
|
-
exclude: ow.optional.array.ofType(ow.any(ow.string, ow.regExp, ow.object.hasKeys('glob'), ow.object.hasKeys('regexp'))),
|
|
58
|
-
transformRequestFunction: ow.optional.function,
|
|
59
|
-
waitForPageIdleSecs: ow.optional.number,
|
|
60
|
-
maxWaitForPageIdleSecs: ow.optional.number,
|
|
61
|
-
label: ow.optional.string,
|
|
62
|
-
forefront: ow.optional.boolean,
|
|
63
|
-
skipNavigation: ow.optional.boolean,
|
|
64
|
-
onSkippedRequest: ow.optional.function,
|
|
65
|
-
}));
|
|
66
|
-
const { page, requestManager, selector, clickOptions,
|
|
67
|
-
// oxlint-disable-next-line typescript/no-deprecated -- still accepted for backwards compat
|
|
68
|
-
pseudoUrls, globs, regexps, transformRequestFunction, waitForPageIdleSecs = 1, maxWaitForPageIdleSecs = 5, forefront, exclude, onSkippedRequest, } = options;
|
|
63
|
+
const parsedOptions = parseArgument(options, enqueueLinksByClickingElementsOptionsSchema, 'EnqueueLinksByClickingElementsOptions');
|
|
64
|
+
const { page, requestManager, selector, clickOptions, include, exclude, transformRequestFunction, waitForPageIdleSecs, maxWaitForPageIdleSecs, forefront, onSkippedRequest, } = parsedOptions;
|
|
69
65
|
const waitForPageIdleMillis = waitForPageIdleSecs * 1000;
|
|
70
66
|
const maxWaitForPageIdleMillis = maxWaitForPageIdleSecs * 1000;
|
|
71
|
-
const urlExcludePatternObjects = [];
|
|
72
|
-
const urlPatternObjects = [];
|
|
73
|
-
if (exclude?.length) {
|
|
74
|
-
for (const excl of exclude) {
|
|
75
|
-
if (typeof excl === 'string' || 'glob' in excl) {
|
|
76
|
-
urlExcludePatternObjects.push(...constructGlobObjectsFromGlobs([excl]));
|
|
77
|
-
}
|
|
78
|
-
else if (excl instanceof RegExp || 'regexp' in excl) {
|
|
79
|
-
urlExcludePatternObjects.push(...constructRegExpObjectsFromRegExps([excl]));
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
if (pseudoUrls?.length) {
|
|
84
|
-
serviceLocator.getLogger().deprecated('`pseudoUrls` option is deprecated, use `globs` or `regexps` instead');
|
|
85
|
-
urlPatternObjects.push(...constructRegExpObjectsFromPseudoUrls(pseudoUrls));
|
|
86
|
-
}
|
|
87
|
-
if (globs?.length) {
|
|
88
|
-
urlPatternObjects.push(...constructGlobObjectsFromGlobs(globs));
|
|
89
|
-
}
|
|
90
|
-
if (regexps?.length) {
|
|
91
|
-
urlPatternObjects.push(...constructRegExpObjectsFromRegExps(regexps));
|
|
92
|
-
}
|
|
67
|
+
const urlExcludePatternObjects = exclude?.length ? constructUrlPatternObjects(exclude) : [];
|
|
68
|
+
const urlPatternObjects = include?.length ? constructUrlPatternObjects(include) : [];
|
|
93
69
|
const interceptedRequests = await clickElementsAndInterceptNavigationRequests({
|
|
94
70
|
page,
|
|
95
71
|
selector,
|
|
@@ -97,7 +73,7 @@ export async function enqueueLinksByClickingElements(options) {
|
|
|
97
73
|
maxWaitForPageIdleMillis,
|
|
98
74
|
clickOptions,
|
|
99
75
|
});
|
|
100
|
-
const requestOptions = createRequestOptions(interceptedRequests,
|
|
76
|
+
const requestOptions = createRequestOptions(interceptedRequests, parsedOptions);
|
|
101
77
|
const skippedByFilters = [];
|
|
102
78
|
let filteredOptions = filterRequestOptionsByPatterns(requestOptions, urlPatternObjects.length > 0 ? urlPatternObjects : undefined, urlExcludePatternObjects, undefined, (url) => skippedByFilters.push(url));
|
|
103
79
|
if (onSkippedRequest && skippedByFilters.length > 0) {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Configuration } from '@crawlee/browser';
|
|
2
|
+
import type { BrowserPool, BrowserPoolHooks, BrowserPoolOptions, PlaywrightPlugin, RemoteBrowserPool, RemoteBrowserPoolOptions } from '@crawlee/browser-pool';
|
|
3
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
4
|
+
import type { Page } from 'playwright';
|
|
5
|
+
import type { PlaywrightLaunchContext } from './playwright-launcher.js';
|
|
6
|
+
/** A {@link BrowserPool} of Playwright browsers, as built by {@link playwrightBrowserPool}. */
|
|
7
|
+
export type PlaywrightBrowserPool = BrowserPool<{
|
|
8
|
+
browserPlugins: [PlaywrightPlugin];
|
|
9
|
+
}, [PlaywrightPlugin]>;
|
|
10
|
+
export interface PlaywrightBrowserPoolOptions extends Omit<BrowserPoolOptions, 'browserPlugins'>, BrowserPoolHooks<ReturnType<PlaywrightPlugin['createController']>, ReturnType<PlaywrightPlugin['createLaunchContext']>, Page> {
|
|
11
|
+
/** How to launch the browser: which Playwright browser type, proxy, user data dir, ... */
|
|
12
|
+
launchContext?: PlaywrightLaunchContext;
|
|
13
|
+
/**
|
|
14
|
+
* Whether to run the browser in headless mode. Shorthand for `launchContext.launchOptions.headless`.
|
|
15
|
+
* Defaults to `true`, and can also be set via {@link Configuration}.
|
|
16
|
+
*/
|
|
17
|
+
headless?: boolean;
|
|
18
|
+
/** Configuration to read the browser defaults from. Defaults to the global configuration. */
|
|
19
|
+
configuration?: Configuration;
|
|
20
|
+
}
|
|
21
|
+
export interface RemotePlaywrightBrowserPoolOptions extends Pick<PlaywrightBrowserPoolOptions, 'launchContext' | 'headless' | 'configuration'>, Omit<RemoteBrowserPoolOptions, 'browserPlugins'> {
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Builds a {@link BrowserPool} of Playwright browsers to pass to a {@link PlaywrightCrawler} as its
|
|
25
|
+
* {@link BrowserCrawlerOptions.browserPool|`browserPool`}.
|
|
26
|
+
*
|
|
27
|
+
* It accepts every {@link BrowserPoolOptions|`BrowserPool` option} plus the crawler's own `launchContext` and
|
|
28
|
+
* `headless`, and derives the browser plugin from them - so a pool built here always matches the crawler it is
|
|
29
|
+
* given to, and configuring one never means assembling a {@link PlaywrightPlugin} by hand.
|
|
30
|
+
*
|
|
31
|
+
* **Example usage:**
|
|
32
|
+
*
|
|
33
|
+
* ```javascript
|
|
34
|
+
* const crawler = new PlaywrightCrawler({
|
|
35
|
+
* browserPool: playwrightBrowserPool({
|
|
36
|
+
* maxOpenPagesPerBrowser: 1,
|
|
37
|
+
* launchContext: { launcher: firefox },
|
|
38
|
+
* }),
|
|
39
|
+
* requestHandler: async ({ page }) => { ... },
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* The returned pool is *not* torn down by the crawler, which is what makes it shareable between crawlers.
|
|
44
|
+
*
|
|
45
|
+
* @category Browser management
|
|
46
|
+
*/
|
|
47
|
+
export declare function playwrightBrowserPool(options?: PlaywrightBrowserPoolOptions): PlaywrightBrowserPool;
|
|
48
|
+
/**
|
|
49
|
+
* The {@link RemoteBrowserPool} counterpart of {@link playwrightBrowserPool}: connects to a remote browser
|
|
50
|
+
* service (Browserbase, Browserless, Steel, ...) with a Playwright plugin derived from `launchContext`.
|
|
51
|
+
*
|
|
52
|
+
* A {@link PlaywrightCrawler} accepts the same connection details directly via
|
|
53
|
+
* {@link BrowserCrawlerOptions.remoteBrowser|`remoteBrowser`}; reach for this factory when you also need to
|
|
54
|
+
* tune the wrapping pool, or to share one remote pool between crawlers.
|
|
55
|
+
*
|
|
56
|
+
* **Example usage:**
|
|
57
|
+
*
|
|
58
|
+
* ```javascript
|
|
59
|
+
* const crawler = new PlaywrightCrawler({
|
|
60
|
+
* browserPool: remotePlaywrightBrowserPool({
|
|
61
|
+
* endpoint: 'wss://production-sfo.browserless.io?token=xxx',
|
|
62
|
+
* maxOpenBrowsers: 2,
|
|
63
|
+
* browserPoolOptions: { useFingerprints: false },
|
|
64
|
+
* }),
|
|
65
|
+
* requestHandler: async ({ page }) => { ... },
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*
|
|
69
|
+
* @category Browser management
|
|
70
|
+
*/
|
|
71
|
+
export declare function remotePlaywrightBrowserPool(options: RemotePlaywrightBrowserPoolOptions): RemoteBrowserPool<Page>;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { PlaywrightLauncher } from './playwright-launcher.js';
|
|
2
|
+
/**
|
|
3
|
+
* Builds a {@link BrowserPool} of Playwright browsers to pass to a {@link PlaywrightCrawler} as its
|
|
4
|
+
* {@link BrowserCrawlerOptions.browserPool|`browserPool`}.
|
|
5
|
+
*
|
|
6
|
+
* It accepts every {@link BrowserPoolOptions|`BrowserPool` option} plus the crawler's own `launchContext` and
|
|
7
|
+
* `headless`, and derives the browser plugin from them - so a pool built here always matches the crawler it is
|
|
8
|
+
* given to, and configuring one never means assembling a {@link PlaywrightPlugin} by hand.
|
|
9
|
+
*
|
|
10
|
+
* **Example usage:**
|
|
11
|
+
*
|
|
12
|
+
* ```javascript
|
|
13
|
+
* const crawler = new PlaywrightCrawler({
|
|
14
|
+
* browserPool: playwrightBrowserPool({
|
|
15
|
+
* maxOpenPagesPerBrowser: 1,
|
|
16
|
+
* launchContext: { launcher: firefox },
|
|
17
|
+
* }),
|
|
18
|
+
* requestHandler: async ({ page }) => { ... },
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* The returned pool is *not* torn down by the crawler, which is what makes it shareable between crawlers.
|
|
23
|
+
*
|
|
24
|
+
* @category Browser management
|
|
25
|
+
*/
|
|
26
|
+
export function playwrightBrowserPool(options = {}) {
|
|
27
|
+
const { launchContext, headless, configuration, ...poolOptions } = options;
|
|
28
|
+
return playwrightLauncher(launchContext, headless, configuration).createBrowserPool(poolOptions);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The {@link RemoteBrowserPool} counterpart of {@link playwrightBrowserPool}: connects to a remote browser
|
|
32
|
+
* service (Browserbase, Browserless, Steel, ...) with a Playwright plugin derived from `launchContext`.
|
|
33
|
+
*
|
|
34
|
+
* A {@link PlaywrightCrawler} accepts the same connection details directly via
|
|
35
|
+
* {@link BrowserCrawlerOptions.remoteBrowser|`remoteBrowser`}; reach for this factory when you also need to
|
|
36
|
+
* tune the wrapping pool, or to share one remote pool between crawlers.
|
|
37
|
+
*
|
|
38
|
+
* **Example usage:**
|
|
39
|
+
*
|
|
40
|
+
* ```javascript
|
|
41
|
+
* const crawler = new PlaywrightCrawler({
|
|
42
|
+
* browserPool: remotePlaywrightBrowserPool({
|
|
43
|
+
* endpoint: 'wss://production-sfo.browserless.io?token=xxx',
|
|
44
|
+
* maxOpenBrowsers: 2,
|
|
45
|
+
* browserPoolOptions: { useFingerprints: false },
|
|
46
|
+
* }),
|
|
47
|
+
* requestHandler: async ({ page }) => { ... },
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* @category Browser management
|
|
52
|
+
*/
|
|
53
|
+
export function remotePlaywrightBrowserPool(options) {
|
|
54
|
+
const { launchContext, headless, configuration, ...remoteOptions } = options;
|
|
55
|
+
return playwrightLauncher(launchContext, headless, configuration).createRemoteBrowserPool(remoteOptions);
|
|
56
|
+
}
|
|
57
|
+
function playwrightLauncher(launchContext = {}, headless, configuration) {
|
|
58
|
+
return new PlaywrightLauncher(headless == null
|
|
59
|
+
? launchContext
|
|
60
|
+
: { ...launchContext, launchOptions: { ...launchContext.launchOptions, headless } }, configuration);
|
|
61
|
+
}
|
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
import type { BrowserCrawlerOptions, BrowserCrawlingContext, BrowserHook, GetUserDataFromRequest, RequestHandler, RouterHandler, RouterRoutes, RouteSchemas, RoutesFromSchemas } from '@crawlee/browser';
|
|
2
2
|
import { BrowserCrawler } from '@crawlee/browser';
|
|
3
|
-
import type { PlaywrightPlugin } from '@crawlee/browser-pool';
|
|
4
3
|
import type { Dictionary } from '@crawlee/types';
|
|
5
4
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
6
5
|
import type { Download, LaunchOptions, Page, Response } from 'playwright';
|
|
6
|
+
import { z } from 'zod';
|
|
7
7
|
import type { EnqueueLinksByClickingElementsOptions } from './enqueue-links/click-elements.js';
|
|
8
8
|
import type { PlaywrightLaunchContext } from './playwright-launcher.js';
|
|
9
9
|
import type { BlockRequestsOptions, DirectNavigationOptions, HandleCloudflareChallengeOptions, InfiniteScrollOptions, InjectFileOptions, PlaywrightContextUtils, SaveSnapshotOptions } from './utils/playwright-utils.js';
|
|
10
10
|
export type PlaywrightGotoOptions = NonNullable<Parameters<Page['goto']>[1]>;
|
|
11
|
-
export interface PlaywrightCrawlingContext<UserData extends Dictionary =
|
|
11
|
+
export interface PlaywrightCrawlingContext<UserData extends Dictionary = any> extends BrowserCrawlingContext<Page, Response, UserData, PlaywrightGotoOptions>, PlaywrightContextUtils {
|
|
12
12
|
}
|
|
13
|
-
|
|
14
|
-
export interface
|
|
15
|
-
}
|
|
16
|
-
export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>, ExtendedContext extends PlaywrightCrawlingContext = PlaywrightCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<PlaywrightCrawlingContext['request']>>> extends BrowserCrawlerOptions<Page, Response, PlaywrightCrawlingContext, ContextExtension, ExtendedContext, {
|
|
17
|
-
browserPlugins: [PlaywrightPlugin];
|
|
18
|
-
}, Routes> {
|
|
13
|
+
export type PlaywrightHook<UserData extends Dictionary = any> = BrowserHook<PlaywrightCrawlingContext<UserData>>;
|
|
14
|
+
export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>, ExtendedContext extends PlaywrightCrawlingContext = PlaywrightCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<PlaywrightCrawlingContext['request']>>, StatisticStateExtension extends object = {}> extends BrowserCrawlerOptions<Page, Response, PlaywrightCrawlingContext, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> {
|
|
19
15
|
/**
|
|
20
16
|
* The same options as used by {@link launchPlaywright}.
|
|
21
17
|
*/
|
|
22
18
|
launchContext?: PlaywrightLaunchContext;
|
|
19
|
+
/**
|
|
20
|
+
* Whether to run browser in headless mode. Defaults to `true`.
|
|
21
|
+
* Can be also set via {@link Configuration}.
|
|
22
|
+
*/
|
|
23
|
+
headless?: boolean;
|
|
23
24
|
/**
|
|
24
25
|
* Function that is called to process each request.
|
|
25
26
|
*
|
|
@@ -59,7 +60,7 @@ export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>,
|
|
|
59
60
|
* ]
|
|
60
61
|
* ```
|
|
61
62
|
*/
|
|
62
|
-
preNavigationHooks?: BrowserHook<PlaywrightCrawlingContext
|
|
63
|
+
preNavigationHooks?: BrowserHook<PlaywrightCrawlingContext<GetUserDataFromRequest<ExtendedContext['request']>>, ContextExtension>[];
|
|
63
64
|
/**
|
|
64
65
|
* Async functions that are sequentially evaluated after the navigation. Good for checking if the navigation was successful.
|
|
65
66
|
* The function accepts `crawlingContext` as the only parameter. A hook may optionally return a partial object
|
|
@@ -76,7 +77,7 @@ export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>,
|
|
|
76
77
|
* ]
|
|
77
78
|
* ```
|
|
78
79
|
*/
|
|
79
|
-
postNavigationHooks?: BrowserHook<PlaywrightCrawlingContext
|
|
80
|
+
postNavigationHooks?: BrowserHook<PlaywrightCrawlingContext<GetUserDataFromRequest<ExtendedContext['request']>>, ContextExtension>[];
|
|
80
81
|
}
|
|
81
82
|
/**
|
|
82
83
|
* Provides a simple framework for parallel crawling of web pages
|
|
@@ -143,109 +144,129 @@ export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>,
|
|
|
143
144
|
* ```
|
|
144
145
|
* @category Crawlers
|
|
145
146
|
*/
|
|
146
|
-
export declare class PlaywrightCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends PlaywrightCrawlingContext = PlaywrightCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<PlaywrightCrawlingContext['request']
|
|
147
|
-
browserPlugins: [PlaywrightPlugin];
|
|
148
|
-
}, LaunchOptions, PlaywrightCrawlingContext, ContextExtension, ExtendedContext, Routes> {
|
|
147
|
+
export declare class PlaywrightCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends PlaywrightCrawlingContext = PlaywrightCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<PlaywrightCrawlingContext['request']>>, StatisticStateExtension extends object = {}> extends BrowserCrawler<Page, Response, LaunchOptions, PlaywrightCrawlingContext, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> {
|
|
149
148
|
protected static optionsShape: {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
statusMessageLoggingInterval: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
208
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
209
|
-
statusMessageCallback: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
210
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
211
|
-
additionalHttpErrorStatusCodes: import("ow").ArrayPredicate<number>;
|
|
212
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
213
|
-
ignoreHttpErrorStatusCodes: import("ow").ArrayPredicate<number>;
|
|
214
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
215
|
-
blockedStatusCodes: import("ow").ArrayPredicate<number>;
|
|
216
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
217
|
-
retryOnBlocked: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
|
|
218
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
219
|
-
respectRobotsTxtFile: import("ow").AnyPredicate<boolean | object>;
|
|
220
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
221
|
-
onSkippedRequest: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
222
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
223
|
-
httpClient: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
224
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
225
|
-
configuration: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
226
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
227
|
-
storageBackend: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
228
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
229
|
-
eventManager: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
230
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
231
|
-
logger: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
232
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
233
|
-
minConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
234
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
235
|
-
maxConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
236
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
237
|
-
maxRequestsPerMinute: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
238
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
239
|
-
keepAlive: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
|
|
240
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
241
|
-
statisticsOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
242
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
243
|
-
id: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
|
|
149
|
+
headless: z.ZodOptional<z.ZodBoolean>;
|
|
150
|
+
launcher: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
151
|
+
navigationTimeoutSecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
152
|
+
preNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
153
|
+
postNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
154
|
+
launchContext: z.ZodDefault<z.ZodCustom<Dictionary, Dictionary>>;
|
|
155
|
+
browserPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
156
|
+
browserPoolBuilder: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
157
|
+
remoteBrowser: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
158
|
+
saveResponseCookies: z.ZodDefault<z.ZodBoolean>;
|
|
159
|
+
proxyConfiguration: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
160
|
+
ignoreIframes: z.ZodDefault<z.ZodBoolean>;
|
|
161
|
+
ignoreShadowRoots: z.ZodDefault<z.ZodBoolean>;
|
|
162
|
+
contextPipelineBuilder: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
163
|
+
extendContext: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
164
|
+
requestList: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
165
|
+
requestQueue: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
166
|
+
requestManager: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
167
|
+
requestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
168
|
+
requestHandlerTimeoutSecs: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
169
|
+
errorHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
170
|
+
failedRequestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
171
|
+
maxRequestRetries: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
172
|
+
sameDomainDelaySecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
173
|
+
maxRequestsPerCrawl: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
174
|
+
maxCrawlDepth: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
175
|
+
taskLoopOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
176
|
+
concurrencySystem: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
177
|
+
sessionPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
178
|
+
statusMessageLoggingInterval: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
179
|
+
statusMessageCallback: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
180
|
+
additionalHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
181
|
+
ignoreHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
182
|
+
blockedStatusCodes: z.ZodOptional<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
183
|
+
retryOnBlocked: z.ZodDefault<z.ZodBoolean>;
|
|
184
|
+
respectRobotsTxtFile: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCustom<Dictionary, Dictionary>]>>;
|
|
185
|
+
transactionalStorage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
186
|
+
requestQueue: z.ZodOptional<z.ZodEnum<{
|
|
187
|
+
deferred: "deferred";
|
|
188
|
+
writeThrough: "writeThrough";
|
|
189
|
+
}>>;
|
|
190
|
+
}, z.core.$strict>]>>;
|
|
191
|
+
onSkippedRequest: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
192
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
193
|
+
httpClient: z.ZodOptional<z.ZodCustom<import("@crawlee/http-client").BaseHttpClient, import("@crawlee/http-client").BaseHttpClient>>;
|
|
194
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
195
|
+
configuration: z.ZodOptional<z.ZodCustom<import("@crawlee/browser").Configuration, import("@crawlee/browser").Configuration>>;
|
|
196
|
+
storageBackend: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
197
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
198
|
+
eventManager: z.ZodOptional<z.ZodCustom<import("@crawlee/browser").EventManager, import("@crawlee/browser").EventManager>>;
|
|
199
|
+
logger: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
200
|
+
minConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
201
|
+
maxConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
202
|
+
maxRequestsPerMinute: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
203
|
+
keepAlive: z.ZodOptional<z.ZodBoolean>;
|
|
204
|
+
statistics: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
205
|
+
id: z.ZodOptional<z.ZodString>;
|
|
244
206
|
};
|
|
207
|
+
protected static optionsSchema: z.ZodObject<{
|
|
208
|
+
headless: z.ZodOptional<z.ZodBoolean>;
|
|
209
|
+
launcher: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
210
|
+
navigationTimeoutSecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
211
|
+
preNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
212
|
+
postNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
213
|
+
launchContext: z.ZodDefault<z.ZodCustom<Dictionary, Dictionary>>;
|
|
214
|
+
browserPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
215
|
+
browserPoolBuilder: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
216
|
+
remoteBrowser: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
217
|
+
saveResponseCookies: z.ZodDefault<z.ZodBoolean>;
|
|
218
|
+
proxyConfiguration: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
219
|
+
ignoreIframes: z.ZodDefault<z.ZodBoolean>;
|
|
220
|
+
ignoreShadowRoots: z.ZodDefault<z.ZodBoolean>;
|
|
221
|
+
contextPipelineBuilder: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
222
|
+
extendContext: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
223
|
+
requestList: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
224
|
+
requestQueue: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
225
|
+
requestManager: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
226
|
+
requestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
227
|
+
requestHandlerTimeoutSecs: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
228
|
+
errorHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
229
|
+
failedRequestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
230
|
+
maxRequestRetries: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
231
|
+
sameDomainDelaySecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
232
|
+
maxRequestsPerCrawl: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
233
|
+
maxCrawlDepth: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
234
|
+
taskLoopOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
235
|
+
concurrencySystem: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
236
|
+
sessionPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
237
|
+
statusMessageLoggingInterval: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
238
|
+
statusMessageCallback: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
239
|
+
additionalHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
240
|
+
ignoreHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
241
|
+
blockedStatusCodes: z.ZodOptional<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
242
|
+
retryOnBlocked: z.ZodDefault<z.ZodBoolean>;
|
|
243
|
+
respectRobotsTxtFile: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCustom<Dictionary, Dictionary>]>>;
|
|
244
|
+
transactionalStorage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
245
|
+
requestQueue: z.ZodOptional<z.ZodEnum<{
|
|
246
|
+
deferred: "deferred";
|
|
247
|
+
writeThrough: "writeThrough";
|
|
248
|
+
}>>;
|
|
249
|
+
}, z.core.$strict>]>>;
|
|
250
|
+
onSkippedRequest: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
251
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
252
|
+
httpClient: z.ZodOptional<z.ZodCustom<import("@crawlee/http-client").BaseHttpClient, import("@crawlee/http-client").BaseHttpClient>>;
|
|
253
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
254
|
+
configuration: z.ZodOptional<z.ZodCustom<import("@crawlee/browser").Configuration, import("@crawlee/browser").Configuration>>;
|
|
255
|
+
storageBackend: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
256
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
257
|
+
eventManager: z.ZodOptional<z.ZodCustom<import("@crawlee/browser").EventManager, import("@crawlee/browser").EventManager>>;
|
|
258
|
+
logger: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
259
|
+
minConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
260
|
+
maxConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
261
|
+
maxRequestsPerMinute: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
262
|
+
keepAlive: z.ZodOptional<z.ZodBoolean>;
|
|
263
|
+
statistics: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
264
|
+
id: z.ZodOptional<z.ZodString>;
|
|
265
|
+
}, z.core.$strict>;
|
|
245
266
|
/**
|
|
246
267
|
* All `PlaywrightCrawler` parameters are passed via an options object.
|
|
247
268
|
*/
|
|
248
|
-
constructor(options?: PlaywrightCrawlerOptions<ContextExtension, ExtendedContext, Routes>);
|
|
269
|
+
constructor(options?: PlaywrightCrawlerOptions<ContextExtension, ExtendedContext, Routes, StatisticStateExtension>);
|
|
249
270
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
250
271
|
protected buildContextPipeline(): import("@crawlee/browser").ContextPipeline<import("@crawlee/browser").CrawlingContext<Dictionary>, BrowserCrawlingContext<Page, Response, Dictionary, Dictionary> & {
|
|
251
272
|
injectFile: (filePath: string, options?: InjectFileOptions) => Promise<unknown>;
|
|
@@ -264,7 +285,7 @@ export declare class PlaywrightCrawler<ContextExtension = Dictionary<never>, Ext
|
|
|
264
285
|
closeCookieModals: () => Promise<void>;
|
|
265
286
|
handleCloudflareChallenge: (options?: HandleCloudflareChallengeOptions) => Promise<Response | undefined>;
|
|
266
287
|
}>;
|
|
267
|
-
protected
|
|
288
|
+
protected navigationHandler(crawlingContext: PlaywrightCrawlingContext, gotoOptions: DirectNavigationOptions): Promise<Response | null>;
|
|
268
289
|
private enhanceContext;
|
|
269
290
|
}
|
|
270
291
|
/**
|