@crawlee/puppeteer 4.0.0-beta.15 → 4.0.0-beta.151

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.
@@ -3,6 +3,7 @@ import { BrowserLauncher, Configuration } from '@crawlee/browser';
3
3
  import { PuppeteerPlugin } from '@crawlee/browser-pool';
4
4
  // @ts-ignore optional peer dependency or compatibility with es2022
5
5
  import type { Browser } from 'puppeteer';
6
+ import { z } from 'zod';
6
7
  /**
7
8
  * Apify extends the launch options of Puppeteer.
8
9
  * You can use any of the Puppeteer compatible
@@ -66,30 +67,42 @@ export interface PuppeteerLaunchContext extends BrowserLaunchContext<PuppeteerPl
66
67
  * @ignore
67
68
  */
68
69
  export declare class PuppeteerLauncher extends BrowserLauncher<PuppeteerPlugin, unknown> {
69
- readonly config: Configuration;
70
+ readonly configuration: Configuration;
71
+ /**
72
+ * @internal
73
+ */
70
74
  protected static optionsShape: {
75
+ proxyUrl: z.ZodOptional<z.ZodURL>;
76
+ useChrome: z.ZodOptional<z.ZodBoolean>;
77
+ useIncognitoPages: z.ZodOptional<z.ZodBoolean>;
78
+ browserPerProxy: z.ZodOptional<z.ZodBoolean>;
79
+ ignoreProxyCertificate: z.ZodOptional<z.ZodBoolean>;
80
+ userDataDir: z.ZodOptional<z.ZodString>;
71
81
  // @ts-ignore optional peer dependency or compatibility with es2022
72
- launcher: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
73
- // @ts-ignore optional peer dependency or compatibility with es2022
74
- proxyUrl: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
75
- // @ts-ignore optional peer dependency or compatibility with es2022
76
- useChrome: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
82
+ launchOptions: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
83
+ userAgent: z.ZodOptional<z.ZodString>;
77
84
  // @ts-ignore optional peer dependency or compatibility with es2022
78
- useIncognitoPages: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
79
- // @ts-ignore optional peer dependency or compatibility with es2022
80
- browserPerProxy: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
81
- // @ts-ignore optional peer dependency or compatibility with es2022
82
- userDataDir: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
85
+ launcher: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
86
+ };
87
+ /** @internal */
88
+ protected static optionsSchema: z.ZodObject<{
89
+ proxyUrl: z.ZodOptional<z.ZodURL>;
90
+ useChrome: z.ZodOptional<z.ZodBoolean>;
91
+ useIncognitoPages: z.ZodOptional<z.ZodBoolean>;
92
+ browserPerProxy: z.ZodOptional<z.ZodBoolean>;
93
+ ignoreProxyCertificate: z.ZodOptional<z.ZodBoolean>;
94
+ userDataDir: z.ZodOptional<z.ZodString>;
83
95
  // @ts-ignore optional peer dependency or compatibility with es2022
84
- launchOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
96
+ launchOptions: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
97
+ userAgent: z.ZodOptional<z.ZodString>;
85
98
  // @ts-ignore optional peer dependency or compatibility with es2022
86
- userAgent: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
87
- };
99
+ launcher: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
100
+ }, z.core.$strict>;
88
101
  /**
89
102
  * All `PuppeteerLauncher` parameters are passed via an launchContext object.
90
103
  */
91
- constructor(launchContext?: PuppeteerLaunchContext, config?: Configuration);
92
- protected _getDefaultHeadlessOption(): boolean;
104
+ constructor(launchContext?: PuppeteerLaunchContext, configuration?: Configuration);
105
+ protected getDefaultHeadlessOption(): boolean;
93
106
  }
94
107
  /**
95
108
  * Launches headless Chrome using Puppeteer pre-configured to work within the Apify platform.
@@ -119,9 +132,8 @@ export declare class PuppeteerLauncher extends BrowserLauncher<PuppeteerPlugin,
119
132
  * @param [launchContext]
120
133
  * All `PuppeteerLauncher` parameters are passed via an launchContext object.
121
134
  * If you want to pass custom `puppeteer.launch(options)` options you can use the `PuppeteerLaunchContext.launchOptions` property.
122
- * @param [config]
135
+ * @param [configuration]
123
136
  * @returns
124
137
  * Promise that resolves to Puppeteer's `Browser` instance.
125
138
  */
126
- export declare function launchPuppeteer(launchContext?: PuppeteerLaunchContext, config?: Configuration): Promise<Browser>;
127
- //# sourceMappingURL=puppeteer-launcher.d.ts.map
139
+ export declare function launchPuppeteer(launchContext?: PuppeteerLaunchContext, configuration?: Configuration): Promise<Browser>;
@@ -1,31 +1,36 @@
1
1
  import { BrowserLauncher, Configuration } from '@crawlee/browser';
2
2
  import { PuppeteerPlugin } 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
  * `PuppeteerLauncher` is based on the `BrowserLauncher`. It launches `puppeteer` browser instance.
6
7
  * @ignore
7
8
  */
8
9
  export class PuppeteerLauncher extends BrowserLauncher {
9
- config;
10
+ configuration;
11
+ /**
12
+ * @internal
13
+ */
10
14
  static optionsShape = {
11
15
  ...BrowserLauncher.optionsShape,
12
- launcher: ow.optional.object,
16
+ launcher: schemas.anyObject.optional(),
13
17
  };
18
+ /** @internal */
19
+ static optionsSchema = z.strictObject(PuppeteerLauncher.optionsShape);
14
20
  /**
15
21
  * All `PuppeteerLauncher` parameters are passed via an launchContext object.
16
22
  */
17
- constructor(launchContext = {}, config = Configuration.getGlobalConfig()) {
18
- ow(launchContext, 'PuppeteerLauncher', ow.object.exactShape(PuppeteerLauncher.optionsShape));
19
- const { launcher = BrowserLauncher.requireLauncherOrThrow('puppeteer', 'apify/actor-node-puppeteer-chrome'), ...browserLauncherOptions } = launchContext;
23
+ constructor(launchContext = {}, configuration = Configuration.getGlobalConfiguration()) {
24
+ const { launcher = BrowserLauncher.requireLauncherOrThrow('puppeteer', 'apify/actor-node-puppeteer-chrome'), ...browserLauncherOptions } = parseArgument(launchContext, PuppeteerLauncher.optionsSchema, 'PuppeteerLaunchContext');
20
25
  super({
21
26
  ...browserLauncherOptions,
22
27
  launcher,
23
- }, config);
24
- this.config = config;
28
+ }, configuration);
29
+ this.configuration = configuration;
25
30
  this.Plugin = PuppeteerPlugin;
26
31
  }
27
- _getDefaultHeadlessOption() {
28
- const headless = super._getDefaultHeadlessOption();
32
+ getDefaultHeadlessOption() {
33
+ const headless = super.getDefaultHeadlessOption();
29
34
  return headless ? 'new' : headless;
30
35
  }
31
36
  }
@@ -57,12 +62,11 @@ export class PuppeteerLauncher extends BrowserLauncher {
57
62
  * @param [launchContext]
58
63
  * All `PuppeteerLauncher` parameters are passed via an launchContext object.
59
64
  * If you want to pass custom `puppeteer.launch(options)` options you can use the `PuppeteerLaunchContext.launchOptions` property.
60
- * @param [config]
65
+ * @param [configuration]
61
66
  * @returns
62
67
  * Promise that resolves to Puppeteer's `Browser` instance.
63
68
  */
64
- export async function launchPuppeteer(launchContext, config = Configuration.getGlobalConfig()) {
65
- const puppeteerLauncher = new PuppeteerLauncher(launchContext, config);
69
+ export async function launchPuppeteer(launchContext, configuration = Configuration.getGlobalConfiguration()) {
70
+ const puppeteerLauncher = new PuppeteerLauncher(launchContext, configuration);
66
71
  return puppeteerLauncher.launch();
67
72
  }
68
- //# sourceMappingURL=puppeteer-launcher.js.map
@@ -58,4 +58,3 @@ export declare function addInterceptRequestHandler(page: Page, handler: Intercep
58
58
  * @param handler Request interception handler.
59
59
  */
60
60
  export declare function removeInterceptRequestHandler(page: Page, handler: InterceptHandler): Promise<void>;
61
- //# sourceMappingURL=puppeteer_request_interception.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import { EventEmitter } from 'node:events';
2
- import ow from 'ow';
3
- import log from '@apify/log';
2
+ import { serviceLocator } from '@crawlee/browser';
3
+ import { parseArgument, schemas } from '@crawlee/utils/internal';
4
+ const pageSchema = schemas.objectWithKeys(['goto', 'evaluate']);
4
5
  // We use weak maps here so that the content gets discarded after page gets closed.
5
6
  const pageInterceptRequestHandlersMap = new WeakMap(); // Maps page to an array of request interception handlers.
6
7
  const pageInterceptRequestMasterHandlerMap = new WeakMap(); // Maps page to master request interception handler.
@@ -137,8 +138,8 @@ async function handleRequest(request, interceptRequestHandlers) {
137
138
  * @param handler Request interception handler.
138
139
  */
139
140
  export async function addInterceptRequestHandler(page, handler) {
140
- ow(page, ow.object.hasKeys('goto', 'evaluate'));
141
- ow(handler, ow.function);
141
+ parseArgument(page, pageSchema);
142
+ parseArgument(handler, schemas.anyFunction);
142
143
  if (!pageInterceptRequestHandlersMap.has(page)) {
143
144
  pageInterceptRequestHandlersMap.set(page, []);
144
145
  }
@@ -174,8 +175,8 @@ export async function addInterceptRequestHandler(page, handler) {
174
175
  * @param handler Request interception handler.
175
176
  */
176
177
  export async function removeInterceptRequestHandler(page, handler) {
177
- ow(page, ow.object.hasKeys('goto', 'evaluate'));
178
- ow(handler, ow.function);
178
+ parseArgument(page, pageSchema);
179
+ parseArgument(handler, schemas.anyFunction);
179
180
  const handlersArray = pageInterceptRequestHandlersMap.get(page).filter((item) => item !== handler);
180
181
  pageInterceptRequestHandlersMap.set(page, handlersArray);
181
182
  if (handlersArray.length === 0) {
@@ -194,7 +195,7 @@ export async function removeInterceptRequestHandler(page, handler) {
194
195
  interceptedRequestsInProgress.removeListener('delete', onDelete);
195
196
  }
196
197
  catch (error) {
197
- log.debug('Error while disabling request interception', { error });
198
+ serviceLocator.getLogger().debug('Error while disabling request interception', { error });
198
199
  }
199
200
  }
200
201
  };
@@ -207,4 +208,3 @@ async function disableRequestInterception(page) {
207
208
  const requestHandler = pageInterceptRequestMasterHandlerMap.get(page);
208
209
  page.off('request', requestHandler);
209
210
  }
210
- //# sourceMappingURL=puppeteer_request_interception.js.map
@@ -20,7 +20,7 @@
20
20
  import type { Request } from '@crawlee/browser';
21
21
  import { Configuration } from '@crawlee/browser';
22
22
  import type { BatchAddRequestsResult, Dictionary } from '@crawlee/types';
23
- import { type CheerioRoot } from '@crawlee/utils';
23
+ import type { CheerioAPI } from 'cheerio';
24
24
  import type { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js';
25
25
  // @ts-ignore optional peer dependency or compatibility with es2022
26
26
  import type { HTTPResponse, Page, ResponseForRequest } from 'puppeteer';
@@ -129,7 +129,7 @@ export declare function injectJQuery(page: Page, options?: {
129
129
  * @param page Puppeteer [`Page`](https://pptr.dev/api/puppeteer.page) object.
130
130
  * @param ignoreShadowRoots
131
131
  */
132
- export declare function parseWithCheerio(page: Page, ignoreShadowRoots?: boolean, ignoreIframes?: boolean): Promise<CheerioRoot>;
132
+ export declare function parseWithCheerio(page: Page, ignoreShadowRoots?: boolean, ignoreIframes?: boolean): Promise<CheerioAPI>;
133
133
  /**
134
134
  * Forces the Puppeteer browser tab to block loading URLs that match a provided pattern.
135
135
  * This is useful to speed up crawling of websites, since it reduces the amount
@@ -305,9 +305,9 @@ export interface SaveSnapshotOptions {
305
305
  keyValueStoreName?: string | null;
306
306
  /**
307
307
  * Configuration of the crawler that will be used to save the snapshot.
308
- * @default Configuration.getGlobalConfig()
308
+ * @default Configuration.getGlobalConfiguration()
309
309
  */
310
- config?: Configuration;
310
+ configuration?: Configuration;
311
311
  }
312
312
  /**
313
313
  * Saves a full screenshot and HTML of the current page into a Key-Value store.
@@ -315,8 +315,6 @@ export interface SaveSnapshotOptions {
315
315
  * @param [options]
316
316
  */
317
317
  export declare function saveSnapshot(page: Page, options?: SaveSnapshotOptions): Promise<void>;
318
- export declare function closeCookieModals(page: Page): Promise<void>;
319
- /** @internal */
320
318
  export interface PuppeteerContextUtils {
321
319
  /**
322
320
  * Injects a JavaScript file into current `page`.
@@ -378,7 +376,7 @@ export interface PuppeteerContextUtils {
378
376
  * });
379
377
  * ```
380
378
  */
381
- parseWithCheerio(selector?: string, timeoutMs?: number): Promise<CheerioRoot>;
379
+ parseWithCheerio(selector?: string, timeoutMs?: number): Promise<CheerioAPI>;
382
380
  /**
383
381
  * The function finds elements matching a specific CSS selector in a Puppeteer page,
384
382
  * clicks all those elements using a mouse move and a left mouse button click and intercepts
@@ -388,8 +386,7 @@ export interface PuppeteerContextUtils {
388
386
  * in `href` elements, but rather navigations are triggered in click handlers.
389
387
  * If you're looking to find URLs in `href` attributes of the page, see {@link enqueueLinks}.
390
388
  *
391
- * Optionally, the function allows you to filter the target links' URLs using an array of {@link PseudoUrl} objects
392
- * and override settings of the enqueued {@link Request} objects.
389
+ * Optionally, the function allows you to filter the target links' URLs using an array of glob or regexp patterns.
393
390
  *
394
391
  * **IMPORTANT**: To be able to do this, this function uses various mutations on the page,
395
392
  * such as changing the Z-index of elements being clicked and their visibility. Therefore,
@@ -410,9 +407,9 @@ export interface PuppeteerContextUtils {
410
407
  * async requestHandler({ enqueueLinksByClickingElements }) {
411
408
  * await enqueueLinksByClickingElements({
412
409
  * selector: 'a.product-detail',
413
- * globs: [
414
- * 'https://www.example.com/handbags/**'
415
- * 'https://www.example.com/purses/**'
410
+ * include: [
411
+ * 'https://www.example.com/handbags/**',
412
+ * 'https://www.example.com/purses/**',
416
413
  * ],
417
414
  * });
418
415
  * });
@@ -420,7 +417,7 @@ export interface PuppeteerContextUtils {
420
417
  *
421
418
  * @returns Promise that resolves to {@link BatchAddRequestsResult} object.
422
419
  */
423
- enqueueLinksByClickingElements(options: Omit<EnqueueLinksByClickingElementsOptions, 'page' | 'requestQueue'>): Promise<BatchAddRequestsResult>;
420
+ enqueueLinksByClickingElements(options: Omit<EnqueueLinksByClickingElementsOptions, 'page' | 'requestManager'>): Promise<BatchAddRequestsResult>;
424
421
  /**
425
422
  * Forces the Puppeteer browser tab to block loading URLs that match a provided pattern.
426
423
  * This is useful to speed up crawling of websites, since it reduces the amount
@@ -550,19 +547,6 @@ export interface PuppeteerContextUtils {
550
547
  * Saves a full screenshot and HTML of the current page into a Key-Value store.
551
548
  */
552
549
  saveSnapshot(options?: SaveSnapshotOptions): Promise<void>;
553
- /**
554
- * Tries to close cookie consent modals on the page. Based on the I Don't Care About Cookies browser extension.
555
- *
556
- * Note that this method requires the idcac-playwright package to be installed.
557
- * Crawlee does not include it by default due to licensing issues.
558
- *
559
- * To use this method, please install the package manually by running:
560
- *
561
- * ```bash
562
- * npm install idcac-playwright
563
- * ```
564
- */
565
- closeCookieModals(): Promise<void>;
566
550
  }
567
551
  export { enqueueLinksByClickingElements, addInterceptRequestHandler, removeInterceptRequestHandler };
568
552
  /** @internal */
@@ -578,6 +562,4 @@ export declare const puppeteerUtils: {
578
562
  infiniteScroll: typeof infiniteScroll;
579
563
  saveSnapshot: typeof saveSnapshot;
580
564
  parseWithCheerio: typeof parseWithCheerio;
581
- closeCookieModals: typeof closeCookieModals;
582
565
  };
583
- //# sourceMappingURL=puppeteer_utils.d.ts.map
@@ -20,19 +20,49 @@
20
20
  import { readFile } from 'node:fs/promises';
21
21
  import { createRequire } from 'node:module';
22
22
  import vm from 'node:vm';
23
- import { Configuration, KeyValueStore, validators } from '@crawlee/browser';
23
+ import { Configuration, KeyValueStore, serviceLocator, validators } from '@crawlee/browser';
24
24
  import { expandShadowRoots, sleep } from '@crawlee/utils';
25
- import * as cheerio from 'cheerio';
26
- import ow from 'ow';
25
+ import { parseArgument, schemas } from '@crawlee/utils/internal';
26
+ import { z } from 'zod';
27
27
  import { LruCache } from '@apify/datastructures';
28
- import log_ from '@apify/log';
29
28
  import { enqueueLinksByClickingElements } from '../enqueue-links/click-elements.js';
30
29
  import { addInterceptRequestHandler, removeInterceptRequestHandler } from './puppeteer_request_interception.js';
31
30
  const require = createRequire(import.meta.url);
32
31
  const jqueryPath = require.resolve('jquery');
33
32
  const MAX_INJECT_FILE_CACHE_SIZE = 10;
34
33
  const DEFAULT_BLOCK_REQUEST_URL_PATTERNS = ['.css', '.jpg', '.jpeg', '.png', '.svg', '.gif', '.woff', '.pdf', '.zip'];
35
- const log = log_.child({ prefix: 'Puppeteer Utils' });
34
+ const filePathSchema = z.string();
35
+ const injectFileOptionsSchema = z.strictObject({
36
+ surviveNavigations: z.boolean().optional(),
37
+ });
38
+ const responseUrlRulesSchema = schemas.arrayOf(z.union([z.string(), z.instanceof(RegExp)]), 'strings or RegExps');
39
+ const gotoExtendedRequestSchema = z.looseObject({
40
+ url: z.url(),
41
+ method: z.string().optional(),
42
+ headers: schemas.anyObject.optional(),
43
+ payload: z.union([z.string(), z.instanceof(Uint8Array)]).optional(),
44
+ });
45
+ const blockRequestsOptionsSchema = z.strictObject({
46
+ urlPatterns: schemas.arrayOf(z.string(), 'strings').default(DEFAULT_BLOCK_REQUEST_URL_PATTERNS),
47
+ extraUrlPatterns: schemas.arrayOf(z.string(), 'strings').default(() => []),
48
+ });
49
+ const infiniteScrollOptionsSchema = z.strictObject({
50
+ timeoutSecs: schemas.anyNumber.default(0),
51
+ maxScrollHeight: schemas.anyNumber.default(0),
52
+ waitForSecs: schemas.anyNumber.default(4),
53
+ scrollDownAndUp: z.boolean().default(false),
54
+ buttonSelector: z.string().optional(),
55
+ stopScrollCallback: schemas.anyFunction.optional(),
56
+ });
57
+ const saveSnapshotOptionsSchema = z.strictObject({
58
+ key: z.string().min(1).default('SNAPSHOT'),
59
+ screenshotQuality: schemas.anyNumber.default(50),
60
+ saveScreenshot: z.boolean().default(true),
61
+ saveHtml: z.boolean().default(true),
62
+ keyValueStoreName: z.string().optional(),
63
+ configuration: schemas.anyObject.optional(),
64
+ });
65
+ const getLog = () => serviceLocator.getChildLog('Puppeteer Utils');
36
66
  /**
37
67
  * Cache contents of previously injected files to limit file system access.
38
68
  */
@@ -49,21 +79,19 @@ const injectedFilesCache = new LruCache({ maxLength: MAX_INJECT_FILE_CACHE_SIZE
49
79
  * @param [options]
50
80
  */
51
81
  export async function injectFile(page, filePath, options = {}) {
52
- ow(page, ow.object.validate(validators.browserPage));
53
- ow(filePath, ow.string);
54
- ow(options, ow.object.exactShape({
55
- surviveNavigations: ow.optional.boolean,
56
- }));
82
+ parseArgument(page, validators.browserPage);
83
+ parseArgument(filePath, filePathSchema);
84
+ const { surviveNavigations } = parseArgument(options, injectFileOptionsSchema);
57
85
  let contents = injectedFilesCache.get(filePath);
58
86
  if (!contents) {
59
87
  contents = await readFile(filePath, 'utf8');
60
88
  injectedFilesCache.add(filePath, contents);
61
89
  }
62
90
  const evalP = page.evaluate(contents);
63
- if (options.surviveNavigations) {
91
+ if (surviveNavigations) {
64
92
  page.on('framenavigated', async () => page
65
93
  .evaluate(contents)
66
- .catch((error) => log.warning('An error occurred during the script injection!', { error })));
94
+ .catch((error) => getLog().warning('An error occurred during the script injection!', { error })));
67
95
  }
68
96
  return evalP;
69
97
  }
@@ -94,7 +122,7 @@ export async function injectFile(page, filePath, options = {}) {
94
122
  * @param [options.surviveNavigations] Opt-out option to disable the JQuery reinjection after navigation.
95
123
  */
96
124
  export async function injectJQuery(page, options) {
97
- ow(page, ow.object.validate(validators.browserPage));
125
+ parseArgument(page, validators.browserPage);
98
126
  return injectFile(page, jqueryPath, { surviveNavigations: options?.surviveNavigations ?? true });
99
127
  }
100
128
  /**
@@ -110,7 +138,7 @@ export async function injectJQuery(page, options) {
110
138
  * @param ignoreShadowRoots
111
139
  */
112
140
  export async function parseWithCheerio(page, ignoreShadowRoots = false, ignoreIframes = false) {
113
- ow(page, ow.object.validate(validators.browserPage));
141
+ parseArgument(page, validators.browserPage);
114
142
  if (page.frames().length > 1 && !ignoreIframes) {
115
143
  const frames = await page.$$('iframe');
116
144
  await Promise.all(frames.map(async (frame) => {
@@ -135,7 +163,7 @@ export async function parseWithCheerio(page, ignoreShadowRoots = false, ignoreIf
135
163
  }
136
164
  }
137
165
  catch (error) {
138
- log.warning(`Failed to extract iframe content: ${error}`);
166
+ getLog().warning(`Failed to extract iframe content: ${error}`);
139
167
  }
140
168
  }));
141
169
  }
@@ -143,7 +171,8 @@ export async function parseWithCheerio(page, ignoreShadowRoots = false, ignoreIf
143
171
  ? null
144
172
  : (await page.evaluate(`(${expandShadowRoots.toString()})(document)`));
145
173
  const pageContent = html || (await page.content());
146
- return cheerio.load(pageContent);
174
+ const { load } = await import('cheerio');
175
+ return load(pageContent);
147
176
  }
148
177
  /**
149
178
  * Forces the Puppeteer browser tab to block loading URLs that match a provided pattern.
@@ -188,12 +217,8 @@ export async function parseWithCheerio(page, ignoreShadowRoots = false, ignoreIf
188
217
  * @param [options]
189
218
  */
190
219
  export async function blockRequests(page, options = {}) {
191
- ow(page, ow.object.validate(validators.browserPage));
192
- ow(options, ow.object.exactShape({
193
- urlPatterns: ow.optional.array.ofType(ow.string),
194
- extraUrlPatterns: ow.optional.array.ofType(ow.string),
195
- }));
196
- const { urlPatterns = DEFAULT_BLOCK_REQUEST_URL_PATTERNS, extraUrlPatterns = [] } = options;
220
+ parseArgument(page, validators.browserPage);
221
+ const { urlPatterns, extraUrlPatterns } = parseArgument(options, blockRequestsOptionsSchema);
197
222
  const patternsToBlock = [...urlPatterns, ...extraUrlPatterns];
198
223
  // We use CDP commands instead of request interception as the latter disables caching, which is not ideal
199
224
  await sendCDPCommand(page, 'Network.setBlockedURLs', { urls: patternsToBlock });
@@ -221,7 +246,9 @@ export async function sendCDPCommand(page, command, ...args) {
221
246
  * @deprecated
222
247
  */
223
248
  export const blockResources = async (page, resourceTypes = ['stylesheet', 'font', 'image', 'media']) => {
224
- log.deprecated('utils.puppeteer.blockResources() has a high impact on performance in recent versions of Puppeteer. ' +
249
+ serviceLocator
250
+ .getLogger()
251
+ .deprecated('utils.puppeteer.blockResources() has a high impact on performance in recent versions of Puppeteer. ' +
225
252
  'Until this resolves, please use utils.puppeteer.blockRequests()');
226
253
  await addInterceptRequestHandler(page, async (request) => {
227
254
  const type = request.resourceType();
@@ -248,10 +275,12 @@ export const blockResources = async (page, resourceTypes = ['stylesheet', 'font'
248
275
  * @deprecated
249
276
  */
250
277
  export async function cacheResponses(page, cache, responseUrlRules) {
251
- ow(page, ow.object.validate(validators.browserPage));
252
- ow(cache, ow.object);
253
- ow(responseUrlRules, ow.array.ofType(ow.any(ow.string, ow.regExp)));
254
- log.deprecated('utils.puppeteer.cacheResponses() has a high impact on performance ' +
278
+ parseArgument(page, validators.browserPage);
279
+ parseArgument(cache, schemas.anyObject);
280
+ parseArgument(responseUrlRules, responseUrlRulesSchema);
281
+ serviceLocator
282
+ .getLogger()
283
+ .deprecated('utils.puppeteer.cacheResponses() has a high impact on performance ' +
255
284
  "in recent versions of Puppeteer so it's use is discouraged until this issue resolves.");
256
285
  await addInterceptRequestHandler(page, async (request) => {
257
286
  const url = request.url();
@@ -321,7 +350,7 @@ export function compileScript(scriptString, context = Object.create(null)) {
321
350
  func = vm.runInNewContext(funcString, context); // "Secure" the context by removing prototypes, unless custom context is provided.
322
351
  }
323
352
  catch (err) {
324
- log.exception(err, 'Cannot compile script!');
353
+ getLog().exception(err, 'Cannot compile script!');
325
354
  throw err;
326
355
  }
327
356
  if (typeof func !== 'function')
@@ -341,23 +370,20 @@ export function compileScript(scriptString, context = Object.create(null)) {
341
370
  * @param [gotoOptions] Custom options for `page.goto()`.
342
371
  */
343
372
  export async function gotoExtended(page, request, gotoOptions = {}) {
344
- ow(page, ow.object.validate(validators.browserPage));
345
- ow(request, ow.object.partialShape({
346
- url: ow.string.url,
347
- method: ow.optional.string,
348
- headers: ow.optional.object,
349
- payload: ow.optional.any(ow.string, ow.uint8Array),
350
- }));
351
- ow(gotoOptions, ow.object);
373
+ parseArgument(page, validators.browserPage);
374
+ parseArgument(request, gotoExtendedRequestSchema);
375
+ parseArgument(gotoOptions, schemas.anyObject);
352
376
  gotoOptions = { ...gotoOptions };
353
377
  if (gotoOptions.waitUntil === 'networkidle') {
354
378
  gotoOptions.waitUntil = 'networkidle0';
355
379
  }
356
380
  const { url, method, headers, payload } = request;
357
381
  const isEmpty = (o) => !o || Object.keys(o).length === 0;
358
- if (method !== 'GET' || payload || !isEmpty(headers)) {
382
+ if (method !== 'GET' || payload) {
359
383
  // This is not deprecated, we use it to log only once.
360
- log.deprecated('Using other request methods than GET, rewriting headers and adding payloads has a high impact on performance ' +
384
+ serviceLocator
385
+ .getLogger()
386
+ .deprecated('Using other request methods than GET, rewriting headers and adding payloads has a high impact on performance ' +
361
387
  'in recent versions of Puppeteer. Use only when necessary.');
362
388
  let wasCalled = false;
363
389
  const interceptRequestHandler = async (interceptedRequest) => {
@@ -380,6 +406,19 @@ export async function gotoExtended(page, request, gotoOptions = {}) {
380
406
  };
381
407
  await addInterceptRequestHandler(page, interceptRequestHandler);
382
408
  }
409
+ else if (!isEmpty(headers)) {
410
+ const extraHeaders = { ...headers };
411
+ // Chrome bundled with Puppeteer 25+ ignores a `User-Agent` passed via `setExtraHTTPHeaders()`, it has to be set explicitly.
412
+ for (const name of Object.keys(extraHeaders)) {
413
+ if (name.toLowerCase() === 'user-agent') {
414
+ await page.setUserAgent(extraHeaders[name]);
415
+ delete extraHeaders[name];
416
+ }
417
+ }
418
+ if (!isEmpty(extraHeaders)) {
419
+ await page.setExtraHTTPHeaders(extraHeaders);
420
+ }
421
+ }
383
422
  return page.goto(url, gotoOptions);
384
423
  }
385
424
  /**
@@ -389,16 +428,8 @@ export async function gotoExtended(page, request, gotoOptions = {}) {
389
428
  * @param [options]
390
429
  */
391
430
  export async function infiniteScroll(page, options = {}) {
392
- ow(page, ow.object.validate(validators.browserPage));
393
- ow(options, ow.object.exactShape({
394
- timeoutSecs: ow.optional.number,
395
- maxScrollHeight: ow.optional.number,
396
- waitForSecs: ow.optional.number,
397
- scrollDownAndUp: ow.optional.boolean,
398
- buttonSelector: ow.optional.string,
399
- stopScrollCallback: ow.optional.function,
400
- }));
401
- const { timeoutSecs = 0, maxScrollHeight = 0, waitForSecs = 4, scrollDownAndUp = false, buttonSelector, stopScrollCallback, } = options;
431
+ parseArgument(page, validators.browserPage);
432
+ const { timeoutSecs, maxScrollHeight, waitForSecs, scrollDownAndUp, buttonSelector, stopScrollCallback } = parseArgument(options, infiniteScrollOptionsSchema);
402
433
  let finished;
403
434
  const startTime = Date.now();
404
435
  const CHECK_INTERVAL_MILLIS = 1000;
@@ -490,19 +521,11 @@ export async function infiniteScroll(page, options = {}) {
490
521
  * @param [options]
491
522
  */
492
523
  export async function saveSnapshot(page, options = {}) {
493
- ow(page, ow.object.validate(validators.browserPage));
494
- ow(options, ow.object.exactShape({
495
- key: ow.optional.string.nonEmpty,
496
- screenshotQuality: ow.optional.number,
497
- saveScreenshot: ow.optional.boolean,
498
- saveHtml: ow.optional.boolean,
499
- keyValueStoreName: ow.optional.string,
500
- config: ow.optional.object,
501
- }));
502
- const { key = 'SNAPSHOT', screenshotQuality = 50, saveScreenshot = true, saveHtml = true, keyValueStoreName, config, } = options;
524
+ parseArgument(page, validators.browserPage);
525
+ const { key, screenshotQuality, saveScreenshot, saveHtml, keyValueStoreName, configuration } = parseArgument(options, saveSnapshotOptionsSchema);
503
526
  try {
504
- const store = await KeyValueStore.open(keyValueStoreName, {
505
- config: config ?? Configuration.getGlobalConfig(),
527
+ const store = await KeyValueStore.open(keyValueStoreName ? { name: keyValueStoreName } : null, {
528
+ configuration: configuration ?? Configuration.getGlobalConfiguration(),
506
529
  });
507
530
  if (saveScreenshot) {
508
531
  const screenshotName = `${key}.jpg`;
@@ -523,35 +546,6 @@ export async function saveSnapshot(page, options = {}) {
523
546
  throw new Error(`saveSnapshot with key ${key} failed.\nCause:${err.message}`);
524
547
  }
525
548
  }
526
- let idcacPlaywright = null;
527
- async function getIdcacPlaywright() {
528
- if (idcacPlaywright)
529
- return idcacPlaywright;
530
- try {
531
- idcacPlaywright = await import('idcac-playwright');
532
- }
533
- catch (error) {
534
- log.warning(`Failed to import 'idcac-playwright'.
535
-
536
- We recently made idcac-playwright an optional dependency due to licensing issues.
537
- To use this feature, please install it manually by running
538
-
539
- npm install idcac-playwright
540
-
541
- Original error message follows:
542
-
543
- ${error.message}
544
- `);
545
- }
546
- return idcacPlaywright;
547
- }
548
- export async function closeCookieModals(page) {
549
- ow(page, ow.object.validate(validators.browserPage));
550
- const idcac = await getIdcacPlaywright();
551
- if (idcac?.getInjectableScript()) {
552
- await page.evaluate(idcac.getInjectableScript());
553
- }
554
- }
555
549
  export { enqueueLinksByClickingElements, addInterceptRequestHandler, removeInterceptRequestHandler };
556
550
  /** @internal */
557
551
  export const puppeteerUtils = {
@@ -566,6 +560,4 @@ export const puppeteerUtils = {
566
560
  infiniteScroll,
567
561
  saveSnapshot,
568
562
  parseWithCheerio,
569
- closeCookieModals,
570
563
  };
571
- //# sourceMappingURL=puppeteer_utils.js.map