@crawlee/playwright 4.0.0-beta.80 → 4.0.0-beta.82
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/adaptive-playwright-crawler.d.ts +47 -18
- package/internals/adaptive-playwright-crawler.js +55 -16
- package/internals/playwright-crawler.d.ts +3 -3
- package/internals/utils/rendering-type-prediction.d.ts +2 -5
- package/internals/utils/rendering-type-prediction.js +9 -2
- package/package.json +9 -9
|
@@ -1,15 +1,14 @@
|
|
|
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,
|
|
4
|
+
import type { ContextPipeline, CrawlingContext, EnqueueLinksOptions, GetUserDataFromRequest, RouterRoutes, StatisticsOptions, StatisticState } from '@crawlee/core';
|
|
5
5
|
import { RequestHandlerResult, Statistics } from '@crawlee/core';
|
|
6
|
-
import type {
|
|
6
|
+
import type { Dictionary, Awaitable } from '@crawlee/types';
|
|
7
7
|
import { type CheerioRoot } from '@crawlee/utils';
|
|
8
8
|
import { type Cheerio } from 'cheerio';
|
|
9
9
|
import type { AnyNode } from 'domhandler';
|
|
10
10
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
11
11
|
import type { Page } from 'playwright';
|
|
12
|
-
import type { SetRequired } from 'type-fest';
|
|
13
12
|
import type { PlaywrightCrawlingContext, PlaywrightGotoOptions } from './playwright-crawler.js';
|
|
14
13
|
import { RenderingTypePredictor } from './utils/rendering-type-prediction.js';
|
|
15
14
|
interface AdaptivePlaywrightCrawlerStatisticState extends StatisticState {
|
|
@@ -21,7 +20,7 @@ declare class AdaptivePlaywrightCrawlerStatistics extends Statistics {
|
|
|
21
20
|
state: AdaptivePlaywrightCrawlerStatisticState;
|
|
22
21
|
constructor(options?: StatisticsOptions);
|
|
23
22
|
reset(): void;
|
|
24
|
-
protected
|
|
23
|
+
protected maybeLoadStatistics(): Promise<void>;
|
|
25
24
|
trackHttpOnlyRequestHandlerRun(): void;
|
|
26
25
|
trackBrowserRequestHandlerRun(): void;
|
|
27
26
|
trackRenderingTypeMisprediction(): void;
|
|
@@ -37,10 +36,15 @@ export interface AdaptivePlaywrightCrawlerContext<UserData extends Dictionary =
|
|
|
37
36
|
*/
|
|
38
37
|
page: Page;
|
|
39
38
|
/**
|
|
40
|
-
* Wait for an element matching the selector to appear and return a Cheerio object of matched
|
|
39
|
+
* Wait for an element matching the selector to appear and return a Cheerio object of the first matched element.
|
|
41
40
|
* Timeout defaults to 5s.
|
|
42
41
|
*/
|
|
43
42
|
querySelector(selector: string, timeoutMs?: number): Promise<Cheerio<AnyNode>>;
|
|
43
|
+
/**
|
|
44
|
+
* Wait for an element matching the selector to appear and return a Cheerio object of all matched elements.
|
|
45
|
+
* Timeout defaults to 5s.
|
|
46
|
+
*/
|
|
47
|
+
querySelectorAll(selector: string, timeoutMs?: number): Promise<Cheerio<AnyNode>>;
|
|
44
48
|
/**
|
|
45
49
|
* Wait for an element matching the selector to appear.
|
|
46
50
|
* Timeout defaults to 5s.
|
|
@@ -75,13 +79,11 @@ interface AdaptiveHookContext extends Pick<AdaptivePlaywrightCrawlerContext, 'id
|
|
|
75
79
|
request: Request;
|
|
76
80
|
gotoOptions?: PlaywrightGotoOptions;
|
|
77
81
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
interface AdaptivePostNavigationHook extends BrowserHook<Omit<AdaptiveHookContext, 'request'> & {
|
|
82
|
+
type AdaptiveHook<ContextExtension = Dictionary<never>> = BrowserHook<AdaptiveHookContext, ContextExtension>;
|
|
83
|
+
type AdaptivePostNavigationHook<ContextExtension = Dictionary<never>> = BrowserHook<Omit<AdaptiveHookContext, 'request'> & {
|
|
81
84
|
request: LoadedRequest<Request>;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export interface AdaptivePlaywrightCrawlerOptions<ExtendedContext extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext> extends Omit<BasicCrawlerOptions<AdaptivePlaywrightCrawlerContext, ExtendedContext>, 'preNavigationHooks' | 'postNavigationHooks'> {
|
|
85
|
+
}, ContextExtension>;
|
|
86
|
+
export interface AdaptivePlaywrightCrawlerOptions<ContextExtension = Dictionary<never>, ExtendedContext extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext & ContextExtension> extends Omit<BasicCrawlerOptions<AdaptivePlaywrightCrawlerContext, ContextExtension, ExtendedContext>, 'preNavigationHooks' | 'postNavigationHooks'> {
|
|
85
87
|
/**
|
|
86
88
|
* Async functions that are sequentially evaluated before the navigation. Good for setting additional cookies.
|
|
87
89
|
* The function accepts a subset of the crawling context. If you attempt to access the `page` property during HTTP-only crawling,
|
|
@@ -90,7 +92,7 @@ export interface AdaptivePlaywrightCrawlerOptions<ExtendedContext extends Adapti
|
|
|
90
92
|
* A hook may optionally return a partial object whose properties are merged into the crawling context,
|
|
91
93
|
* allowing the hook to override context members for subsequent hooks and pipeline stages.
|
|
92
94
|
*/
|
|
93
|
-
preNavigationHooks?: AdaptiveHook[];
|
|
95
|
+
preNavigationHooks?: AdaptiveHook<ContextExtension>[];
|
|
94
96
|
/**
|
|
95
97
|
* Async functions that are sequentially evaluated after the navigation. Good for checking if the navigation was successful.
|
|
96
98
|
* The function accepts a subset of the crawling context. If you attempt to access the `page` property during HTTP-only crawling,
|
|
@@ -99,7 +101,7 @@ export interface AdaptivePlaywrightCrawlerOptions<ExtendedContext extends Adapti
|
|
|
99
101
|
* A hook may optionally return a partial object whose properties are merged into the crawling context
|
|
100
102
|
* (e.g. to override `response` after solving a challenge).
|
|
101
103
|
*/
|
|
102
|
-
postNavigationHooks?: AdaptivePostNavigationHook[];
|
|
104
|
+
postNavigationHooks?: AdaptivePostNavigationHook<ContextExtension>[];
|
|
103
105
|
/**
|
|
104
106
|
* Specifies the frequency of rendering type detection checks - 0.1 means roughly 10% of requests.
|
|
105
107
|
* Defaults to 0.1 (so 10%).
|
|
@@ -130,6 +132,8 @@ export interface AdaptivePlaywrightCrawlerOptions<ExtendedContext extends Adapti
|
|
|
130
132
|
* If it returns 'inconclusive', the detection result won't be used.
|
|
131
133
|
* If no result comparator is specified, but there is a `resultChecker`, any site where the `resultChecker` returns true is considered static.
|
|
132
134
|
* If neither `resultComparator` nor `resultChecker` are specified, a deep comparison of returned dataset items is used as a default.
|
|
135
|
+
*
|
|
136
|
+
* For a stricter, ready-made comparator that also takes enqueued requests and key-value store changes into account, see {@link fullResultComparator}.
|
|
133
137
|
*/
|
|
134
138
|
resultComparator?: (resultA: RequestHandlerResult, resultB: RequestHandlerResult) => boolean | 'equal' | 'different' | 'inconclusive';
|
|
135
139
|
/**
|
|
@@ -171,7 +175,7 @@ export interface AdaptivePlaywrightCrawlerOptions<ExtendedContext extends Adapti
|
|
|
171
175
|
*
|
|
172
176
|
* @experimental
|
|
173
177
|
*/
|
|
174
|
-
export declare class AdaptivePlaywrightCrawler<ExtendedContext extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext> extends BasicCrawler<AdaptivePlaywrightCrawlerContext, ExtendedContext> {
|
|
178
|
+
export declare class AdaptivePlaywrightCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext & ContextExtension> extends BasicCrawler<AdaptivePlaywrightCrawlerContext, ContextExtension, ExtendedContext> {
|
|
175
179
|
private renderingTypePredictor;
|
|
176
180
|
private resultChecker;
|
|
177
181
|
private shouldPropagateError;
|
|
@@ -184,13 +188,14 @@ export declare class AdaptivePlaywrightCrawler<ExtendedContext extends AdaptiveP
|
|
|
184
188
|
private resultObjects;
|
|
185
189
|
private inFlightRenderingTypeDetections;
|
|
186
190
|
private teardownHooks;
|
|
187
|
-
constructor(options?: AdaptivePlaywrightCrawlerOptions<ExtendedContext>);
|
|
191
|
+
constructor(options?: AdaptivePlaywrightCrawlerOptions<ContextExtension, ExtendedContext>);
|
|
188
192
|
protected _init(): Promise<void>;
|
|
189
193
|
protected buildContextPipeline(): ContextPipeline<CrawlingContext<Dictionary>, CrawlingContext<Dictionary> & {
|
|
190
194
|
readonly request: LoadedRequest<Request<Dictionary>>;
|
|
191
195
|
readonly response: Response;
|
|
192
196
|
readonly page: Page;
|
|
193
197
|
readonly querySelector: AdaptivePlaywrightCrawlerContext["querySelector"];
|
|
198
|
+
readonly querySelectorAll: AdaptivePlaywrightCrawlerContext["querySelectorAll"];
|
|
194
199
|
readonly waitForSelector: AdaptivePlaywrightCrawlerContext["waitForSelector"];
|
|
195
200
|
readonly parseWithCheerio: AdaptivePlaywrightCrawlerContext["parseWithCheerio"];
|
|
196
201
|
}>;
|
|
@@ -198,19 +203,43 @@ export declare class AdaptivePlaywrightCrawler<ExtendedContext extends AdaptiveP
|
|
|
198
203
|
private adaptPlaywrightContext;
|
|
199
204
|
private crawlOne;
|
|
200
205
|
protected runRequestHandler(crawlingContext: CrawlingContext): Promise<void>;
|
|
201
|
-
|
|
202
|
-
|
|
206
|
+
private commitResult;
|
|
207
|
+
private allowStorageAccess;
|
|
203
208
|
/**
|
|
204
209
|
* Reading the pending request count queries the underlying request manager, which counts as storage access.
|
|
205
210
|
* Since this is internal crawler bookkeeping used to compute the `enqueueLinks` limit (not user-initiated storage
|
|
206
211
|
* access), it must be allowed even while a request handler runs inside the storage-access guard.
|
|
207
212
|
*/
|
|
208
213
|
protected getPendingRequestCountApproximation(): Promise<number>;
|
|
209
|
-
|
|
214
|
+
private enqueueLinks;
|
|
210
215
|
private createLogProxy;
|
|
211
216
|
teardown(): Promise<void>;
|
|
212
217
|
}
|
|
213
218
|
export declare function createAdaptivePlaywrightRouter<Context extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<Context['request']>>>(routes?: RouterRoutes<Context, Routes>): RouterHandler<Context, Routes>;
|
|
214
219
|
export declare function createAdaptivePlaywrightRouter<Context extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext, UserData extends Dictionary = GetUserDataFromRequest<Context['request']>>(routes?: RouterRoutes<Context, Record<string, UserData>>): RouterHandler<Context, Record<string, UserData>>;
|
|
215
220
|
export declare function createAdaptivePlaywrightRouter<Context extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext, const Schemas extends RouteSchemas = RouteSchemas>(schemas: Schemas): RouterHandler<Context, RoutesFromSchemas<Schemas>>;
|
|
221
|
+
/**
|
|
222
|
+
* An opt-in {@link AdaptivePlaywrightCrawlerOptions.resultComparator|`resultComparator`} that considers two
|
|
223
|
+
* request handler results equal only if *all* of their observable effects match - the pushed dataset items, the
|
|
224
|
+
* enqueued requests, and the key-value store changes. This is stricter than the default comparator, which only
|
|
225
|
+
* compares dataset items.
|
|
226
|
+
*
|
|
227
|
+
* **Beware:** enqueued URLs are compared exactly. The same page rendered in a browser and via plain HTTP often
|
|
228
|
+
* yields links that differ only in tracking query parameters, for example:
|
|
229
|
+
* - `https://sdk.apify.com/docs/guides/getting-started`
|
|
230
|
+
* - `https://sdk.apify.com/docs/guides/getting-started?__hsfp=1136113150&__hssc=7591405.1.173549427712`
|
|
231
|
+
*
|
|
232
|
+
* Such links are treated as *different*, which will make the crawler favor browser rendering for those pages.
|
|
233
|
+
*
|
|
234
|
+
* **Example usage:**
|
|
235
|
+
* ```ts
|
|
236
|
+
* const crawler = new AdaptivePlaywrightCrawler({
|
|
237
|
+
* resultComparator: fullResultComparator,
|
|
238
|
+
* async requestHandler({ pushData, enqueueLinks }) {
|
|
239
|
+
* // ...
|
|
240
|
+
* },
|
|
241
|
+
* });
|
|
242
|
+
* ```
|
|
243
|
+
*/
|
|
244
|
+
export declare function fullResultComparator(resultA: RequestHandlerResult, resultB: RequestHandlerResult): boolean;
|
|
216
245
|
export {};
|
|
@@ -19,8 +19,8 @@ class AdaptivePlaywrightCrawlerStatistics extends Statistics {
|
|
|
19
19
|
this.state.browserRequestHandlerRuns = 0;
|
|
20
20
|
this.state.renderingTypeMispredictions = 0;
|
|
21
21
|
}
|
|
22
|
-
async
|
|
23
|
-
await super.
|
|
22
|
+
async maybeLoadStatistics() {
|
|
23
|
+
await super.maybeLoadStatistics();
|
|
24
24
|
const savedState = await this.keyValueStore?.getValue(this.persistStateKey);
|
|
25
25
|
if (!savedState) {
|
|
26
26
|
return;
|
|
@@ -122,10 +122,14 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
122
122
|
}));
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
|
-
//
|
|
126
|
-
// `
|
|
127
|
-
//
|
|
128
|
-
//
|
|
125
|
+
// `extendContext` is forwarded to the inner crawlers, which run it *before* navigation (see
|
|
126
|
+
// `BasicCrawler`), keeping the behavior consistent with the non-adaptive crawlers: the
|
|
127
|
+
// extension is visible to the pre/post-navigation hooks and the request handler, but cannot
|
|
128
|
+
// access navigation-dependent members (`page`, `response`, `$`, ...).
|
|
129
|
+
//
|
|
130
|
+
// The adaptive hooks target a subset context (`AdaptiveHookContext`); the casts to the inner
|
|
131
|
+
// crawlers' `PlaywrightHook` type relax that nominal difference. The `ContextPipeline` merges
|
|
132
|
+
// each hook's overrides at runtime regardless of the static type.
|
|
129
133
|
const staticCrawler = new CheerioCrawler({
|
|
130
134
|
...rest,
|
|
131
135
|
statisticsOptions: {
|
|
@@ -133,6 +137,7 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
133
137
|
},
|
|
134
138
|
preNavigationHooks,
|
|
135
139
|
postNavigationHooks,
|
|
140
|
+
extendContext,
|
|
136
141
|
});
|
|
137
142
|
const browserCrawler = new PlaywrightCrawler({
|
|
138
143
|
...rest,
|
|
@@ -141,21 +146,14 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
141
146
|
},
|
|
142
147
|
preNavigationHooks: preNavigationHooks,
|
|
143
148
|
postNavigationHooks: postNavigationHooks,
|
|
149
|
+
extendContext,
|
|
144
150
|
});
|
|
145
151
|
this.teardownHooks.push(browserCrawler.teardown.bind(browserCrawler));
|
|
146
|
-
this.staticContextPipeline = staticCrawler.contextPipeline
|
|
147
|
-
.compose({
|
|
152
|
+
this.staticContextPipeline = staticCrawler.contextPipeline.compose({
|
|
148
153
|
action: this.adaptCheerioContext.bind(this),
|
|
149
|
-
})
|
|
150
|
-
.compose({
|
|
151
|
-
action: async (context) => extendContext ? await extendContext(context) : context,
|
|
152
154
|
});
|
|
153
|
-
this.browserContextPipeline = browserCrawler.contextPipeline
|
|
154
|
-
.compose({
|
|
155
|
+
this.browserContextPipeline = browserCrawler.contextPipeline.compose({
|
|
155
156
|
action: this.adaptPlaywrightContext.bind(this),
|
|
156
|
-
})
|
|
157
|
-
.compose({
|
|
158
|
-
action: async (context) => extendContext ? await extendContext(context) : context,
|
|
159
157
|
});
|
|
160
158
|
this.stats = new AdaptivePlaywrightCrawlerStatistics({
|
|
161
159
|
logMessage: `${this.log.getOptions().prefix} request statistics:`,
|
|
@@ -183,6 +181,9 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
183
181
|
get querySelector() {
|
|
184
182
|
throw new Error(errorMessage('querySelector'));
|
|
185
183
|
},
|
|
184
|
+
get querySelectorAll() {
|
|
185
|
+
throw new Error(errorMessage('querySelectorAll'));
|
|
186
|
+
},
|
|
186
187
|
get waitForSelector() {
|
|
187
188
|
throw new Error(errorMessage('waitForSelector'));
|
|
188
189
|
},
|
|
@@ -203,6 +204,9 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
203
204
|
throw new Error('Page object was used in HTTP-only request handler');
|
|
204
205
|
},
|
|
205
206
|
async querySelector(selector) {
|
|
207
|
+
return cheerioContext.$(selector).first();
|
|
208
|
+
},
|
|
209
|
+
async querySelectorAll(selector) {
|
|
206
210
|
return cheerioContext.$(selector);
|
|
207
211
|
},
|
|
208
212
|
enqueueLinks: async (options = {}) => {
|
|
@@ -226,6 +230,12 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
226
230
|
statusText: originalResponse.statusText(),
|
|
227
231
|
}),
|
|
228
232
|
async querySelector(selector, timeoutMs = 5000) {
|
|
233
|
+
const locator = playwrightContext.page.locator(selector).first();
|
|
234
|
+
await locator.waitFor({ timeout: timeoutMs, state: 'attached' });
|
|
235
|
+
const $ = await playwrightContext.parseWithCheerio();
|
|
236
|
+
return $(selector).first();
|
|
237
|
+
},
|
|
238
|
+
async querySelectorAll(selector, timeoutMs = 5000) {
|
|
229
239
|
const locator = playwrightContext.page.locator(selector).first();
|
|
230
240
|
await locator.waitFor({ timeout: timeoutMs, state: 'attached' });
|
|
231
241
|
const $ = await playwrightContext.parseWithCheerio();
|
|
@@ -449,3 +459,32 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
|
|
|
449
459
|
export function createAdaptivePlaywrightRouter(routesOrSchemas) {
|
|
450
460
|
return Router.create(routesOrSchemas);
|
|
451
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* An opt-in {@link AdaptivePlaywrightCrawlerOptions.resultComparator|`resultComparator`} that considers two
|
|
464
|
+
* request handler results equal only if *all* of their observable effects match - the pushed dataset items, the
|
|
465
|
+
* enqueued requests, and the key-value store changes. This is stricter than the default comparator, which only
|
|
466
|
+
* compares dataset items.
|
|
467
|
+
*
|
|
468
|
+
* **Beware:** enqueued URLs are compared exactly. The same page rendered in a browser and via plain HTTP often
|
|
469
|
+
* yields links that differ only in tracking query parameters, for example:
|
|
470
|
+
* - `https://sdk.apify.com/docs/guides/getting-started`
|
|
471
|
+
* - `https://sdk.apify.com/docs/guides/getting-started?__hsfp=1136113150&__hssc=7591405.1.173549427712`
|
|
472
|
+
*
|
|
473
|
+
* Such links are treated as *different*, which will make the crawler favor browser rendering for those pages.
|
|
474
|
+
*
|
|
475
|
+
* **Example usage:**
|
|
476
|
+
* ```ts
|
|
477
|
+
* const crawler = new AdaptivePlaywrightCrawler({
|
|
478
|
+
* resultComparator: fullResultComparator,
|
|
479
|
+
* async requestHandler({ pushData, enqueueLinks }) {
|
|
480
|
+
* // ...
|
|
481
|
+
* },
|
|
482
|
+
* });
|
|
483
|
+
* ```
|
|
484
|
+
*/
|
|
485
|
+
export function fullResultComparator(resultA, resultB) {
|
|
486
|
+
return (isDeepStrictEqual(resultA.datasetItems, resultB.datasetItems) &&
|
|
487
|
+
isDeepStrictEqual(resultA.enqueuedUrls, resultB.enqueuedUrls) &&
|
|
488
|
+
isDeepStrictEqual(resultA.enqueuedUrlLists, resultB.enqueuedUrlLists) &&
|
|
489
|
+
isDeepStrictEqual(resultA.keyValueStoreChanges, resultB.keyValueStoreChanges));
|
|
490
|
+
}
|
|
@@ -59,7 +59,7 @@ export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>,
|
|
|
59
59
|
* ]
|
|
60
60
|
* ```
|
|
61
61
|
*/
|
|
62
|
-
preNavigationHooks?:
|
|
62
|
+
preNavigationHooks?: BrowserHook<PlaywrightCrawlingContext, ContextExtension>[];
|
|
63
63
|
/**
|
|
64
64
|
* Async functions that are sequentially evaluated after the navigation. Good for checking if the navigation was successful.
|
|
65
65
|
* The function accepts `crawlingContext` as the only parameter. A hook may optionally return a partial object
|
|
@@ -76,7 +76,7 @@ export interface PlaywrightCrawlerOptions<ContextExtension = Dictionary<never>,
|
|
|
76
76
|
* ]
|
|
77
77
|
* ```
|
|
78
78
|
*/
|
|
79
|
-
postNavigationHooks?:
|
|
79
|
+
postNavigationHooks?: BrowserHook<PlaywrightCrawlingContext, ContextExtension>[];
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
82
|
* Provides a simple framework for parallel crawling of web pages
|
|
@@ -243,7 +243,7 @@ export declare class PlaywrightCrawler<ContextExtension = Dictionary<never>, Ext
|
|
|
243
243
|
/**
|
|
244
244
|
* All `PlaywrightCrawler` parameters are passed via an options object.
|
|
245
245
|
*/
|
|
246
|
-
constructor(options?: PlaywrightCrawlerOptions<ExtendedContext>);
|
|
246
|
+
constructor(options?: PlaywrightCrawlerOptions<ContextExtension, ExtendedContext>);
|
|
247
247
|
// @ts-ignore optional peer dependency or compatibility with es2022
|
|
248
248
|
protected buildContextPipeline(): import("@crawlee/browser").ContextPipeline<import("@crawlee/browser").CrawlingContext<Dictionary>, BrowserCrawlingContext<Page, Response, Dictionary, Dictionary> & {
|
|
249
249
|
injectFile: (filePath: string, options?: InjectFileOptions) => Promise<unknown>;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { RecoverableStatePersistenceOptions, Request } from '@crawlee/core';
|
|
2
2
|
export type RenderingType = 'clientOnly' | 'static';
|
|
3
|
-
type URLComponents = string[];
|
|
4
|
-
type FeatureVector = [staticResultsSimilarity: number, clientOnlyResultsSimilarity: number];
|
|
5
3
|
export interface RenderingTypePredictorOptions {
|
|
6
4
|
/** A number between 0 and 1 that determines the desired ratio of rendering type detections */
|
|
7
5
|
detectionRatio: number;
|
|
@@ -32,7 +30,6 @@ export declare class RenderingTypePredictor {
|
|
|
32
30
|
*/
|
|
33
31
|
storeResult(requests: Request | Request[], renderingType: RenderingType): void;
|
|
34
32
|
private resultCount;
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
private calculateFeatureVector;
|
|
34
|
+
private retrain;
|
|
37
35
|
}
|
|
38
|
-
export {};
|
|
@@ -10,10 +10,17 @@ const calculateUrlSimilarity = (a, b) => {
|
|
|
10
10
|
if (a[0] !== b[0]) {
|
|
11
11
|
return 0;
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
const maxLength = Math.max(a.length, b.length);
|
|
14
|
+
// Only the hostname is present (no path components to compare) - the hosts already match.
|
|
15
|
+
if (maxLength <= 1) {
|
|
16
|
+
return 1;
|
|
17
|
+
}
|
|
18
|
+
for (let i = 1; i < maxLength; i++) {
|
|
14
19
|
values.push(stringComparison.jaroWinkler.similarity(a[i] ?? '', b[i] ?? '') > 0.8 ? 1 : 0);
|
|
15
20
|
}
|
|
16
|
-
|
|
21
|
+
// The first component (index 0, the hostname) is excluded from the comparison above,
|
|
22
|
+
// so it must also be excluded from the denominator of the weighted average.
|
|
23
|
+
return sum(values) / (maxLength - 1);
|
|
17
24
|
};
|
|
18
25
|
const sum = (values) => values.reduce((acc, value) => acc + value);
|
|
19
26
|
const mean = (values) => (values.length > 0 ? sum(values) / values.length : undefined);
|
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.82",
|
|
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.3.2",
|
|
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.82",
|
|
53
|
+
"@crawlee/browser": "4.0.0-beta.82",
|
|
54
|
+
"@crawlee/browser-pool": "4.0.0-beta.82",
|
|
55
|
+
"@crawlee/cheerio": "4.0.0-beta.82",
|
|
56
|
+
"@crawlee/core": "4.0.0-beta.82",
|
|
57
|
+
"@crawlee/types": "4.0.0-beta.82",
|
|
58
|
+
"@crawlee/utils": "4.0.0-beta.82",
|
|
59
59
|
"cheerio": "^1.0.0",
|
|
60
60
|
"idcac-playwright": "^0.1.3",
|
|
61
61
|
"jquery": "^3.7.1",
|
|
@@ -85,5 +85,5 @@
|
|
|
85
85
|
}
|
|
86
86
|
}
|
|
87
87
|
},
|
|
88
|
-
"gitHead": "
|
|
88
|
+
"gitHead": "eb1096f7c7743d124375ef011fbbadb19476822e"
|
|
89
89
|
}
|