@crawlee/playwright 4.0.0-beta.99 → 4.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,48 +1,25 @@
1
- import type { BrowserCrawlerOptions, BrowserCrawlingContext, BrowserHook, GetUserDataFromRequest, RequestHandler, RouterHandler, RouterRoutes, RouteSchemas, RoutesFromSchemas } from '@crawlee/browser';
1
+ import type { BrowserCrawlerOptions, BrowserCrawlingContext, BrowserHook, GetUserDataFromRequest, 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
- import type { Download, LaunchOptions, Page, Response } from 'playwright';
7
- import type { EnqueueLinksByClickingElementsOptions } from './enqueue-links/click-elements.js';
5
+ import type { Page, Response } from 'playwright';
6
+ import { z } from 'zod';
8
7
  import type { PlaywrightLaunchContext } from './playwright-launcher.js';
9
- import type { BlockRequestsOptions, DirectNavigationOptions, HandleCloudflareChallengeOptions, InfiniteScrollOptions, InjectFileOptions, PlaywrightContextUtils, SaveSnapshotOptions } from './utils/playwright-utils.js';
8
+ import type { DirectNavigationOptions, HandleCloudflareChallengeOptions, PlaywrightContextUtils } from './utils/playwright-utils.js';
10
9
  export type PlaywrightGotoOptions = NonNullable<Parameters<Page['goto']>[1]>;
11
- export interface PlaywrightCrawlingContext<UserData extends Dictionary = Dictionary> extends BrowserCrawlingContext<Page, Response, UserData, PlaywrightGotoOptions>, PlaywrightContextUtils {
10
+ export interface PlaywrightCrawlingContext<UserData extends Dictionary = any> extends BrowserCrawlingContext<Page, Response, UserData, PlaywrightGotoOptions>, PlaywrightContextUtils {
12
11
  }
13
- // @ts-ignore optional peer dependency or compatibility with es2022
14
- export interface PlaywrightHook extends BrowserHook<PlaywrightCrawlingContext> {
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> {
12
+ export type PlaywrightHook<UserData extends Dictionary = any> = BrowserHook<PlaywrightCrawlingContext<UserData>>;
13
+ 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
14
  /**
20
15
  * The same options as used by {@link launchPlaywright}.
21
16
  */
22
17
  launchContext?: PlaywrightLaunchContext;
23
18
  /**
24
- * Function that is called to process each request.
25
- *
26
- * The function receives the {@link PlaywrightCrawlingContext} as an argument, where:
27
- * - `request` is an instance of the {@link Request} object with details about the URL to open, HTTP method etc.
28
- * - `page` is an instance of the `Playwright`
29
- * [`Page`](https://playwright.dev/docs/api/class-page)
30
- * - `response` is an instance of the `Playwright`
31
- * [`Response`](https://playwright.dev/docs/api/class-response),
32
- * which is the main resource response as returned by `page.goto(request.url)`.
33
- *
34
- * The function must return a promise, which is then awaited by the crawler.
35
- *
36
- * If the function throws an exception, the crawler will try to re-crawl the
37
- * request later, up to `option.maxRequestRetries` times.
38
- * If all the retries fail, the crawler calls the function
39
- * provided to the `failedRequestHandler` parameter.
40
- * To make this work, you should **always**
41
- * let your function throw exceptions rather than catch them.
42
- * The exceptions are logged to the request using the
43
- * {@link Request.pushErrorMessage} function.
19
+ * Whether to run browser in headless mode. Defaults to `true`.
20
+ * Can be also set via {@link Configuration}.
44
21
  */
45
- requestHandler?: RouterHandler<ExtendedContext, Routes> | RequestHandler<ExtendedContext>;
22
+ headless?: boolean;
46
23
  /**
47
24
  * Async functions that are sequentially evaluated before the navigation. Good for setting additional cookies
48
25
  * or browser properties before navigation. The function receives the `crawlingContext`; the options object
@@ -59,7 +36,7 @@ export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>,
59
36
  * ]
60
37
  * ```
61
38
  */
62
- preNavigationHooks?: BrowserHook<PlaywrightCrawlingContext, ContextExtension>[];
39
+ preNavigationHooks?: BrowserHook<PlaywrightCrawlingContext<GetUserDataFromRequest<ExtendedContext['request']>>, ContextExtension>[];
63
40
  /**
64
41
  * Async functions that are sequentially evaluated after the navigation. Good for checking if the navigation was successful.
65
42
  * The function accepts `crawlingContext` as the only parameter. A hook may optionally return a partial object
@@ -76,7 +53,7 @@ export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>,
76
53
  * ]
77
54
  * ```
78
55
  */
79
- postNavigationHooks?: BrowserHook<PlaywrightCrawlingContext, ContextExtension>[];
56
+ postNavigationHooks?: BrowserHook<PlaywrightCrawlingContext<GetUserDataFromRequest<ExtendedContext['request']>>, ContextExtension>[];
80
57
  }
81
58
  /**
82
59
  * Provides a simple framework for parallel crawling of web pages
@@ -143,129 +120,135 @@ export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>,
143
120
  * ```
144
121
  * @category Crawlers
145
122
  */
146
- export declare class PlaywrightCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends PlaywrightCrawlingContext = PlaywrightCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<PlaywrightCrawlingContext['request']>>> extends BrowserCrawler<Page, Response, {
147
- browserPlugins: [PlaywrightPlugin];
148
- }, LaunchOptions, PlaywrightCrawlingContext, ContextExtension, ExtendedContext, Routes> {
123
+ 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, PlaywrightCrawlingContext, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> {
124
+ #private;
125
+ /**
126
+ * @internal
127
+ */
149
128
  protected static optionsShape: {
150
- // @ts-ignore optional peer dependency or compatibility with es2022
151
- browserPoolOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
152
- // @ts-ignore optional peer dependency or compatibility with es2022
153
- launcher: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
154
- // @ts-ignore optional peer dependency or compatibility with es2022
155
- ignoreIframes: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
156
- // @ts-ignore optional peer dependency or compatibility with es2022
157
- ignoreShadowRoots: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
158
- // @ts-ignore optional peer dependency or compatibility with es2022
159
- navigationTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
160
- // @ts-ignore optional peer dependency or compatibility with es2022
161
- preNavigationHooks: import("ow").ArrayPredicate<unknown> & import("ow").BasePredicate<unknown[] | undefined>;
162
- // @ts-ignore optional peer dependency or compatibility with es2022
163
- postNavigationHooks: import("ow").ArrayPredicate<unknown> & import("ow").BasePredicate<unknown[] | undefined>;
164
- // @ts-ignore optional peer dependency or compatibility with es2022
165
- launchContext: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
166
- // @ts-ignore optional peer dependency or compatibility with es2022
167
- headless: import("ow").AnyPredicate<string | boolean>;
168
- // @ts-ignore optional peer dependency or compatibility with es2022
169
- browserPool: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
170
- // @ts-ignore optional peer dependency or compatibility with es2022
171
- remoteBrowser: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
172
- // @ts-ignore optional peer dependency or compatibility with es2022
173
- saveResponseCookies: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
174
- // @ts-ignore optional peer dependency or compatibility with es2022
175
- proxyConfiguration: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
176
- // @ts-ignore optional peer dependency or compatibility with es2022
177
- contextPipelineBuilder: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
178
- // @ts-ignore optional peer dependency or compatibility with es2022
179
- extendContext: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
180
- // @ts-ignore optional peer dependency or compatibility with es2022
181
- requestList: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
182
- // @ts-ignore optional peer dependency or compatibility with es2022
183
- requestQueue: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
184
- // @ts-ignore optional peer dependency or compatibility with es2022
185
- requestHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
186
- // @ts-ignore optional peer dependency or compatibility with es2022
187
- requestHandlerTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
188
- // @ts-ignore optional peer dependency or compatibility with es2022
189
- errorHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
190
- // @ts-ignore optional peer dependency or compatibility with es2022
191
- failedRequestHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
192
- // @ts-ignore optional peer dependency or compatibility with es2022
193
- maxRequestRetries: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
194
- // @ts-ignore optional peer dependency or compatibility with es2022
195
- sameDomainDelaySecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
196
- // @ts-ignore optional peer dependency or compatibility with es2022
197
- maxRequestsPerCrawl: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
198
- // @ts-ignore optional peer dependency or compatibility with es2022
199
- maxCrawlDepth: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
200
- // @ts-ignore optional peer dependency or compatibility with es2022
201
- taskLoopOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
202
- // @ts-ignore optional peer dependency or compatibility with es2022
203
- concurrencySystem: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
204
- // @ts-ignore optional peer dependency or compatibility with es2022
205
- sessionPool: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
206
- // @ts-ignore optional peer dependency or compatibility with es2022
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>;
129
+ contextPipelineBuilder: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
130
+ extendContext: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
131
+ requestList: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
132
+ requestQueue: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
133
+ requestManager: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
134
+ requestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
135
+ requestHandlerTimeoutSecs: z.ZodOptional<z.ZodCustom<number, number>>;
136
+ errorHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
137
+ failedRequestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
138
+ maxRequestRetries: z.ZodDefault<z.ZodCustom<number, number>>;
139
+ sameDomainDelaySecs: z.ZodDefault<z.ZodCustom<number, number>>;
140
+ maxRequestsPerCrawl: z.ZodOptional<z.ZodCustom<number, number>>;
141
+ maxCrawlDepth: z.ZodOptional<z.ZodCustom<number, number>>;
142
+ taskLoopOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
143
+ concurrencySystem: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
144
+ sessionPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
145
+ statusMessageLoggingInterval: z.ZodDefault<z.ZodCustom<number, number>>;
146
+ statusMessageCallback: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
147
+ additionalHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
148
+ ignoreHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
149
+ blockedStatusCodes: z.ZodOptional<z.ZodArray<z.ZodCustom<number, number>>>;
150
+ retryOnBlocked: z.ZodDefault<z.ZodBoolean>;
151
+ respectRobotsTxtFile: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCustom<Dictionary, Dictionary>]>>;
152
+ transactionalStorage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
153
+ requestQueue: z.ZodOptional<z.ZodEnum<{
154
+ deferred: "deferred";
155
+ writeThrough: "writeThrough";
156
+ }>>;
157
+ }, z.core.$strict>]>>;
158
+ onSkippedRequest: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
159
+ // @ts-ignore optional peer dependency or compatibility with es2022
160
+ httpClient: z.ZodOptional<z.ZodInstanceOf<import("@crawlee/http-client").BaseHttpClient>>;
161
+ // @ts-ignore optional peer dependency or compatibility with es2022
162
+ configuration: z.ZodOptional<z.ZodInstanceOf<import("@crawlee/browser").Configuration>>;
163
+ storageBackend: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
164
+ // @ts-ignore optional peer dependency or compatibility with es2022
165
+ eventManager: z.ZodOptional<z.ZodInstanceOf<import("@crawlee/browser").EventManager>>;
166
+ logger: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
167
+ minConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
168
+ maxConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
169
+ initialConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
170
+ maxRequestsPerMinute: z.ZodOptional<z.ZodCustom<number, number>>;
171
+ keepAlive: z.ZodOptional<z.ZodBoolean>;
172
+ statistics: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
173
+ id: z.ZodOptional<z.ZodString>;
174
+ navigationTimeoutSecs: z.ZodDefault<z.ZodCustom<number, number>>;
175
+ preNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
176
+ postNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
177
+ browserPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
178
+ browserPoolBuilder: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
179
+ remoteBrowser: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
180
+ saveResponseCookies: z.ZodDefault<z.ZodBoolean>;
181
+ proxyConfiguration: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
182
+ ignoreIframes: z.ZodDefault<z.ZodBoolean>;
183
+ ignoreShadowRoots: z.ZodDefault<z.ZodBoolean>;
184
+ launchContext: z.ZodDefault<z.ZodCustom<Dictionary, Dictionary>>;
185
+ headless: z.ZodOptional<z.ZodBoolean>;
244
186
  };
187
+ /** @internal */
188
+ protected static optionsSchema: z.ZodObject<{
189
+ contextPipelineBuilder: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
190
+ extendContext: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
191
+ requestList: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
192
+ requestQueue: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
193
+ requestManager: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
194
+ requestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
195
+ requestHandlerTimeoutSecs: z.ZodOptional<z.ZodCustom<number, number>>;
196
+ errorHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
197
+ failedRequestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
198
+ maxRequestRetries: z.ZodDefault<z.ZodCustom<number, number>>;
199
+ sameDomainDelaySecs: z.ZodDefault<z.ZodCustom<number, number>>;
200
+ maxRequestsPerCrawl: z.ZodOptional<z.ZodCustom<number, number>>;
201
+ maxCrawlDepth: z.ZodOptional<z.ZodCustom<number, number>>;
202
+ taskLoopOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
203
+ concurrencySystem: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
204
+ sessionPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
205
+ statusMessageLoggingInterval: z.ZodDefault<z.ZodCustom<number, number>>;
206
+ statusMessageCallback: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
207
+ additionalHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
208
+ ignoreHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
209
+ blockedStatusCodes: z.ZodOptional<z.ZodArray<z.ZodCustom<number, number>>>;
210
+ retryOnBlocked: z.ZodDefault<z.ZodBoolean>;
211
+ respectRobotsTxtFile: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCustom<Dictionary, Dictionary>]>>;
212
+ transactionalStorage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
213
+ requestQueue: z.ZodOptional<z.ZodEnum<{
214
+ deferred: "deferred";
215
+ writeThrough: "writeThrough";
216
+ }>>;
217
+ }, z.core.$strict>]>>;
218
+ onSkippedRequest: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
219
+ // @ts-ignore optional peer dependency or compatibility with es2022
220
+ httpClient: z.ZodOptional<z.ZodInstanceOf<import("@crawlee/http-client").BaseHttpClient>>;
221
+ // @ts-ignore optional peer dependency or compatibility with es2022
222
+ configuration: z.ZodOptional<z.ZodInstanceOf<import("@crawlee/browser").Configuration>>;
223
+ storageBackend: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
224
+ // @ts-ignore optional peer dependency or compatibility with es2022
225
+ eventManager: z.ZodOptional<z.ZodInstanceOf<import("@crawlee/browser").EventManager>>;
226
+ logger: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
227
+ minConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
228
+ maxConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
229
+ initialConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
230
+ maxRequestsPerMinute: z.ZodOptional<z.ZodCustom<number, number>>;
231
+ keepAlive: z.ZodOptional<z.ZodBoolean>;
232
+ statistics: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
233
+ id: z.ZodOptional<z.ZodString>;
234
+ navigationTimeoutSecs: z.ZodDefault<z.ZodCustom<number, number>>;
235
+ preNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
236
+ postNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
237
+ browserPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
238
+ browserPoolBuilder: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
239
+ remoteBrowser: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
240
+ saveResponseCookies: z.ZodDefault<z.ZodBoolean>;
241
+ proxyConfiguration: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
242
+ ignoreIframes: z.ZodDefault<z.ZodBoolean>;
243
+ ignoreShadowRoots: z.ZodDefault<z.ZodBoolean>;
244
+ launchContext: z.ZodDefault<z.ZodCustom<Dictionary, Dictionary>>;
245
+ headless: z.ZodOptional<z.ZodBoolean>;
246
+ }, z.core.$strict>;
245
247
  /**
246
248
  * All `PlaywrightCrawler` parameters are passed via an options object.
247
249
  */
248
- constructor(options?: PlaywrightCrawlerOptions<ContextExtension, ExtendedContext, Routes>);
249
- // @ts-ignore optional peer dependency or compatibility with es2022
250
- protected buildContextPipeline(): import("@crawlee/browser").ContextPipeline<import("@crawlee/browser").CrawlingContext<Dictionary>, BrowserCrawlingContext<Page, Response, Dictionary, Dictionary> & {
251
- injectFile: (filePath: string, options?: InjectFileOptions) => Promise<unknown>;
252
- injectJQuery: () => Promise<void>;
253
- blockRequests: (options?: BlockRequestsOptions) => Promise<void>;
254
- waitForSelector: (selector: string, timeoutMs?: number) => Promise<void>;
255
- // @ts-ignore optional peer dependency or compatibility with es2022
256
- parseWithCheerio: (selector?: string, timeoutMs?: number) => Promise<import("@crawlee/browser").CheerioAPI>;
257
- infiniteScroll: (options?: InfiniteScrollOptions) => Promise<void>;
258
- listDownloads: () => Promise<Download[]>;
259
- saveSnapshot: (options?: SaveSnapshotOptions) => Promise<void>;
260
- // @ts-ignore optional peer dependency or compatibility with es2022
261
- enqueueLinksByClickingElements: (options: Omit<EnqueueLinksByClickingElementsOptions, "page" | "requestManager">) => Promise<import("@crawlee/types").BatchAddRequestsResult>;
262
- // @ts-ignore optional peer dependency or compatibility with es2022
263
- compileScript: (scriptString: string, ctx?: Dictionary) => import("./utils/playwright-utils.js").CompiledScriptFunction;
264
- closeCookieModals: () => Promise<void>;
265
- handleCloudflareChallenge: (options?: HandleCloudflareChallengeOptions) => Promise<Response | undefined>;
266
- }>;
267
- protected _navigationHandler(crawlingContext: PlaywrightCrawlingContext, gotoOptions: DirectNavigationOptions): Promise<Response | null>;
268
- private enhanceContext;
250
+ constructor(options?: PlaywrightCrawlerOptions<ContextExtension, ExtendedContext, Routes, StatisticStateExtension>);
251
+ protected navigationHandler(crawlingContext: PlaywrightCrawlingContext, gotoOptions: DirectNavigationOptions): Promise<Response | null>;
269
252
  }
270
253
  /**
271
254
  * Returns a `postNavigationHooks`-ready hook that runs {@link PlaywrightContextUtils.handleCloudflareChallenge}
@@ -1,7 +1,8 @@
1
1
  import { BrowserCrawler, RequestState, Router, serviceLocator } from '@crawlee/browser';
2
- import ow from 'ow';
3
- import { PlaywrightLauncher } from './playwright-launcher.js';
4
- import { gotoExtended, playwrightUtils } from './utils/playwright-utils.js';
2
+ import { assertBrowserPoolNotConfigured, parseArgument, schemas } from '@crawlee/utils/internal';
3
+ import { z } from 'zod';
4
+ import { playwrightBrowserPool, remotePlaywrightBrowserPool } from './playwright-browser-pool.js';
5
+ import { blockRequests, compileScript, enqueueLinksByClickingElements, gotoExtended, handleCloudflareChallenge, infiniteScroll, injectFile, injectJQuery, parseWithCheerio, saveSnapshot, } from './utils/playwright-utils.js';
5
6
  /**
6
7
  * Provides a simple framework for parallel crawling of web pages
7
8
  * using headless Chromium, Firefox and Webkit browsers with [Playwright](https://github.com/microsoft/playwright).
@@ -68,51 +69,49 @@ import { gotoExtended, playwrightUtils } from './utils/playwright-utils.js';
68
69
  * @category Crawlers
69
70
  */
70
71
  export class PlaywrightCrawler extends BrowserCrawler {
72
+ /**
73
+ * @internal
74
+ */
71
75
  static optionsShape = {
72
76
  ...BrowserCrawler.optionsShape,
73
- browserPoolOptions: ow.optional.object,
74
- launcher: ow.optional.object,
75
- ignoreIframes: ow.optional.boolean,
76
- ignoreShadowRoots: ow.optional.boolean,
77
+ launchContext: schemas.anyObject.default(() => ({})),
78
+ headless: z.boolean().optional(),
77
79
  };
80
+ /** @internal */
81
+ static optionsSchema = z.strictObject(PlaywrightCrawler.optionsShape);
78
82
  /**
79
83
  * All `PlaywrightCrawler` parameters are passed via an options object.
80
84
  */
81
85
  constructor(options = {}) {
82
- ow(options, 'PlaywrightCrawlerOptions', ow.object.exactShape(PlaywrightCrawler.optionsShape));
83
- const { launchContext = {}, headless, contextPipelineBuilder, ...browserCrawlerOptions } = options;
84
- const browserPoolOptions = {
85
- ...options.browserPoolOptions,
86
- };
86
+ const parsedOptions = parseArgument(options, PlaywrightCrawler.optionsSchema, 'PlaywrightCrawlerOptions');
87
+ const { launchContext, headless, configuration, ...browserCrawlerOptions } = parsedOptions;
87
88
  if (launchContext.proxyUrl) {
88
89
  throw new Error('PlaywrightCrawlerOptions.launchContext.proxyUrl is not allowed in PlaywrightCrawler.' +
89
90
  'Use PlaywrightCrawlerOptions.proxyConfiguration');
90
91
  }
91
- // `browserPlugins` is working when it's not overridden by `launchContext`,
92
- // which for crawlers it is always overridden. Hence the error to use the other option.
93
- if (browserPoolOptions.browserPlugins) {
94
- throw new Error('browserPoolOptions.browserPlugins is disallowed. Use launchContext.launcher instead.');
95
- }
96
- if (headless != null) {
97
- launchContext.launchOptions ??= {};
98
- launchContext.launchOptions.headless = headless;
92
+ if (options.browserPool) {
93
+ // The raw options, not the parsed ones: `launchContext` has a default, so by now it is always set.
94
+ assertBrowserPoolNotConfigured(new.target.name, {
95
+ launchContext: options.launchContext,
96
+ headless: options.headless,
97
+ });
99
98
  }
100
- const playwrightLauncher = new PlaywrightLauncher(launchContext, options.configuration);
101
- browserPoolOptions.browserPlugins = [playwrightLauncher.createBrowserPlugin()];
102
99
  super({
103
100
  ...browserCrawlerOptions,
104
- launchContext,
105
- browserPoolOptions,
106
- contextPipelineBuilder: contextPipelineBuilder ?? (() => this.buildContextPipeline()),
101
+ configuration,
102
+ browserPoolBuilder: (remoteBrowser) => remoteBrowser
103
+ ? remotePlaywrightBrowserPool({ ...remoteBrowser, launchContext, headless, configuration })
104
+ : playwrightBrowserPool({ launchContext, headless, configuration }),
105
+ contextPipelineBuilder: () => this.#buildContextPipeline(),
107
106
  });
108
107
  }
109
- buildContextPipeline() {
110
- return super.buildContextPipeline().compose({ action: this.enhanceContext.bind(this) });
108
+ #buildContextPipeline() {
109
+ return this.buildContextPipeline().compose(this.#enhanceContext.bind(this));
111
110
  }
112
- async _navigationHandler(crawlingContext, gotoOptions) {
111
+ async navigationHandler(crawlingContext, gotoOptions) {
113
112
  return gotoExtended(crawlingContext.page, crawlingContext.request, gotoOptions);
114
113
  }
115
- async enhanceContext(context) {
114
+ async #enhanceContext(context) {
116
115
  const waitForSelector = async (selector, timeoutMs = 5_000) => {
117
116
  const locator = context.page.locator(selector).first();
118
117
  await locator.waitFor({ timeout: timeoutMs, state: 'attached' });
@@ -120,38 +119,37 @@ export class PlaywrightCrawler extends BrowserCrawler {
120
119
  const downloads = [];
121
120
  context.page.on('download', (download) => downloads.push(download));
122
121
  return {
123
- injectFile: async (filePath, options) => playwrightUtils.injectFile(context.page, filePath, options),
122
+ injectFile: async (filePath, options) => injectFile(context.page, filePath, options),
124
123
  injectJQuery: async () => {
125
124
  if (context.request.state === RequestState.BEFORE_NAV) {
126
125
  context.log.warning('Using injectJQuery() in preNavigationHooks leads to unstable results. Use it in a postNavigationHook or a requestHandler instead.');
127
- await playwrightUtils.injectJQuery(context.page);
126
+ await injectJQuery(context.page);
128
127
  return;
129
128
  }
130
- await playwrightUtils.injectJQuery(context.page, { surviveNavigations: false });
129
+ await injectJQuery(context.page, { surviveNavigations: false });
131
130
  },
132
- blockRequests: async (options) => playwrightUtils.blockRequests(context.page, options),
131
+ blockRequests: async (options) => blockRequests(context.page, options),
133
132
  waitForSelector,
134
133
  parseWithCheerio: async (selector, timeoutMs = 5_000) => {
135
134
  if (selector) {
136
135
  await waitForSelector(selector, timeoutMs);
137
136
  }
138
- return playwrightUtils.parseWithCheerio(context.page, this.ignoreShadowRoots, this.ignoreIframes);
137
+ return parseWithCheerio(context.page, this.ignoreShadowRoots, this.ignoreIframes);
139
138
  },
140
- infiniteScroll: async (options) => playwrightUtils.infiniteScroll(context.page, options),
139
+ infiniteScroll: async (options) => infiniteScroll(context.page, options),
141
140
  listDownloads: async () => downloads,
142
- saveSnapshot: async (options) => playwrightUtils.saveSnapshot(context.page, {
141
+ saveSnapshot: async (options) => saveSnapshot(context.page, {
143
142
  ...options,
144
143
  configuration: serviceLocator.getConfiguration(),
145
144
  }),
146
- enqueueLinksByClickingElements: async (options) => playwrightUtils.enqueueLinksByClickingElements({
145
+ enqueueLinksByClickingElements: async (options) => enqueueLinksByClickingElements({
147
146
  ...options,
148
147
  page: context.page,
149
148
  requestManager: this.requestManager,
150
149
  }),
151
- compileScript: (scriptString, ctx) => playwrightUtils.compileScript(scriptString, ctx),
152
- closeCookieModals: async () => playwrightUtils.closeCookieModals(context.page),
150
+ compileScript: (scriptString, ctx) => compileScript(scriptString, ctx),
153
151
  handleCloudflareChallenge: async (options) => {
154
- return playwrightUtils.handleCloudflareChallenge(context.page, context.request.url, options);
152
+ return handleCloudflareChallenge(context.page, context.request.url, options);
155
153
  },
156
154
  };
157
155
  }
@@ -3,6 +3,7 @@ import { BrowserLauncher, Configuration } from '@crawlee/browser';
3
3
  import { PlaywrightPlugin } from '@crawlee/browser-pool';
4
4
  // @ts-ignore optional peer dependency or compatibility with es2022
5
5
  import type { Browser, BrowserType, LaunchOptions } from 'playwright';
6
+ import { z } from 'zod';
6
7
  /**
7
8
  * Apify extends the launch options of Playwright.
8
9
  * You can use any of the Playwright compatible
@@ -71,28 +72,36 @@ export interface PlaywrightLaunchContext extends BrowserLaunchContext<LaunchOpti
71
72
  */
72
73
  export declare class PlaywrightLauncher extends BrowserLauncher<PlaywrightPlugin> {
73
74
  readonly configuration: Configuration;
75
+ /**
76
+ * @internal
77
+ */
74
78
  protected static optionsShape: {
79
+ proxyUrl: z.ZodOptional<z.ZodURL>;
80
+ useChrome: z.ZodOptional<z.ZodBoolean>;
81
+ useIncognitoPages: z.ZodOptional<z.ZodBoolean>;
82
+ browserPerProxy: z.ZodOptional<z.ZodBoolean>;
83
+ ignoreProxyCertificate: z.ZodOptional<z.ZodBoolean>;
84
+ userDataDir: z.ZodOptional<z.ZodString>;
75
85
  // @ts-ignore optional peer dependency or compatibility with es2022
76
- launcher: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
77
- // @ts-ignore optional peer dependency or compatibility with es2022
78
- launchContextOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
79
- // @ts-ignore optional peer dependency or compatibility with es2022
80
- proxyUrl: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
81
- // @ts-ignore optional peer dependency or compatibility with es2022
82
- useChrome: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
86
+ launchOptions: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
87
+ userAgent: z.ZodOptional<z.ZodString>;
83
88
  // @ts-ignore optional peer dependency or compatibility with es2022
84
- useIncognitoPages: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
85
- // @ts-ignore optional peer dependency or compatibility with es2022
86
- browserPerProxy: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
87
- // @ts-ignore optional peer dependency or compatibility with es2022
88
- ignoreProxyCertificate: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
89
- // @ts-ignore optional peer dependency or compatibility with es2022
90
- userDataDir: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
89
+ launcher: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
90
+ };
91
+ /** @internal */
92
+ protected static optionsSchema: z.ZodObject<{
93
+ proxyUrl: z.ZodOptional<z.ZodURL>;
94
+ useChrome: z.ZodOptional<z.ZodBoolean>;
95
+ useIncognitoPages: z.ZodOptional<z.ZodBoolean>;
96
+ browserPerProxy: z.ZodOptional<z.ZodBoolean>;
97
+ ignoreProxyCertificate: z.ZodOptional<z.ZodBoolean>;
98
+ userDataDir: z.ZodOptional<z.ZodString>;
91
99
  // @ts-ignore optional peer dependency or compatibility with es2022
92
- launchOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
100
+ launchOptions: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
101
+ userAgent: z.ZodOptional<z.ZodString>;
93
102
  // @ts-ignore optional peer dependency or compatibility with es2022
94
- userAgent: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
95
- };
103
+ launcher: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
104
+ }, z.core.$strict>;
96
105
  /**
97
106
  * All `PlaywrightLauncher` parameters are passed via this launchContext object.
98
107
  */
@@ -1,29 +1,35 @@
1
1
  import { BrowserLauncher, Configuration } from '@crawlee/browser';
2
2
  import { PlaywrightPlugin } from '@crawlee/browser-pool';
3
- import ow from 'ow';
3
+ import { parseArgument, schemas } from '@crawlee/utils/internal';
4
+ import { z } from 'zod';
4
5
  /**
5
6
  * `PlaywrightLauncher` is based on the `BrowserLauncher`. It launches `playwright` browser instance.
6
7
  * @ignore
7
8
  */
8
9
  export class PlaywrightLauncher extends BrowserLauncher {
9
10
  configuration;
11
+ /**
12
+ * @internal
13
+ */
10
14
  static optionsShape = {
11
15
  ...BrowserLauncher.optionsShape,
12
- launcher: ow.optional.object,
13
- launchContextOptions: ow.optional.object,
16
+ // Passthrough schema — the launcher module object must keep its prototype through parsing.
17
+ launcher: schemas.anyObject.optional(),
14
18
  };
19
+ /** @internal */
20
+ static optionsSchema = z.strictObject(PlaywrightLauncher.optionsShape);
15
21
  /**
16
22
  * All `PlaywrightLauncher` parameters are passed via this launchContext object.
17
23
  */
18
24
  constructor(launchContext = {}, configuration = Configuration.getGlobalConfiguration()) {
19
- ow(launchContext, 'PlaywrightLauncherOptions', ow.object.exactShape(PlaywrightLauncher.optionsShape));
20
- const { launcher = BrowserLauncher.requireLauncherOrThrow('playwright', 'apify/actor-node-playwright-*').chromium, } = launchContext;
21
- const { launchOptions = {}, ...rest } = launchContext;
25
+ const parsedContext = parseArgument(launchContext, PlaywrightLauncher.optionsSchema, 'PlaywrightLaunchContext');
26
+ const { launcher = BrowserLauncher.requireLauncherOrThrow('playwright', 'apify/actor-node-playwright-*').chromium, } = parsedContext;
27
+ const { launchOptions = {}, ...rest } = parsedContext;
22
28
  super({
23
29
  ...rest,
24
30
  launchOptions: {
25
31
  ...launchOptions,
26
- executablePath: getDefaultExecutablePath(launchContext, configuration),
32
+ executablePath: getDefaultExecutablePath(parsedContext, configuration),
27
33
  },
28
34
  launcher,
29
35
  }, configuration);