@crawlee/playwright 4.0.0-beta.124 → 4.0.0-beta.125
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,34 +1,39 @@
|
|
|
1
1
|
import type { BrowserHook, LoadedRequest, Request, RouterHandler, RouteSchemas, RoutesFromSchemas } from '@crawlee/browser';
|
|
2
2
|
import type { BasicCrawlerOptions } from '@crawlee/basic';
|
|
3
3
|
import { BasicCrawler } from '@crawlee/basic';
|
|
4
|
-
import type { ContextPipeline, CrawlingContext, EnqueueLinksOptions, GetUserDataFromRequest, RouterRoutes,
|
|
5
|
-
import { Statistics } from '@crawlee/core';
|
|
4
|
+
import type { ContextPipeline, CrawlingContext, EnqueueLinksOptions, GetUserDataFromRequest, RouterRoutes, StorageTransactionView } from '@crawlee/core';
|
|
6
5
|
import type { Dictionary, Awaitable } from '@crawlee/types';
|
|
7
6
|
import { type CheerioRoot } from '@crawlee/utils/internal';
|
|
8
7
|
import { type Cheerio } from 'cheerio';
|
|
9
8
|
import type { AnyNode } from 'domhandler';
|
|
10
9
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
11
10
|
import type { Page } from 'playwright';
|
|
11
|
+
import { z } from 'zod';
|
|
12
12
|
import type { PlaywrightCrawlingContext, PlaywrightGotoOptions } from './playwright-crawler.js';
|
|
13
13
|
import { type IRenderingTypePredictor } from './utils/rendering-type-prediction.js';
|
|
14
|
-
|
|
15
|
-
httpOnlyRequestHandlerRuns
|
|
16
|
-
browserRequestHandlerRuns
|
|
17
|
-
renderingTypeMispredictions
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
14
|
+
declare const adaptiveStatisticStateSchema: z.ZodObject<{
|
|
15
|
+
httpOnlyRequestHandlerRuns: z.ZodDefault<z.ZodNumber>;
|
|
16
|
+
browserRequestHandlerRuns: z.ZodDefault<z.ZodNumber>;
|
|
17
|
+
renderingTypeMispredictions: z.ZodDefault<z.ZodNumber>;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
/**
|
|
20
|
+
* The extra statistics fields {@link AdaptivePlaywrightCrawler} tracks on top of the built-in
|
|
21
|
+
* {@link StatisticState} ones. They are available on `crawler.stats.state` and are persisted with the rest of
|
|
22
|
+
* the statistics.
|
|
23
|
+
*/
|
|
24
|
+
export type AdaptivePlaywrightCrawlerStatisticState = z.infer<typeof adaptiveStatisticStateSchema>;
|
|
25
|
+
/**
|
|
26
|
+
* The {@link AdaptivePlaywrightCrawlerStatisticState} fields as a {@link Statistics} state extension, defaults
|
|
27
|
+
* and all. A {@link Statistics} instance to be injected into an {@link AdaptivePlaywrightCrawler} has to carry
|
|
28
|
+
* them - `deserialize.extend()` your own fields onto this one and pass the result as `stateExtension`.
|
|
29
|
+
*/
|
|
30
|
+
export declare const adaptivePlaywrightCrawlerStatisticState: {
|
|
31
|
+
deserialize: z.ZodObject<{
|
|
32
|
+
httpOnlyRequestHandlerRuns: z.ZodDefault<z.ZodNumber>;
|
|
33
|
+
browserRequestHandlerRuns: z.ZodDefault<z.ZodNumber>;
|
|
34
|
+
renderingTypeMispredictions: z.ZodDefault<z.ZodNumber>;
|
|
35
|
+
}, z.core.$strip>;
|
|
36
|
+
};
|
|
32
37
|
export interface AdaptivePlaywrightCrawlerContext<UserData extends Dictionary = any> extends CrawlingContext<UserData> {
|
|
33
38
|
request: LoadedRequest<Request<UserData>>;
|
|
34
39
|
/**
|
|
@@ -87,7 +92,7 @@ type AdaptiveHook<ContextExtension = Dictionary<never>> = BrowserHook<AdaptiveHo
|
|
|
87
92
|
type AdaptivePostNavigationHook<ContextExtension = Dictionary<never>> = BrowserHook<Omit<AdaptiveHookContext, 'request'> & {
|
|
88
93
|
request: LoadedRequest<Request>;
|
|
89
94
|
}, ContextExtension>;
|
|
90
|
-
export interface AdaptivePlaywrightCrawlerOptions<ContextExtension = Dictionary<never>, ExtendedContext extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<AdaptivePlaywrightCrawlerContext['request']
|
|
95
|
+
export interface AdaptivePlaywrightCrawlerOptions<ContextExtension = Dictionary<never>, ExtendedContext extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<AdaptivePlaywrightCrawlerContext['request']>>, StatisticStateExtension extends AdaptivePlaywrightCrawlerStatisticState = AdaptivePlaywrightCrawlerStatisticState> extends Omit<BasicCrawlerOptions<AdaptivePlaywrightCrawlerContext, ContextExtension, ExtendedContext, Routes, StatisticStateExtension>, 'preNavigationHooks' | 'postNavigationHooks'> {
|
|
91
96
|
/**
|
|
92
97
|
* Async functions that are sequentially evaluated before the navigation. Good for setting additional cookies.
|
|
93
98
|
* The function accepts a subset of the crawling context. If you attempt to access the `page` property during HTTP-only crawling,
|
|
@@ -177,10 +182,9 @@ export interface AdaptivePlaywrightCrawlerOptions<ContextExtension = Dictionary<
|
|
|
177
182
|
*
|
|
178
183
|
* @experimental
|
|
179
184
|
*/
|
|
180
|
-
export declare class AdaptivePlaywrightCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<AdaptivePlaywrightCrawlerContext['request']
|
|
185
|
+
export declare class AdaptivePlaywrightCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<AdaptivePlaywrightCrawlerContext['request']>>, StatisticStateExtension extends AdaptivePlaywrightCrawlerStatisticState = AdaptivePlaywrightCrawlerStatisticState> extends BasicCrawler<AdaptivePlaywrightCrawlerContext, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> {
|
|
181
186
|
#private;
|
|
182
|
-
|
|
183
|
-
constructor(options?: AdaptivePlaywrightCrawlerOptions<ContextExtension, ExtendedContext, Routes>);
|
|
187
|
+
constructor(options?: AdaptivePlaywrightCrawlerOptions<ContextExtension, ExtendedContext, Routes, StatisticStateExtension>);
|
|
184
188
|
protected init(): Promise<void>;
|
|
185
189
|
protected buildContextPipeline(): ContextPipeline<CrawlingContext<Dictionary>, CrawlingContext<Dictionary> & {
|
|
186
190
|
readonly request: LoadedRequest<Request<Dictionary>>;
|
|
@@ -8,39 +8,22 @@ import { z } from 'zod';
|
|
|
8
8
|
import { addTimeoutToPromise } from '@apify/timeout';
|
|
9
9
|
import { PlaywrightCrawler } from './playwright-crawler.js';
|
|
10
10
|
import { RenderingTypePredictor, } from './utils/rendering-type-prediction.js';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
browserRequestHandlerRuns: persistedState.browserRequestHandlerRuns,
|
|
28
|
-
renderingTypeMispredictions: persistedState.renderingTypeMispredictions,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
trackHttpOnlyRequestHandlerRun() {
|
|
32
|
-
this.state.httpOnlyRequestHandlerRuns ??= 0;
|
|
33
|
-
this.state.httpOnlyRequestHandlerRuns += 1;
|
|
34
|
-
}
|
|
35
|
-
trackBrowserRequestHandlerRun() {
|
|
36
|
-
this.state.browserRequestHandlerRuns ??= 0;
|
|
37
|
-
this.state.browserRequestHandlerRuns += 1;
|
|
38
|
-
}
|
|
39
|
-
trackRenderingTypeMisprediction() {
|
|
40
|
-
this.state.renderingTypeMispredictions ??= 0;
|
|
41
|
-
this.state.renderingTypeMispredictions += 1;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
11
|
+
const adaptiveStatisticStateSchema = z.object({
|
|
12
|
+
/** How many requests were handled by the HTTP-only request handler. */
|
|
13
|
+
httpOnlyRequestHandlerRuns: z.number().default(0),
|
|
14
|
+
/** How many requests were handled in a browser. */
|
|
15
|
+
browserRequestHandlerRuns: z.number().default(0),
|
|
16
|
+
/** How many times the HTTP-only handler produced a result the `resultChecker` rejected. */
|
|
17
|
+
renderingTypeMispredictions: z.number().default(0),
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* The {@link AdaptivePlaywrightCrawlerStatisticState} fields as a {@link Statistics} state extension, defaults
|
|
21
|
+
* and all. A {@link Statistics} instance to be injected into an {@link AdaptivePlaywrightCrawler} has to carry
|
|
22
|
+
* them - `deserialize.extend()` your own fields onto this one and pass the result as `stateExtension`.
|
|
23
|
+
*/
|
|
24
|
+
export const adaptivePlaywrightCrawlerStatisticState = {
|
|
25
|
+
deserialize: adaptiveStatisticStateSchema,
|
|
26
|
+
};
|
|
44
27
|
const proxyLogMethods = [
|
|
45
28
|
'error',
|
|
46
29
|
'exception',
|
|
@@ -88,10 +71,6 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
88
71
|
#staticContextPipeline;
|
|
89
72
|
#browserContextPipeline;
|
|
90
73
|
#individualRequestHandlerTimeoutMillis;
|
|
91
|
-
// The constructor always injects an `AdaptivePlaywrightCrawlerStatistics`, so narrowing the cast is sound.
|
|
92
|
-
get stats() {
|
|
93
|
-
return super.stats;
|
|
94
|
-
}
|
|
95
74
|
/**
|
|
96
75
|
* The write policy of the per-attempt transactions. Defaults the request queue to `deferred`:
|
|
97
76
|
* a discarded attempt's enqueues must never reach the queue.
|
|
@@ -103,6 +82,16 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
103
82
|
// The user's value is replaced by `false` in the `super` call below — validate it separately,
|
|
104
83
|
// wrapped in an object so the error still names the field.
|
|
105
84
|
parseArgument({ transactionalStorage }, z.object({ transactionalStorage: BasicCrawler.optionsShape.transactionalStorage }), 'AdaptivePlaywrightCrawlerOptions');
|
|
85
|
+
// The extra fields are only tracked if the injected instance was built with them - the types enforce that,
|
|
86
|
+
// but plain JS callers would otherwise silently increment `undefined` into a sticky `NaN`. Extend
|
|
87
|
+
// `adaptivePlaywrightCrawlerStatisticState` to satisfy this.
|
|
88
|
+
if (statistics !== undefined) {
|
|
89
|
+
parseArgument(statistics.state, z.object({
|
|
90
|
+
httpOnlyRequestHandlerRuns: z.number(),
|
|
91
|
+
browserRequestHandlerRuns: z.number(),
|
|
92
|
+
renderingTypeMispredictions: z.number(),
|
|
93
|
+
}), 'statistics.state');
|
|
94
|
+
}
|
|
106
95
|
// Per-attempt buffering is load-bearing here: the handler runs up to twice per request and the
|
|
107
96
|
// losing attempt's writes must be discardable.
|
|
108
97
|
if (transactionalStorage === false) {
|
|
@@ -111,20 +100,19 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
111
100
|
'attempts. `transactionalStorage: false` is therefore not supported; a write policy ' +
|
|
112
101
|
'object is accepted and forwarded to the per-attempt transactions.');
|
|
113
102
|
}
|
|
114
|
-
if (statistics !== undefined && !(statistics instanceof AdaptivePlaywrightCrawlerStatistics)) {
|
|
115
|
-
throw new Error('AdaptivePlaywrightCrawler tracks extra fields on its own Statistics subclass and cannot use a ' +
|
|
116
|
-
'plain `statistics` instance. Omit the option to let the crawler build its own.');
|
|
117
|
-
}
|
|
118
103
|
super({
|
|
119
104
|
...rest,
|
|
120
105
|
errorHandler,
|
|
121
106
|
failedRequestHandler,
|
|
122
107
|
requestHandler,
|
|
123
108
|
requestHandlerTimeoutSecs,
|
|
124
|
-
//
|
|
109
|
+
// The base would build a `Statistics` without the adaptive fields, so provide a default that has them.
|
|
110
|
+
// The cast covers a `StatisticStateExtension` that adds further fields - those can only come from an
|
|
111
|
+
// injected instance, in which case this default is never built.
|
|
125
112
|
statistics: statistics ??
|
|
126
|
-
new
|
|
113
|
+
new Statistics({
|
|
127
114
|
logMessage: `${AdaptivePlaywrightCrawler.name} request statistics:`,
|
|
115
|
+
stateExtension: adaptivePlaywrightCrawlerStatisticState,
|
|
128
116
|
}),
|
|
129
117
|
contextPipelineBuilder: contextPipelineBuilder ?? (() => this.buildContextPipeline()),
|
|
130
118
|
// The base crawler must not wrap requests in a transaction of its own - this crawler opens
|
|
@@ -334,7 +322,7 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
334
322
|
try {
|
|
335
323
|
if (renderingTypePrediction.renderingType === 'static' && !shouldDetectRenderingType) {
|
|
336
324
|
crawlingContext.log.debug(`Running HTTP-only request handler for ${crawlingContext.request.url}`);
|
|
337
|
-
this.stats.
|
|
325
|
+
this.stats.state.httpOnlyRequestHandlerRuns++;
|
|
338
326
|
const plainHTTPRun = await this.crawlOne('static', crawlingContext, crawlingContext.useState, transactions);
|
|
339
327
|
if (plainHTTPRun.ok && this.#resultChecker(plainHTTPRun.result)) {
|
|
340
328
|
crawlingContext.log.debug(`HTTP-only request handler succeeded for ${crawlingContext.request.url}`);
|
|
@@ -354,11 +342,11 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
354
342
|
}
|
|
355
343
|
else {
|
|
356
344
|
crawlingContext.log.warning(`HTTP-only request handler returned a suspicious result for ${crawlingContext.request.url}`);
|
|
357
|
-
this.stats.
|
|
345
|
+
this.stats.state.renderingTypeMispredictions++;
|
|
358
346
|
}
|
|
359
347
|
}
|
|
360
348
|
crawlingContext.log.debug(`Running browser request handler for ${crawlingContext.request.url}`);
|
|
361
|
-
this.stats.
|
|
349
|
+
this.stats.state.browserRequestHandlerRuns++;
|
|
362
350
|
// Run the request handler in a browser. The copy of the crawler state is kept so that we can perform
|
|
363
351
|
// a rendering type detection if necessary. Without this measure, the HTTP request handler would run
|
|
364
352
|
// under different conditions, which could change its behavior. Changes done to the crawler state by
|
|
@@ -12,9 +12,9 @@ export type PlaywrightGotoOptions = NonNullable<Parameters<Page['goto']>[1]>;
|
|
|
12
12
|
export interface PlaywrightCrawlingContext<UserData extends Dictionary = any> extends BrowserCrawlingContext<Page, Response, UserData, PlaywrightGotoOptions>, PlaywrightContextUtils {
|
|
13
13
|
}
|
|
14
14
|
export type PlaywrightHook<UserData extends Dictionary = any> = BrowserHook<PlaywrightCrawlingContext<UserData>>;
|
|
15
|
-
export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>, ExtendedContext extends PlaywrightCrawlingContext = PlaywrightCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<PlaywrightCrawlingContext['request']
|
|
15
|
+
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, {
|
|
16
16
|
browserPlugins: [PlaywrightPlugin];
|
|
17
|
-
}, Routes> {
|
|
17
|
+
}, Routes, StatisticStateExtension> {
|
|
18
18
|
/**
|
|
19
19
|
* The same options as used by {@link launchPlaywright}.
|
|
20
20
|
*/
|
|
@@ -142,9 +142,9 @@ export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>,
|
|
|
142
142
|
* ```
|
|
143
143
|
* @category Crawlers
|
|
144
144
|
*/
|
|
145
|
-
export declare class PlaywrightCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends PlaywrightCrawlingContext = PlaywrightCrawlingContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<PlaywrightCrawlingContext['request']
|
|
145
|
+
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, {
|
|
146
146
|
browserPlugins: [PlaywrightPlugin];
|
|
147
|
-
}, LaunchOptions, PlaywrightCrawlingContext, ContextExtension, ExtendedContext, Routes> {
|
|
147
|
+
}, LaunchOptions, PlaywrightCrawlingContext, ContextExtension, ExtendedContext, Routes, StatisticStateExtension> {
|
|
148
148
|
protected static optionsShape: {
|
|
149
149
|
browserPoolOptions: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
150
150
|
launcher: z.ZodOptional<z.ZodCustom<Dictionary, Dictionary>>;
|
|
@@ -266,7 +266,7 @@ export declare class PlaywrightCrawler<ContextExtension = Dictionary<never>, Ext
|
|
|
266
266
|
/**
|
|
267
267
|
* All `PlaywrightCrawler` parameters are passed via an options object.
|
|
268
268
|
*/
|
|
269
|
-
constructor(options?: PlaywrightCrawlerOptions<ContextExtension, ExtendedContext, Routes>);
|
|
269
|
+
constructor(options?: PlaywrightCrawlerOptions<ContextExtension, ExtendedContext, Routes, StatisticStateExtension>);
|
|
270
270
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
271
271
|
protected buildContextPipeline(): import("@crawlee/browser").ContextPipeline<import("@crawlee/browser").CrawlingContext<Dictionary>, BrowserCrawlingContext<Page, Response, Dictionary, Dictionary> & {
|
|
272
272
|
injectFile: (filePath: string, options?: InjectFileOptions) => Promise<unknown>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crawlee/playwright",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.125",
|
|
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"
|
|
@@ -49,13 +49,13 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"@apify/datastructures": "^2.0.3",
|
|
51
51
|
"@apify/timeout": "^0.4.4",
|
|
52
|
-
"@crawlee/basic": "4.0.0-beta.
|
|
53
|
-
"@crawlee/browser": "4.0.0-beta.
|
|
54
|
-
"@crawlee/browser-pool": "4.0.0-beta.
|
|
55
|
-
"@crawlee/cheerio": "4.0.0-beta.
|
|
56
|
-
"@crawlee/core": "4.0.0-beta.
|
|
57
|
-
"@crawlee/types": "4.0.0-beta.
|
|
58
|
-
"@crawlee/utils": "4.0.0-beta.
|
|
52
|
+
"@crawlee/basic": "4.0.0-beta.125",
|
|
53
|
+
"@crawlee/browser": "4.0.0-beta.125",
|
|
54
|
+
"@crawlee/browser-pool": "4.0.0-beta.125",
|
|
55
|
+
"@crawlee/cheerio": "4.0.0-beta.125",
|
|
56
|
+
"@crawlee/core": "4.0.0-beta.125",
|
|
57
|
+
"@crawlee/types": "4.0.0-beta.125",
|
|
58
|
+
"@crawlee/utils": "4.0.0-beta.125",
|
|
59
59
|
"cheerio": "^1.0.0",
|
|
60
60
|
"jquery": "^3.7.1",
|
|
61
61
|
"ml-logistic-regression": "^2.0.0",
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "04a7212dd4abe4a5f94f5fc9632acb6089819c8b"
|
|
88
88
|
}
|