@crawlee/puppeteer 4.0.0-beta.121 → 4.0.0-beta.122
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/internals/enqueue-links/click-elements.js +21 -21
- package/internals/puppeteer-crawler.d.ts +115 -92
- package/internals/puppeteer-crawler.js +8 -7
- package/internals/puppeteer-launcher.d.ts +22 -15
- package/internals/puppeteer-launcher.js +5 -5
- package/internals/utils/puppeteer_request_interception.js +6 -6
- package/internals/utils/puppeteer_utils.js +52 -48
- package/package.json +9 -9
|
@@ -1,9 +1,25 @@
|
|
|
1
1
|
import { URL } from 'node:url';
|
|
2
|
-
import { applyRequestTransform, constructUrlPatternObjects, createRequestOptions, filterRequestOptionsByPatterns, Request, serviceLocator, } from '@crawlee/browser';
|
|
3
|
-
import
|
|
2
|
+
import { applyRequestTransform, constructUrlPatternObjects, createRequestOptions, filterRequestOptionsByPatterns, parseArgument, urlPatternSchema, Request, schemas, serviceLocator, } from '@crawlee/browser';
|
|
3
|
+
import { z } from 'zod';
|
|
4
4
|
import { addInterceptRequestHandler, removeInterceptRequestHandler } from '../utils/puppeteer_request_interception.js';
|
|
5
5
|
const STARTING_Z_INDEX = 2147400000;
|
|
6
6
|
const getLog = () => serviceLocator.getChildLog('Puppeteer Click Elements');
|
|
7
|
+
const enqueueLinksByClickingElementsOptionsSchema = z.strictObject({
|
|
8
|
+
page: schemas.objectWithKeys(['goto', 'evaluate']),
|
|
9
|
+
requestManager: schemas.objectWithKeys(['fetchNextRequest', 'addRequestsBatched']),
|
|
10
|
+
selector: z.string(),
|
|
11
|
+
userData: schemas.anyObject.optional(),
|
|
12
|
+
clickOptions: schemas.anyObject.optional(),
|
|
13
|
+
include: schemas.arrayOf(urlPatternSchema, 'URL patterns').optional(),
|
|
14
|
+
exclude: schemas.arrayOf(urlPatternSchema, 'URL patterns').optional(),
|
|
15
|
+
transformRequestFunction: schemas.anyFunction.optional(),
|
|
16
|
+
waitForPageIdleSecs: schemas.anyNumber.default(1),
|
|
17
|
+
maxWaitForPageIdleSecs: schemas.anyNumber.default(5),
|
|
18
|
+
label: z.string().optional(),
|
|
19
|
+
forefront: z.boolean().optional(),
|
|
20
|
+
skipNavigation: z.boolean().optional(),
|
|
21
|
+
onSkippedRequest: schemas.anyFunction.optional(),
|
|
22
|
+
});
|
|
7
23
|
/**
|
|
8
24
|
* The function finds elements matching a specific CSS selector in a Puppeteer page,
|
|
9
25
|
* clicks all those elements using a mouse move and a left mouse button click and intercepts
|
|
@@ -45,24 +61,8 @@ const getLog = () => serviceLocator.getChildLog('Puppeteer Click Elements');
|
|
|
45
61
|
* @returns Promise that resolves to {@link BatchAddRequestsResult} object.
|
|
46
62
|
*/
|
|
47
63
|
export async function enqueueLinksByClickingElements(options) {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
page: ow.object.hasKeys('goto', 'evaluate'),
|
|
51
|
-
requestManager: ow.object.hasKeys('fetchNextRequest', 'addRequestsBatched'),
|
|
52
|
-
selector: ow.string,
|
|
53
|
-
userData: ow.optional.object,
|
|
54
|
-
clickOptions: ow.optional.object,
|
|
55
|
-
include: ow.optional.array.ofType(urlPatternValidator),
|
|
56
|
-
exclude: ow.optional.array.ofType(urlPatternValidator),
|
|
57
|
-
transformRequestFunction: ow.optional.function,
|
|
58
|
-
waitForPageIdleSecs: ow.optional.number,
|
|
59
|
-
maxWaitForPageIdleSecs: ow.optional.number,
|
|
60
|
-
label: ow.optional.string,
|
|
61
|
-
forefront: ow.optional.boolean,
|
|
62
|
-
skipNavigation: ow.optional.boolean,
|
|
63
|
-
onSkippedRequest: ow.optional.function,
|
|
64
|
-
}));
|
|
65
|
-
const { page, requestManager, selector, clickOptions, include, exclude, transformRequestFunction, waitForPageIdleSecs = 1, maxWaitForPageIdleSecs = 5, forefront, onSkippedRequest, } = options;
|
|
64
|
+
const parsedOptions = parseArgument(options, enqueueLinksByClickingElementsOptionsSchema, 'EnqueueLinksByClickingElementsOptions');
|
|
65
|
+
const { page, requestManager, selector, clickOptions, include, exclude, transformRequestFunction, waitForPageIdleSecs, maxWaitForPageIdleSecs, forefront, onSkippedRequest, } = parsedOptions;
|
|
66
66
|
const waitForPageIdleMillis = waitForPageIdleSecs * 1000;
|
|
67
67
|
const maxWaitForPageIdleMillis = maxWaitForPageIdleSecs * 1000;
|
|
68
68
|
const urlExcludePatternObjects = exclude?.length ? constructUrlPatternObjects(exclude) : [];
|
|
@@ -74,7 +74,7 @@ export async function enqueueLinksByClickingElements(options) {
|
|
|
74
74
|
maxWaitForPageIdleMillis,
|
|
75
75
|
clickOptions,
|
|
76
76
|
});
|
|
77
|
-
const requestOptions = createRequestOptions(interceptedRequests,
|
|
77
|
+
const requestOptions = createRequestOptions(interceptedRequests, parsedOptions);
|
|
78
78
|
const skippedByFilters = [];
|
|
79
79
|
let filteredOptions = filterRequestOptionsByPatterns(requestOptions, urlPatternObjects.length > 0 ? urlPatternObjects : undefined, urlExcludePatternObjects, undefined, (url) => skippedByFilters.push(url));
|
|
80
80
|
if (onSkippedRequest && skippedByFilters.length > 0) {
|
|
@@ -4,6 +4,7 @@ import type { PuppeteerPlugin } from '@crawlee/browser-pool';
|
|
|
4
4
|
import type { Dictionary } from '@crawlee/types';
|
|
5
5
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
6
6
|
import type { HTTPResponse, LaunchOptions, Page } from 'puppeteer';
|
|
7
|
+
import { z } from 'zod';
|
|
7
8
|
import type { EnqueueLinksByClickingElementsOptions } from './enqueue-links/click-elements.js';
|
|
8
9
|
import type { PuppeteerLaunchContext } from './puppeteer-launcher.js';
|
|
9
10
|
import type { InterceptHandler } from './utils/puppeteer_request_interception.js';
|
|
@@ -123,99 +124,121 @@ export declare class PuppeteerCrawler<ContextExtension = Dictionary<never>, Exte
|
|
|
123
124
|
browserPlugins: [PuppeteerPlugin];
|
|
124
125
|
}, LaunchOptions, PuppeteerCrawlingContext, ContextExtension, ExtendedContext, Routes> {
|
|
125
126
|
protected static optionsShape: {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
169
|
-
|
|
170
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
183
|
-
additionalHttpErrorStatusCodes: import("ow").ArrayPredicate<number>;
|
|
184
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
185
|
-
ignoreHttpErrorStatusCodes: import("ow").ArrayPredicate<number>;
|
|
186
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
187
|
-
blockedStatusCodes: import("ow").ArrayPredicate<number>;
|
|
188
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
189
|
-
retryOnBlocked: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
|
|
190
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
191
|
-
respectRobotsTxtFile: import("ow").AnyPredicate<boolean | object>;
|
|
192
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
193
|
-
transactionalStorage: import("ow").BasePredicate<boolean | Partial<import("@crawlee/browser").StorageWritePolicy> | undefined>;
|
|
194
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
195
|
-
onSkippedRequest: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
|
|
196
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
197
|
-
httpClient: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
198
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
199
|
-
configuration: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
200
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
201
|
-
storageBackend: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
202
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
203
|
-
eventManager: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
204
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
205
|
-
logger: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
206
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
207
|
-
minConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
208
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
209
|
-
maxConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
210
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
211
|
-
maxRequestsPerMinute: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
|
|
212
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
213
|
-
keepAlive: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
|
|
214
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
215
|
-
statistics: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
|
|
216
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
217
|
-
id: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
|
|
127
|
+
browserPoolOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
128
|
+
navigationTimeoutSecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
129
|
+
preNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
130
|
+
postNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
131
|
+
launchContext: z.ZodDefault<z.ZodCustom<Dictionary, Dictionary>>;
|
|
132
|
+
headless: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>;
|
|
133
|
+
browserPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
134
|
+
remoteBrowser: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
135
|
+
saveResponseCookies: z.ZodDefault<z.ZodBoolean>;
|
|
136
|
+
proxyConfiguration: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
137
|
+
ignoreIframes: z.ZodDefault<z.ZodBoolean>;
|
|
138
|
+
ignoreShadowRoots: z.ZodDefault<z.ZodBoolean>;
|
|
139
|
+
contextPipelineBuilder: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
140
|
+
extendContext: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
141
|
+
requestList: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
142
|
+
requestQueue: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
143
|
+
requestManager: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
144
|
+
requestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
145
|
+
requestHandlerTimeoutSecs: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
146
|
+
errorHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
147
|
+
failedRequestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
148
|
+
maxRequestRetries: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
149
|
+
sameDomainDelaySecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
150
|
+
maxRequestsPerCrawl: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
151
|
+
maxCrawlDepth: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
152
|
+
taskLoopOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
153
|
+
concurrencySystem: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
154
|
+
sessionPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
155
|
+
statusMessageLoggingInterval: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
156
|
+
statusMessageCallback: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
157
|
+
additionalHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
158
|
+
ignoreHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
159
|
+
blockedStatusCodes: z.ZodOptional<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
160
|
+
retryOnBlocked: z.ZodDefault<z.ZodBoolean>;
|
|
161
|
+
respectRobotsTxtFile: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCustom<Dictionary, Dictionary>]>>;
|
|
162
|
+
transactionalStorage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
163
|
+
requestQueue: z.ZodOptional<z.ZodEnum<{
|
|
164
|
+
deferred: "deferred";
|
|
165
|
+
writeThrough: "writeThrough";
|
|
166
|
+
}>>;
|
|
167
|
+
}, z.core.$strict>]>>;
|
|
168
|
+
onSkippedRequest: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
169
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
170
|
+
httpClient: z.ZodOptional<z.ZodCustom<import("@crawlee/http-client").BaseHttpClient, import("@crawlee/http-client").BaseHttpClient>>;
|
|
171
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
172
|
+
configuration: z.ZodOptional<z.ZodCustom<import("@crawlee/browser").Configuration, import("@crawlee/browser").Configuration>>;
|
|
173
|
+
storageBackend: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
174
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
175
|
+
eventManager: z.ZodOptional<z.ZodCustom<import("@crawlee/browser").EventManager, import("@crawlee/browser").EventManager>>;
|
|
176
|
+
logger: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
177
|
+
minConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
178
|
+
maxConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
179
|
+
maxRequestsPerMinute: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
180
|
+
keepAlive: z.ZodOptional<z.ZodBoolean>;
|
|
181
|
+
statistics: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
182
|
+
id: z.ZodOptional<z.ZodString>;
|
|
218
183
|
};
|
|
184
|
+
protected static optionsSchema: z.ZodObject<{
|
|
185
|
+
browserPoolOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
186
|
+
navigationTimeoutSecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
187
|
+
preNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
188
|
+
postNavigationHooks: z.ZodDefault<z.ZodCustom<unknown[], unknown[]>>;
|
|
189
|
+
launchContext: z.ZodDefault<z.ZodCustom<Dictionary, Dictionary>>;
|
|
190
|
+
headless: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodString]>>;
|
|
191
|
+
browserPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
192
|
+
remoteBrowser: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
193
|
+
saveResponseCookies: z.ZodDefault<z.ZodBoolean>;
|
|
194
|
+
proxyConfiguration: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
195
|
+
ignoreIframes: z.ZodDefault<z.ZodBoolean>;
|
|
196
|
+
ignoreShadowRoots: z.ZodDefault<z.ZodBoolean>;
|
|
197
|
+
contextPipelineBuilder: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
198
|
+
extendContext: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
199
|
+
requestList: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
200
|
+
requestQueue: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
201
|
+
requestManager: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
202
|
+
requestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
203
|
+
requestHandlerTimeoutSecs: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
204
|
+
errorHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
205
|
+
failedRequestHandler: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
206
|
+
maxRequestRetries: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
207
|
+
sameDomainDelaySecs: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
208
|
+
maxRequestsPerCrawl: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
209
|
+
maxCrawlDepth: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
210
|
+
taskLoopOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
211
|
+
concurrencySystem: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
212
|
+
sessionPool: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
213
|
+
statusMessageLoggingInterval: z.ZodDefault<z.ZodCustom<number, number>>;
|
|
214
|
+
statusMessageCallback: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
215
|
+
additionalHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
216
|
+
ignoreHttpErrorStatusCodes: z.ZodDefault<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
217
|
+
blockedStatusCodes: z.ZodOptional<z.ZodArray<z.ZodCustom<number, number>>>;
|
|
218
|
+
retryOnBlocked: z.ZodDefault<z.ZodBoolean>;
|
|
219
|
+
respectRobotsTxtFile: z.ZodDefault<z.ZodUnion<readonly [z.ZodBoolean, z.ZodCustom<Dictionary, Dictionary>]>>;
|
|
220
|
+
transactionalStorage: z.ZodOptional<z.ZodUnion<readonly [z.ZodBoolean, z.ZodObject<{
|
|
221
|
+
requestQueue: z.ZodOptional<z.ZodEnum<{
|
|
222
|
+
deferred: "deferred";
|
|
223
|
+
writeThrough: "writeThrough";
|
|
224
|
+
}>>;
|
|
225
|
+
}, z.core.$strict>]>>;
|
|
226
|
+
onSkippedRequest: z.ZodOptional<z.ZodCustom<(...args: any[]) => unknown, (...args: any[]) => unknown>>;
|
|
227
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
228
|
+
httpClient: z.ZodOptional<z.ZodCustom<import("@crawlee/http-client").BaseHttpClient, import("@crawlee/http-client").BaseHttpClient>>;
|
|
229
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
230
|
+
configuration: z.ZodOptional<z.ZodCustom<import("@crawlee/browser").Configuration, import("@crawlee/browser").Configuration>>;
|
|
231
|
+
storageBackend: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
232
|
+
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
233
|
+
eventManager: z.ZodOptional<z.ZodCustom<import("@crawlee/browser").EventManager, import("@crawlee/browser").EventManager>>;
|
|
234
|
+
logger: z.ZodOptional<z.ZodType<Dictionary<any>, unknown, z.core.$ZodTypeInternals<Dictionary<any>, unknown>>>;
|
|
235
|
+
minConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
236
|
+
maxConcurrency: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
237
|
+
maxRequestsPerMinute: z.ZodOptional<z.ZodCustom<number, number>>;
|
|
238
|
+
keepAlive: z.ZodOptional<z.ZodBoolean>;
|
|
239
|
+
statistics: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
240
|
+
id: z.ZodOptional<z.ZodString>;
|
|
241
|
+
}, z.core.$strict>;
|
|
219
242
|
/**
|
|
220
243
|
* All `PuppeteerCrawler` parameters are passed via an options object.
|
|
221
244
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { BrowserCrawler, RequestState, Router } from '@crawlee/browser';
|
|
2
|
-
import { serviceLocator } from '@crawlee/core';
|
|
3
|
-
import
|
|
2
|
+
import { parseArgument, schemas, serviceLocator } from '@crawlee/core';
|
|
3
|
+
import { z } from 'zod';
|
|
4
4
|
import { PuppeteerLauncher } from './puppeteer-launcher.js';
|
|
5
5
|
import { gotoExtended, puppeteerUtils } from './utils/puppeteer_utils.js';
|
|
6
6
|
/**
|
|
@@ -71,16 +71,17 @@ import { gotoExtended, puppeteerUtils } from './utils/puppeteer_utils.js';
|
|
|
71
71
|
export class PuppeteerCrawler extends BrowserCrawler {
|
|
72
72
|
static optionsShape = {
|
|
73
73
|
...BrowserCrawler.optionsShape,
|
|
74
|
-
browserPoolOptions:
|
|
74
|
+
browserPoolOptions: schemas.anyObject.optional(),
|
|
75
75
|
};
|
|
76
|
+
static optionsSchema = z.strictObject(PuppeteerCrawler.optionsShape);
|
|
76
77
|
/**
|
|
77
78
|
* All `PuppeteerCrawler` parameters are passed via an options object.
|
|
78
79
|
*/
|
|
79
80
|
constructor(options = {}) {
|
|
80
|
-
|
|
81
|
-
const { launchContext
|
|
81
|
+
const parsedOptions = parseArgument(options, PuppeteerCrawler.optionsSchema, 'PuppeteerCrawlerOptions');
|
|
82
|
+
const { launchContext, headless, proxyConfiguration, contextPipelineBuilder, ...browserCrawlerOptions } = parsedOptions;
|
|
82
83
|
const browserPoolOptions = {
|
|
83
|
-
...
|
|
84
|
+
...parsedOptions.browserPoolOptions,
|
|
84
85
|
};
|
|
85
86
|
if (launchContext.proxyUrl) {
|
|
86
87
|
throw new Error('PuppeteerCrawlerOptions.launchContext.proxyUrl is not allowed in PuppeteerCrawler.' +
|
|
@@ -95,7 +96,7 @@ export class PuppeteerCrawler extends BrowserCrawler {
|
|
|
95
96
|
launchContext.launchOptions ??= {};
|
|
96
97
|
launchContext.launchOptions.headless = headless;
|
|
97
98
|
}
|
|
98
|
-
const puppeteerLauncher = new PuppeteerLauncher(launchContext,
|
|
99
|
+
const puppeteerLauncher = new PuppeteerLauncher(launchContext, parsedOptions.configuration);
|
|
99
100
|
browserPoolOptions.browserPlugins = [puppeteerLauncher.createBrowserPlugin()];
|
|
100
101
|
super({
|
|
101
102
|
...browserCrawlerOptions,
|
|
@@ -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
|
|
@@ -69,24 +70,30 @@ export declare class PuppeteerLauncher extends BrowserLauncher<PuppeteerPlugin,
|
|
|
69
70
|
readonly configuration: Configuration;
|
|
70
71
|
protected static optionsShape: {
|
|
71
72
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
72
|
-
launcher: import("
|
|
73
|
+
launcher: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
|
|
74
|
+
proxyUrl: z.ZodOptional<z.ZodURL>;
|
|
75
|
+
useChrome: z.ZodOptional<z.ZodBoolean>;
|
|
76
|
+
useIncognitoPages: z.ZodOptional<z.ZodBoolean>;
|
|
77
|
+
browserPerProxy: z.ZodOptional<z.ZodBoolean>;
|
|
78
|
+
ignoreProxyCertificate: z.ZodOptional<z.ZodBoolean>;
|
|
79
|
+
userDataDir: z.ZodOptional<z.ZodString>;
|
|
73
80
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
-
ignoreProxyCertificate: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
|
|
83
|
-
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
84
|
-
userDataDir: import("ow").StringPredicate & import("ow").BasePredicate<string | undefined>;
|
|
81
|
+
launchOptions: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
|
|
82
|
+
userAgent: z.ZodOptional<z.ZodString>;
|
|
83
|
+
};
|
|
84
|
+
protected static optionsSchema: z.ZodObject<{
|
|
85
85
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
86
|
-
|
|
86
|
+
launcher: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
|
|
87
|
+
proxyUrl: z.ZodOptional<z.ZodURL>;
|
|
88
|
+
useChrome: z.ZodOptional<z.ZodBoolean>;
|
|
89
|
+
useIncognitoPages: z.ZodOptional<z.ZodBoolean>;
|
|
90
|
+
browserPerProxy: z.ZodOptional<z.ZodBoolean>;
|
|
91
|
+
ignoreProxyCertificate: z.ZodOptional<z.ZodBoolean>;
|
|
92
|
+
userDataDir: z.ZodOptional<z.ZodString>;
|
|
87
93
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
launchOptions: z.ZodOptional<z.ZodCustom<import("@crawlee/types").Dictionary, import("@crawlee/types").Dictionary>>;
|
|
95
|
+
userAgent: z.ZodOptional<z.ZodString>;
|
|
96
|
+
}, z.core.$strict>;
|
|
90
97
|
/**
|
|
91
98
|
* All `PuppeteerLauncher` parameters are passed via an launchContext object.
|
|
92
99
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { BrowserLauncher, Configuration } from '@crawlee/browser';
|
|
1
|
+
import { BrowserLauncher, Configuration, parseArgument, schemas } from '@crawlee/browser';
|
|
2
2
|
import { PuppeteerPlugin } from '@crawlee/browser-pool';
|
|
3
|
-
import
|
|
3
|
+
import { z } from 'zod';
|
|
4
4
|
/**
|
|
5
5
|
* `PuppeteerLauncher` is based on the `BrowserLauncher`. It launches `puppeteer` browser instance.
|
|
6
6
|
* @ignore
|
|
@@ -9,14 +9,14 @@ export class PuppeteerLauncher extends BrowserLauncher {
|
|
|
9
9
|
configuration;
|
|
10
10
|
static optionsShape = {
|
|
11
11
|
...BrowserLauncher.optionsShape,
|
|
12
|
-
launcher:
|
|
12
|
+
launcher: schemas.anyObject.optional(),
|
|
13
13
|
};
|
|
14
|
+
static optionsSchema = z.strictObject(PuppeteerLauncher.optionsShape);
|
|
14
15
|
/**
|
|
15
16
|
* All `PuppeteerLauncher` parameters are passed via an launchContext object.
|
|
16
17
|
*/
|
|
17
18
|
constructor(launchContext = {}, configuration = Configuration.getGlobalConfiguration()) {
|
|
18
|
-
|
|
19
|
-
const { launcher = BrowserLauncher.requireLauncherOrThrow('puppeteer', 'apify/actor-node-puppeteer-chrome'), ...browserLauncherOptions } = launchContext;
|
|
19
|
+
const { launcher = BrowserLauncher.requireLauncherOrThrow('puppeteer', 'apify/actor-node-puppeteer-chrome'), ...browserLauncherOptions } = parseArgument(launchContext, PuppeteerLauncher.optionsSchema, 'PuppeteerLaunchContext');
|
|
20
20
|
super({
|
|
21
21
|
...browserLauncherOptions,
|
|
22
22
|
launcher,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
|
-
import { serviceLocator } from '@crawlee/browser';
|
|
3
|
-
|
|
2
|
+
import { parseArgument, schemas, serviceLocator } from '@crawlee/browser';
|
|
3
|
+
const pageSchema = schemas.objectWithKeys(['goto', 'evaluate']);
|
|
4
4
|
// We use weak maps here so that the content gets discarded after page gets closed.
|
|
5
5
|
const pageInterceptRequestHandlersMap = new WeakMap(); // Maps page to an array of request interception handlers.
|
|
6
6
|
const pageInterceptRequestMasterHandlerMap = new WeakMap(); // Maps page to master request interception handler.
|
|
@@ -137,8 +137,8 @@ async function handleRequest(request, interceptRequestHandlers) {
|
|
|
137
137
|
* @param handler Request interception handler.
|
|
138
138
|
*/
|
|
139
139
|
export async function addInterceptRequestHandler(page, handler) {
|
|
140
|
-
|
|
141
|
-
|
|
140
|
+
parseArgument(page, pageSchema);
|
|
141
|
+
parseArgument(handler, schemas.anyFunction);
|
|
142
142
|
if (!pageInterceptRequestHandlersMap.has(page)) {
|
|
143
143
|
pageInterceptRequestHandlersMap.set(page, []);
|
|
144
144
|
}
|
|
@@ -174,8 +174,8 @@ export async function addInterceptRequestHandler(page, handler) {
|
|
|
174
174
|
* @param handler Request interception handler.
|
|
175
175
|
*/
|
|
176
176
|
export async function removeInterceptRequestHandler(page, handler) {
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
parseArgument(page, pageSchema);
|
|
178
|
+
parseArgument(handler, schemas.anyFunction);
|
|
179
179
|
const handlersArray = pageInterceptRequestHandlersMap.get(page).filter((item) => item !== handler);
|
|
180
180
|
pageInterceptRequestHandlersMap.set(page, handlersArray);
|
|
181
181
|
if (handlersArray.length === 0) {
|
|
@@ -20,9 +20,9 @@
|
|
|
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, serviceLocator, validators } from '@crawlee/browser';
|
|
23
|
+
import { Configuration, KeyValueStore, parseArgument, schemas, serviceLocator, validators } from '@crawlee/browser';
|
|
24
24
|
import { expandShadowRoots, sleep } from '@crawlee/utils';
|
|
25
|
-
import
|
|
25
|
+
import { z } from 'zod';
|
|
26
26
|
import { LruCache } from '@apify/datastructures';
|
|
27
27
|
import { enqueueLinksByClickingElements } from '../enqueue-links/click-elements.js';
|
|
28
28
|
import { addInterceptRequestHandler, removeInterceptRequestHandler } from './puppeteer_request_interception.js';
|
|
@@ -30,6 +30,37 @@ const require = createRequire(import.meta.url);
|
|
|
30
30
|
const jqueryPath = require.resolve('jquery');
|
|
31
31
|
const MAX_INJECT_FILE_CACHE_SIZE = 10;
|
|
32
32
|
const DEFAULT_BLOCK_REQUEST_URL_PATTERNS = ['.css', '.jpg', '.jpeg', '.png', '.svg', '.gif', '.woff', '.pdf', '.zip'];
|
|
33
|
+
const filePathSchema = z.string();
|
|
34
|
+
const injectFileOptionsSchema = z.strictObject({
|
|
35
|
+
surviveNavigations: z.boolean().optional(),
|
|
36
|
+
});
|
|
37
|
+
const responseUrlRulesSchema = schemas.arrayOf(z.union([z.string(), z.instanceof(RegExp)]), 'strings or RegExps');
|
|
38
|
+
const gotoExtendedRequestSchema = z.looseObject({
|
|
39
|
+
url: z.url(),
|
|
40
|
+
method: z.string().optional(),
|
|
41
|
+
headers: schemas.anyObject.optional(),
|
|
42
|
+
payload: z.union([z.string(), z.instanceof(Uint8Array)]).optional(),
|
|
43
|
+
});
|
|
44
|
+
const blockRequestsOptionsSchema = z.strictObject({
|
|
45
|
+
urlPatterns: schemas.arrayOf(z.string(), 'strings').default(DEFAULT_BLOCK_REQUEST_URL_PATTERNS),
|
|
46
|
+
extraUrlPatterns: schemas.arrayOf(z.string(), 'strings').default(() => []),
|
|
47
|
+
});
|
|
48
|
+
const infiniteScrollOptionsSchema = z.strictObject({
|
|
49
|
+
timeoutSecs: schemas.anyNumber.default(0),
|
|
50
|
+
maxScrollHeight: schemas.anyNumber.default(0),
|
|
51
|
+
waitForSecs: schemas.anyNumber.default(4),
|
|
52
|
+
scrollDownAndUp: z.boolean().default(false),
|
|
53
|
+
buttonSelector: z.string().optional(),
|
|
54
|
+
stopScrollCallback: schemas.anyFunction.optional(),
|
|
55
|
+
});
|
|
56
|
+
const saveSnapshotOptionsSchema = z.strictObject({
|
|
57
|
+
key: z.string().min(1).default('SNAPSHOT'),
|
|
58
|
+
screenshotQuality: schemas.anyNumber.default(50),
|
|
59
|
+
saveScreenshot: z.boolean().default(true),
|
|
60
|
+
saveHtml: z.boolean().default(true),
|
|
61
|
+
keyValueStoreName: z.string().optional(),
|
|
62
|
+
configuration: schemas.anyObject.optional(),
|
|
63
|
+
});
|
|
33
64
|
const getLog = () => serviceLocator.getChildLog('Puppeteer Utils');
|
|
34
65
|
/**
|
|
35
66
|
* Cache contents of previously injected files to limit file system access.
|
|
@@ -47,18 +78,16 @@ const injectedFilesCache = new LruCache({ maxLength: MAX_INJECT_FILE_CACHE_SIZE
|
|
|
47
78
|
* @param [options]
|
|
48
79
|
*/
|
|
49
80
|
export async function injectFile(page, filePath, options = {}) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
surviveNavigations: ow.optional.boolean,
|
|
54
|
-
}));
|
|
81
|
+
parseArgument(page, validators.browserPage);
|
|
82
|
+
parseArgument(filePath, filePathSchema);
|
|
83
|
+
const { surviveNavigations } = parseArgument(options, injectFileOptionsSchema);
|
|
55
84
|
let contents = injectedFilesCache.get(filePath);
|
|
56
85
|
if (!contents) {
|
|
57
86
|
contents = await readFile(filePath, 'utf8');
|
|
58
87
|
injectedFilesCache.add(filePath, contents);
|
|
59
88
|
}
|
|
60
89
|
const evalP = page.evaluate(contents);
|
|
61
|
-
if (
|
|
90
|
+
if (surviveNavigations) {
|
|
62
91
|
page.on('framenavigated', async () => page
|
|
63
92
|
.evaluate(contents)
|
|
64
93
|
.catch((error) => getLog().warning('An error occurred during the script injection!', { error })));
|
|
@@ -92,7 +121,7 @@ export async function injectFile(page, filePath, options = {}) {
|
|
|
92
121
|
* @param [options.surviveNavigations] Opt-out option to disable the JQuery reinjection after navigation.
|
|
93
122
|
*/
|
|
94
123
|
export async function injectJQuery(page, options) {
|
|
95
|
-
|
|
124
|
+
parseArgument(page, validators.browserPage);
|
|
96
125
|
return injectFile(page, jqueryPath, { surviveNavigations: options?.surviveNavigations ?? true });
|
|
97
126
|
}
|
|
98
127
|
/**
|
|
@@ -108,7 +137,7 @@ export async function injectJQuery(page, options) {
|
|
|
108
137
|
* @param ignoreShadowRoots
|
|
109
138
|
*/
|
|
110
139
|
export async function parseWithCheerio(page, ignoreShadowRoots = false, ignoreIframes = false) {
|
|
111
|
-
|
|
140
|
+
parseArgument(page, validators.browserPage);
|
|
112
141
|
if (page.frames().length > 1 && !ignoreIframes) {
|
|
113
142
|
const frames = await page.$$('iframe');
|
|
114
143
|
await Promise.all(frames.map(async (frame) => {
|
|
@@ -187,12 +216,8 @@ export async function parseWithCheerio(page, ignoreShadowRoots = false, ignoreIf
|
|
|
187
216
|
* @param [options]
|
|
188
217
|
*/
|
|
189
218
|
export async function blockRequests(page, options = {}) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
urlPatterns: ow.optional.array.ofType(ow.string),
|
|
193
|
-
extraUrlPatterns: ow.optional.array.ofType(ow.string),
|
|
194
|
-
}));
|
|
195
|
-
const { urlPatterns = DEFAULT_BLOCK_REQUEST_URL_PATTERNS, extraUrlPatterns = [] } = options;
|
|
219
|
+
parseArgument(page, validators.browserPage);
|
|
220
|
+
const { urlPatterns, extraUrlPatterns } = parseArgument(options, blockRequestsOptionsSchema);
|
|
196
221
|
const patternsToBlock = [...urlPatterns, ...extraUrlPatterns];
|
|
197
222
|
// We use CDP commands instead of request interception as the latter disables caching, which is not ideal
|
|
198
223
|
await sendCDPCommand(page, 'Network.setBlockedURLs', { urls: patternsToBlock });
|
|
@@ -249,9 +274,9 @@ export const blockResources = async (page, resourceTypes = ['stylesheet', 'font'
|
|
|
249
274
|
* @deprecated
|
|
250
275
|
*/
|
|
251
276
|
export async function cacheResponses(page, cache, responseUrlRules) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
277
|
+
parseArgument(page, validators.browserPage);
|
|
278
|
+
parseArgument(cache, schemas.anyObject);
|
|
279
|
+
parseArgument(responseUrlRules, responseUrlRulesSchema);
|
|
255
280
|
serviceLocator
|
|
256
281
|
.getLogger()
|
|
257
282
|
.deprecated('utils.puppeteer.cacheResponses() has a high impact on performance ' +
|
|
@@ -344,14 +369,9 @@ export function compileScript(scriptString, context = Object.create(null)) {
|
|
|
344
369
|
* @param [gotoOptions] Custom options for `page.goto()`.
|
|
345
370
|
*/
|
|
346
371
|
export async function gotoExtended(page, request, gotoOptions = {}) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
method: ow.optional.string,
|
|
351
|
-
headers: ow.optional.object,
|
|
352
|
-
payload: ow.optional.any(ow.string, ow.uint8Array),
|
|
353
|
-
}));
|
|
354
|
-
ow(gotoOptions, ow.object);
|
|
372
|
+
parseArgument(page, validators.browserPage);
|
|
373
|
+
parseArgument(request, gotoExtendedRequestSchema);
|
|
374
|
+
parseArgument(gotoOptions, schemas.anyObject);
|
|
355
375
|
gotoOptions = { ...gotoOptions };
|
|
356
376
|
if (gotoOptions.waitUntil === 'networkidle') {
|
|
357
377
|
gotoOptions.waitUntil = 'networkidle0';
|
|
@@ -407,16 +427,8 @@ export async function gotoExtended(page, request, gotoOptions = {}) {
|
|
|
407
427
|
* @param [options]
|
|
408
428
|
*/
|
|
409
429
|
export async function infiniteScroll(page, options = {}) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
timeoutSecs: ow.optional.number,
|
|
413
|
-
maxScrollHeight: ow.optional.number,
|
|
414
|
-
waitForSecs: ow.optional.number,
|
|
415
|
-
scrollDownAndUp: ow.optional.boolean,
|
|
416
|
-
buttonSelector: ow.optional.string,
|
|
417
|
-
stopScrollCallback: ow.optional.function,
|
|
418
|
-
}));
|
|
419
|
-
const { timeoutSecs = 0, maxScrollHeight = 0, waitForSecs = 4, scrollDownAndUp = false, buttonSelector, stopScrollCallback, } = options;
|
|
430
|
+
parseArgument(page, validators.browserPage);
|
|
431
|
+
const { timeoutSecs, maxScrollHeight, waitForSecs, scrollDownAndUp, buttonSelector, stopScrollCallback } = parseArgument(options, infiniteScrollOptionsSchema);
|
|
420
432
|
let finished;
|
|
421
433
|
const startTime = Date.now();
|
|
422
434
|
const CHECK_INTERVAL_MILLIS = 1000;
|
|
@@ -508,16 +520,8 @@ export async function infiniteScroll(page, options = {}) {
|
|
|
508
520
|
* @param [options]
|
|
509
521
|
*/
|
|
510
522
|
export async function saveSnapshot(page, options = {}) {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
key: ow.optional.string.nonEmpty,
|
|
514
|
-
screenshotQuality: ow.optional.number,
|
|
515
|
-
saveScreenshot: ow.optional.boolean,
|
|
516
|
-
saveHtml: ow.optional.boolean,
|
|
517
|
-
keyValueStoreName: ow.optional.string,
|
|
518
|
-
configuration: ow.optional.object,
|
|
519
|
-
}));
|
|
520
|
-
const { key = 'SNAPSHOT', screenshotQuality = 50, saveScreenshot = true, saveHtml = true, keyValueStoreName, configuration, } = options;
|
|
523
|
+
parseArgument(page, validators.browserPage);
|
|
524
|
+
const { key, screenshotQuality, saveScreenshot, saveHtml, keyValueStoreName, configuration } = parseArgument(options, saveSnapshotOptionsSchema);
|
|
521
525
|
try {
|
|
522
526
|
const store = await KeyValueStore.open(keyValueStoreName ? { name: keyValueStoreName } : null, {
|
|
523
527
|
configuration: configuration ?? Configuration.getGlobalConfiguration(),
|
|
@@ -564,7 +568,7 @@ ${error.message}
|
|
|
564
568
|
return idcacPlaywright;
|
|
565
569
|
}
|
|
566
570
|
export async function closeCookieModals(page) {
|
|
567
|
-
|
|
571
|
+
parseArgument(page, validators.browserPage);
|
|
568
572
|
const idcac = await getIdcacPlaywright();
|
|
569
573
|
if (idcac?.getInjectableScript()) {
|
|
570
574
|
await page.evaluate(idcac.getInjectableScript());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crawlee/puppeteer",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.122",
|
|
4
4
|
"description": "The scalable web crawling and scraping library for JavaScript/Node.js. Enables development of data extraction and web automation jobs (not only) with headless Chrome and Puppeteer.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22.0.0"
|
|
@@ -48,16 +48,16 @@
|
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@apify/datastructures": "^2.0.3",
|
|
51
|
-
"@crawlee/browser": "4.0.0-beta.
|
|
52
|
-
"@crawlee/browser-pool": "4.0.0-beta.
|
|
53
|
-
"@crawlee/core": "4.0.0-beta.
|
|
54
|
-
"@crawlee/types": "4.0.0-beta.
|
|
55
|
-
"@crawlee/utils": "4.0.0-beta.
|
|
51
|
+
"@crawlee/browser": "4.0.0-beta.122",
|
|
52
|
+
"@crawlee/browser-pool": "4.0.0-beta.122",
|
|
53
|
+
"@crawlee/core": "4.0.0-beta.122",
|
|
54
|
+
"@crawlee/types": "4.0.0-beta.122",
|
|
55
|
+
"@crawlee/utils": "4.0.0-beta.122",
|
|
56
56
|
"cheerio": "^1.0.0",
|
|
57
57
|
"devtools-protocol": "*",
|
|
58
58
|
"jquery": "^3.7.1",
|
|
59
|
-
"
|
|
60
|
-
"
|
|
59
|
+
"tslib": "^2.8.1",
|
|
60
|
+
"zod": "^4.4.3"
|
|
61
61
|
},
|
|
62
62
|
"peerDependencies": {
|
|
63
63
|
"idcac-playwright": "^0.2.0",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
},
|
|
81
|
-
"gitHead": "
|
|
81
|
+
"gitHead": "2c3e87fefdb9e1fca4c144f03167d8524cfdc2e5"
|
|
82
82
|
}
|