@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.
@@ -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, RestrictedCrawlingContext, RouterRoutes, StatisticsOptions, StatisticState } from '@crawlee/core';
4
+ import type { ContextPipeline, CrawlingContext, EnqueueLinksOptions, GetUserDataFromRequest, RouterRoutes, StatisticsOptions, StatisticState } from '@crawlee/core';
5
5
  import { RequestHandlerResult, Statistics } from '@crawlee/core';
6
- import type { BatchAddRequestsResult, Dictionary, Awaitable } from '@crawlee/types';
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 _maybeLoadStatistics(): Promise<void>;
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 elements.
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
- interface AdaptiveHook extends BrowserHook<AdaptiveHookContext> {
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
- protected commitResult(crawlingContext: CrawlingContext, { calls, keyValueStoreChanges }: RequestHandlerResult): Promise<void>;
202
- protected allowStorageAccess<R, TArgs extends any[]>(func: (...args: TArgs) => Promise<R>): (...args: TArgs) => Promise<R>;
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
- protected enqueueLinks(options: SetRequired<EnqueueLinksOptions, 'urls'>, request: RestrictedCrawlingContext['request'], result: RequestHandlerResult): Promise<BatchAddRequestsResult>;
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 _maybeLoadStatistics() {
23
- await super._maybeLoadStatistics();
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
- // Each adaptive hook is registered as its own static/browser hook so the underlying
126
- // `ContextPipeline` handles override merging between hooks for free. The hook signatures
127
- // are structurally compatible with the underlying crawlers' contexts (subset of fields);
128
- // the casts just relax the nominal type difference.
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?: PlaywrightHook[];
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?: PlaywrightHook[];
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
- protected calculateFeatureVector(url: URLComponents, label: string | undefined): FeatureVector;
36
- protected retrain(): void;
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
- for (let i = 1; i < Math.max(a.length, b.length); i++) {
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
- return sum(values) / Math.max(a.length, b.length);
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.80",
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.80",
53
- "@crawlee/browser": "4.0.0-beta.80",
54
- "@crawlee/browser-pool": "4.0.0-beta.80",
55
- "@crawlee/cheerio": "4.0.0-beta.80",
56
- "@crawlee/core": "4.0.0-beta.80",
57
- "@crawlee/types": "4.0.0-beta.80",
58
- "@crawlee/utils": "4.0.0-beta.80",
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": "96c57b4a0c999e4b2bd198792490af28db7aa42d"
88
+ "gitHead": "eb1096f7c7743d124375ef011fbbadb19476822e"
89
89
  }