@crawlee/playwright 4.0.0-beta.105 → 4.0.0-beta.106

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.
@@ -174,23 +174,10 @@ export interface AdaptivePlaywrightCrawlerOptions<ContextExtension = Dictionary<
174
174
  * @experimental
175
175
  */
176
176
  export declare class AdaptivePlaywrightCrawler<ContextExtension = Dictionary<never>, ExtendedContext extends AdaptivePlaywrightCrawlerContext = AdaptivePlaywrightCrawlerContext & ContextExtension, Routes extends Record<keyof Routes, Dictionary> = Record<string, GetUserDataFromRequest<AdaptivePlaywrightCrawlerContext['request']>>> extends BasicCrawler<AdaptivePlaywrightCrawlerContext, ContextExtension, ExtendedContext, Routes> {
177
- private renderingTypePredictor;
178
- private resultChecker;
179
- private shouldPropagateError;
180
- private resultComparator;
181
- private staticContextPipeline;
182
- private browserContextPipeline;
183
- private individualRequestHandlerTimeoutMillis;
177
+ #private;
184
178
  get stats(): AdaptivePlaywrightCrawlerStatistics;
185
- private inFlightRenderingTypeDetections;
186
- /**
187
- * The write policy of the per-attempt transactions. Defaults the request queue to `deferred`:
188
- * a discarded attempt's enqueues must never reach the queue.
189
- */
190
- private readonly attemptWritePolicy;
191
- private teardownHooks;
192
179
  constructor(options?: AdaptivePlaywrightCrawlerOptions<ContextExtension, ExtendedContext, Routes>);
193
- protected _init(): Promise<void>;
180
+ protected init(): Promise<void>;
194
181
  protected buildContextPipeline(): ContextPipeline<CrawlingContext<Dictionary>, CrawlingContext<Dictionary> & {
195
182
  readonly request: LoadedRequest<Request<Dictionary>>;
196
183
  readonly response: Response;
@@ -83,24 +83,23 @@ const proxyLogMethods = [
83
83
  * @experimental
84
84
  */
85
85
  export class AdaptivePlaywrightCrawler extends BasicCrawler {
86
- renderingTypePredictor;
87
- resultChecker;
88
- shouldPropagateError;
89
- resultComparator;
90
- staticContextPipeline;
91
- browserContextPipeline;
92
- individualRequestHandlerTimeoutMillis;
86
+ #renderingTypePredictor;
87
+ #resultChecker;
88
+ #shouldPropagateError;
89
+ #resultComparator;
90
+ #staticContextPipeline;
91
+ #browserContextPipeline;
92
+ #individualRequestHandlerTimeoutMillis;
93
93
  // The constructor always injects an `AdaptivePlaywrightCrawlerStatistics`, so narrowing the cast is sound.
94
94
  get stats() {
95
95
  return super.stats;
96
96
  }
97
- inFlightRenderingTypeDetections = 0;
98
97
  /**
99
98
  * The write policy of the per-attempt transactions. Defaults the request queue to `deferred`:
100
99
  * a discarded attempt's enqueues must never reach the queue.
101
100
  */
102
- attemptWritePolicy;
103
- teardownHooks = [];
101
+ #attemptWritePolicy;
102
+ #teardownHooks = [];
104
103
  constructor(options = {}) {
105
104
  const { requestHandler, renderingTypeDetectionRatio = 0.1, renderingTypePredictor, resultChecker, shouldPropagateError, resultComparator, statistics, requestHandlerTimeoutSecs = 60, errorHandler, failedRequestHandler, preNavigationHooks = [], postNavigationHooks = [], extendContext, contextPipelineBuilder, transactionalStorage, ...rest } = options;
106
105
  // The user's value is replaced by `false` in the `super` call below — validate it separately.
@@ -134,24 +133,24 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
134
133
  // user-facing option (validated above) to those.
135
134
  transactionalStorage: false,
136
135
  });
137
- this.individualRequestHandlerTimeoutMillis = requestHandlerTimeoutSecs * 1000;
136
+ this.#individualRequestHandlerTimeoutMillis = requestHandlerTimeoutSecs * 1000;
138
137
  // `renderingTypeDetectionRatio` only configures the default predictor - an injected one brings its own
139
138
  // detection ratio (and its own state), so the option is ignored in that case.
140
- this.renderingTypePredictor = OwnedOrInjected.resolve(renderingTypePredictor, () => new RenderingTypePredictor({ detectionRatio: renderingTypeDetectionRatio }));
141
- this.attemptWritePolicy = {
139
+ this.#renderingTypePredictor = OwnedOrInjected.resolve(renderingTypePredictor, () => new RenderingTypePredictor({ detectionRatio: renderingTypeDetectionRatio }));
140
+ this.#attemptWritePolicy = {
142
141
  requestQueue: 'deferred',
143
142
  ...(typeof transactionalStorage === 'object' ? transactionalStorage : {}),
144
143
  };
145
- this.resultChecker = resultChecker ?? (() => true);
146
- this.shouldPropagateError = shouldPropagateError ?? (() => false);
144
+ this.#resultChecker = resultChecker ?? (() => true);
145
+ this.#shouldPropagateError = shouldPropagateError ?? (() => false);
147
146
  if (resultComparator !== undefined) {
148
- this.resultComparator = resultComparator;
147
+ this.#resultComparator = resultComparator;
149
148
  }
150
149
  else if (resultChecker !== undefined) {
151
- this.resultComparator = (resultA, resultB) => this.resultChecker(resultA) && this.resultChecker(resultB);
150
+ this.#resultComparator = (resultA, resultB) => this.#resultChecker(resultA) && this.#resultChecker(resultB);
152
151
  }
153
152
  else {
154
- this.resultComparator = (resultA, resultB) => {
153
+ this.#resultComparator = (resultA, resultB) => {
155
154
  return (resultA.datasetItems.length === resultB.datasetItems.length &&
156
155
  resultA.datasetItems.every((itemA, i) => {
157
156
  const itemB = resultB.datasetItems[i];
@@ -181,19 +180,19 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
181
180
  postNavigationHooks: postNavigationHooks,
182
181
  extendContext,
183
182
  });
184
- this.teardownHooks.push(browserCrawler.teardown.bind(browserCrawler));
185
- this.staticContextPipeline = staticCrawler.contextPipeline.compose({
183
+ this.#teardownHooks.push(browserCrawler.teardown.bind(browserCrawler));
184
+ this.#staticContextPipeline = staticCrawler.contextPipeline.compose({
186
185
  action: this.adaptCheerioContext.bind(this),
187
186
  });
188
- this.browserContextPipeline = browserCrawler.contextPipeline.compose({
187
+ this.#browserContextPipeline = browserCrawler.contextPipeline.compose({
189
188
  action: this.adaptPlaywrightContext.bind(this),
190
189
  });
191
190
  }
192
- async _init() {
191
+ async init() {
193
192
  // Only the predictor we built ourselves is ours to initialize - an injected one is borrowed, so its
194
193
  // lifecycle (including restoring persisted state) stays with whoever created it.
195
- await this.renderingTypePredictor.ifOwned((predictor) => predictor.initialize());
196
- return await super._init();
194
+ await this.#renderingTypePredictor.ifOwned((predictor) => predictor.initialize());
195
+ return await super.init();
197
196
  }
198
197
  buildContextPipeline() {
199
198
  const errorMessage = (prop) => `The \`${prop}\` property is not available on the outer context pipeline of AdaptivePlaywrightCrawler - it is provided by the inner (static/browser) pipelines`;
@@ -289,7 +288,7 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
289
288
  */
290
289
  async crawlOne(renderingType, context, useStateFunction, transactions) {
291
290
  const transaction = createStorageTransaction({
292
- policy: this.attemptWritePolicy,
291
+ policy: this.#attemptWritePolicy,
293
292
  commitTimeoutMillis: this.internalTimeoutMillis,
294
293
  });
295
294
  transactions.push(transaction);
@@ -309,16 +308,16 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
309
308
  try {
310
309
  const callAdaptiveRequestHandler = async () => {
311
310
  if (renderingType === 'static') {
312
- await this.staticContextPipeline.call(subCrawlerContext, this.requestHandler.bind(this));
311
+ await this.#staticContextPipeline.call(subCrawlerContext, this.requestHandler.bind(this));
313
312
  }
314
313
  else if (renderingType === 'clientOnly') {
315
- await this.browserContextPipeline.call(subCrawlerContext, this.requestHandler.bind(this));
314
+ await this.#browserContextPipeline.call(subCrawlerContext, this.requestHandler.bind(this));
316
315
  }
317
316
  };
318
317
  // this crawler overrides `runRequestHandler` and times each rendering-type run itself, so it has
319
318
  // to resolve any per-route override too - otherwise routes would be silently ignored here
320
319
  const routeTimeoutSecs = this.requestHandler.getTimeoutSecs?.(context.request.label);
321
- const timeoutMillis = routeTimeoutSecs === undefined ? this.individualRequestHandlerTimeoutMillis : routeTimeoutSecs * 1000;
320
+ const timeoutMillis = routeTimeoutSecs === undefined ? this.#individualRequestHandlerTimeoutMillis : routeTimeoutSecs * 1000;
322
321
  await addTimeoutToPromise(async () => transaction.run(callAdaptiveRequestHandler), timeoutMillis, 'Request handler timed out');
323
322
  return { result: transaction, ok: true, logs };
324
323
  }
@@ -330,14 +329,11 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
330
329
  }
331
330
  }
332
331
  async runRequestHandler(crawlingContext) {
333
- const renderingTypePrediction = this.renderingTypePredictor.value.predict(crawlingContext.request);
332
+ const renderingTypePrediction = this.#renderingTypePredictor.value.predict(crawlingContext.request);
334
333
  const shouldDetectRenderingType = Math.random() < renderingTypePrediction.detectionProbabilityRecommendation;
335
334
  if (!shouldDetectRenderingType) {
336
335
  crawlingContext.log.debug(`Predicted rendering type ${renderingTypePrediction.renderingType} for ${crawlingContext.request.url}`);
337
336
  }
338
- if (shouldDetectRenderingType) {
339
- this.inFlightRenderingTypeDetections += 1;
340
- }
341
337
  // Every transaction created for this request - up to two, since the static-then-browser
342
338
  // fall-through and the browser-then-detection pair are mutually exclusive. Disposed in the
343
339
  // `finally` below, not earlier: the comparators read the journals after `crawlOne` returns.
@@ -347,7 +343,7 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
347
343
  crawlingContext.log.debug(`Running HTTP-only request handler for ${crawlingContext.request.url}`);
348
344
  this.stats.trackHttpOnlyRequestHandlerRun();
349
345
  const plainHTTPRun = await this.crawlOne('static', crawlingContext, crawlingContext.useState, transactions);
350
- if (plainHTTPRun.ok && this.resultChecker(plainHTTPRun.result)) {
346
+ if (plainHTTPRun.ok && this.#resultChecker(plainHTTPRun.result)) {
351
347
  crawlingContext.log.debug(`HTTP-only request handler succeeded for ${crawlingContext.request.url}`);
352
348
  plainHTTPRun.logs?.forEach(([log, method, ...args]) => log[method](...args));
353
349
  await plainHTTPRun.result.commit();
@@ -358,7 +354,7 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
358
354
  const actualError = plainHTTPRun.error instanceof RequestHandlerError
359
355
  ? plainHTTPRun.error.cause
360
356
  : plainHTTPRun.error;
361
- if (await this.shouldPropagateError(actualError, crawlingContext)) {
357
+ if (await this.#shouldPropagateError(actualError, crawlingContext)) {
362
358
  throw actualError;
363
359
  }
364
360
  crawlingContext.log.exception(actualError, `HTTP-only request handler failed for ${crawlingContext.request.url}`);
@@ -405,7 +401,7 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
405
401
  if (!plainHTTPRun.ok) {
406
402
  return 'clientOnly';
407
403
  }
408
- const comparisonResult = this.resultComparator(plainHTTPRun.result, browserRun.result);
404
+ const comparisonResult = this.#resultComparator(plainHTTPRun.result, browserRun.result);
409
405
  if (comparisonResult === true || comparisonResult === 'equal') {
410
406
  return 'static';
411
407
  }
@@ -416,14 +412,11 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
416
412
  })();
417
413
  crawlingContext.log.debug(`Detected rendering type ${detectionResult} for ${crawlingContext.request.url}`);
418
414
  if (detectionResult !== undefined) {
419
- this.renderingTypePredictor.value.storeResult(crawlingContext.request, detectionResult);
415
+ this.#renderingTypePredictor.value.storeResult(crawlingContext.request, detectionResult);
420
416
  }
421
417
  }
422
418
  }
423
419
  finally {
424
- if (shouldDetectRenderingType) {
425
- this.inFlightRenderingTypeDetections -= 1;
426
- }
427
420
  // A still-open transaction here belongs to a discarded attempt - roll it back, then release.
428
421
  for (const transaction of transactions) {
429
422
  transaction.rollback();
@@ -456,7 +449,7 @@ export class AdaptivePlaywrightCrawler extends BasicCrawler {
456
449
  }
457
450
  async teardown() {
458
451
  await super.teardown();
459
- for (const hook of this.teardownHooks) {
452
+ for (const hook of this.#teardownHooks) {
460
453
  await hook();
461
454
  }
462
455
  }
@@ -264,7 +264,7 @@ export declare class PlaywrightCrawler<ContextExtension = Dictionary<never>, Ext
264
264
  closeCookieModals: () => Promise<void>;
265
265
  handleCloudflareChallenge: (options?: HandleCloudflareChallengeOptions) => Promise<Response | undefined>;
266
266
  }>;
267
- protected _navigationHandler(crawlingContext: PlaywrightCrawlingContext, gotoOptions: DirectNavigationOptions): Promise<Response | null>;
267
+ protected navigationHandler(crawlingContext: PlaywrightCrawlingContext, gotoOptions: DirectNavigationOptions): Promise<Response | null>;
268
268
  private enhanceContext;
269
269
  }
270
270
  /**
@@ -109,7 +109,7 @@ export class PlaywrightCrawler extends BrowserCrawler {
109
109
  buildContextPipeline() {
110
110
  return super.buildContextPipeline().compose({ action: this.enhanceContext.bind(this) });
111
111
  }
112
- async _navigationHandler(crawlingContext, gotoOptions) {
112
+ async navigationHandler(crawlingContext, gotoOptions) {
113
113
  return gotoExtended(crawlingContext.page, crawlingContext.request, gotoOptions);
114
114
  }
115
115
  async enhanceContext(context) {
@@ -26,7 +26,7 @@ export interface IRenderingTypePredictor {
26
26
  * @experimental
27
27
  */
28
28
  export declare class RenderingTypePredictor implements IRenderingTypePredictor {
29
- private detectionRatio;
29
+ #private;
30
30
  private state;
31
31
  constructor({ detectionRatio, persistenceOptions }: RenderingTypePredictorOptions);
32
32
  /**
@@ -30,10 +30,11 @@ const mean = (values) => (values.length > 0 ? sum(values) / values.length : unde
30
30
  * @experimental
31
31
  */
32
32
  export class RenderingTypePredictor {
33
- detectionRatio;
33
+ #detectionRatio;
34
+ // kept as TS-private: tests reach for it at runtime
34
35
  state;
35
36
  constructor({ detectionRatio, persistenceOptions }) {
36
- this.detectionRatio = detectionRatio;
37
+ this.#detectionRatio = detectionRatio;
37
38
  this.state = new RecoverableState({
38
39
  defaultState: {
39
40
  logreg: new LogisticRegression({ numSteps: 1000, learningRate: 0.05 }),
@@ -86,7 +87,7 @@ export class RenderingTypePredictor {
86
87
  renderingType: prediction === 1 ? 'static' : 'clientOnly',
87
88
  detectionProbabilityRecommendation: Math.abs(scores[0] - scores[1]) < 0.1
88
89
  ? 1
89
- : this.detectionRatio * Math.max(1, 5 - this.resultCount(label)),
90
+ : this.#detectionRatio * Math.max(1, 5 - this.resultCount(label)),
90
91
  };
91
92
  }
92
93
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crawlee/playwright",
3
- "version": "4.0.0-beta.105",
3
+ "version": "4.0.0-beta.106",
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,15 +49,14 @@
49
49
  "dependencies": {
50
50
  "@apify/datastructures": "^2.0.3",
51
51
  "@apify/timeout": "^0.4.4",
52
- "@crawlee/basic": "4.0.0-beta.105",
53
- "@crawlee/browser": "4.0.0-beta.105",
54
- "@crawlee/browser-pool": "4.0.0-beta.105",
55
- "@crawlee/cheerio": "4.0.0-beta.105",
56
- "@crawlee/core": "4.0.0-beta.105",
57
- "@crawlee/types": "4.0.0-beta.105",
58
- "@crawlee/utils": "4.0.0-beta.105",
52
+ "@crawlee/basic": "4.0.0-beta.106",
53
+ "@crawlee/browser": "4.0.0-beta.106",
54
+ "@crawlee/browser-pool": "4.0.0-beta.106",
55
+ "@crawlee/cheerio": "4.0.0-beta.106",
56
+ "@crawlee/core": "4.0.0-beta.106",
57
+ "@crawlee/types": "4.0.0-beta.106",
58
+ "@crawlee/utils": "4.0.0-beta.106",
59
59
  "cheerio": "^1.0.0",
60
- "idcac-playwright": "^0.1.3",
61
60
  "jquery": "^3.7.1",
62
61
  "ml-logistic-regression": "^2.0.0",
63
62
  "ml-matrix": "^6.12.1",
@@ -85,5 +84,5 @@
85
84
  }
86
85
  }
87
86
  },
88
- "gitHead": "26073a822c7699ac487931383a39192bc3daae7a"
87
+ "gitHead": "c622f1fc65e65221ea245817c58ecc0ffb4a5cb0"
89
88
  }