@crawlee/puppeteer 3.0.0-alpha.0 → 3.0.0-alpha.3

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.
Files changed (38) hide show
  1. package/dist/LICENSE.md +201 -0
  2. package/{README.md → dist/README.md} +0 -0
  3. package/dist/index.d.ts +12 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +12 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/index.mjs +76 -0
  8. package/dist/internals/enqueue-links/click-elements.d.ts +188 -0
  9. package/dist/internals/enqueue-links/click-elements.d.ts.map +1 -0
  10. package/dist/internals/enqueue-links/click-elements.js +336 -0
  11. package/dist/internals/enqueue-links/click-elements.js.map +1 -0
  12. package/dist/internals/puppeteer-crawler.d.ts +149 -0
  13. package/dist/internals/puppeteer-crawler.d.ts.map +1 -0
  14. package/dist/internals/puppeteer-crawler.js +117 -0
  15. package/dist/internals/puppeteer-crawler.js.map +1 -0
  16. package/dist/internals/puppeteer-launcher.d.ts +134 -0
  17. package/dist/internals/puppeteer-launcher.d.ts.map +1 -0
  18. package/dist/internals/puppeteer-launcher.js +146 -0
  19. package/dist/internals/puppeteer-launcher.js.map +1 -0
  20. package/dist/internals/stealth/hiding_tricks.d.ts +10 -0
  21. package/dist/internals/stealth/hiding_tricks.d.ts.map +1 -0
  22. package/dist/internals/stealth/hiding_tricks.js +334 -0
  23. package/dist/internals/stealth/hiding_tricks.js.map +1 -0
  24. package/dist/internals/stealth/index.d.ts +40 -0
  25. package/dist/internals/stealth/index.d.ts.map +1 -0
  26. package/dist/internals/stealth/index.js +108 -0
  27. package/dist/internals/stealth/index.js.map +1 -0
  28. package/dist/internals/utils/puppeteer_request_interception.d.ts +60 -0
  29. package/dist/internals/utils/puppeteer_request_interception.d.ts.map +1 -0
  30. package/dist/internals/utils/puppeteer_request_interception.js +225 -0
  31. package/dist/internals/utils/puppeteer_request_interception.js.map +1 -0
  32. package/dist/internals/utils/puppeteer_utils.d.ts +298 -0
  33. package/dist/internals/utils/puppeteer_utils.d.ts.map +1 -0
  34. package/dist/internals/utils/puppeteer_utils.js +468 -0
  35. package/dist/internals/utils/puppeteer_utils.js.map +1 -0
  36. package/dist/package.json +66 -0
  37. package/dist/tsconfig.build.tsbuildinfo +1 -0
  38. package/package.json +8 -7
@@ -0,0 +1,336 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clickElements = exports.isTargetRelevant = exports.clickElementsAndInterceptNavigationRequests = exports.enqueueLinksByClickingElements = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const browser_1 = require("@crawlee/browser");
6
+ const log_1 = tslib_1.__importDefault(require("@apify/log"));
7
+ const ow_1 = tslib_1.__importDefault(require("ow"));
8
+ const url_1 = require("url");
9
+ const puppeteer_request_interception_1 = require("../utils/puppeteer_request_interception");
10
+ const STARTING_Z_INDEX = 2147400000;
11
+ const log = log_1.default.child({ prefix: 'Puppeteer Click Elements' });
12
+ /**
13
+ * The function finds elements matching a specific CSS selector in a Puppeteer page,
14
+ * clicks all those elements using a mouse move and a left mouse button click and intercepts
15
+ * all the navigation requests that are subsequently produced by the page. The intercepted
16
+ * requests, including their methods, headers and payloads are then enqueued to a provided
17
+ * {@link RequestQueue}. This is useful to crawl JavaScript heavy pages where links are not available
18
+ * in `href` elements, but rather navigations are triggered in click handlers.
19
+ * If you're looking to find URLs in `href` attributes of the page, see {@link enqueueLinks}.
20
+ *
21
+ * Optionally, the function allows you to filter the target links' URLs using an array of {@link PseudoUrl} objects
22
+ * and override settings of the enqueued {@link Request} objects.
23
+ *
24
+ * **IMPORTANT**: To be able to do this, this function uses various mutations on the page,
25
+ * such as changing the Z-index of elements being clicked and their visibility. Therefore,
26
+ * it is recommended to only use this function as the last operation in the page.
27
+ *
28
+ * **USING HEADFUL BROWSER**: When using a headful browser, this function will only be able to click elements
29
+ * in the focused tab, effectively limiting concurrency to 1. In headless mode, full concurrency can be achieved.
30
+ *
31
+ * **PERFORMANCE**: Clicking elements with a mouse and intercepting requests is not a low level operation
32
+ * that takes nanoseconds. It's not very CPU intensive, but it takes time. We strongly recommend limiting
33
+ * the scope of the clicking as much as possible by using a specific selector that targets only the elements
34
+ * that you assume or know will produce a navigation. You can certainly click everything by using
35
+ * the `*` selector, but be prepared to wait minutes to get results on a large and complex page.
36
+ *
37
+ * **Example usage**
38
+ *
39
+ * ```javascript
40
+ * await Actor.utils.puppeteer.enqueueLinksByClickingElements({
41
+ * page,
42
+ * requestQueue,
43
+ * selector: 'a.product-detail',
44
+ * pseudoUrls: [
45
+ * 'https://www.example.com/handbags/[.*]'
46
+ * 'https://www.example.com/purses/[.*]'
47
+ * ],
48
+ * });
49
+ * ```
50
+ *
51
+ * @returns Promise that resolves to {@link BatchAddRequestsResult} object.
52
+ */
53
+ async function enqueueLinksByClickingElements(options) {
54
+ (0, ow_1.default)(options, ow_1.default.object.exactShape({
55
+ page: ow_1.default.object.hasKeys('goto', 'evaluate'),
56
+ requestQueue: ow_1.default.object.hasKeys('fetchNextRequest', 'addRequest'),
57
+ selector: ow_1.default.string,
58
+ clickOptions: ow_1.default.optional.object.hasKeys('clickCount', 'delay'),
59
+ pseudoUrls: ow_1.default.optional.array.ofType(ow_1.default.any(ow_1.default.string, ow_1.default.object.hasKeys('purl'))),
60
+ globs: ow_1.default.optional.array.ofType(ow_1.default.any(ow_1.default.string, ow_1.default.object.hasKeys('glob'))),
61
+ regexps: ow_1.default.optional.array.ofType(ow_1.default.any(ow_1.default.regExp, ow_1.default.object.hasKeys('regexp'))),
62
+ transformRequestFunction: ow_1.default.optional.function,
63
+ waitForPageIdleSecs: ow_1.default.optional.number,
64
+ maxWaitForPageIdleSecs: ow_1.default.optional.number,
65
+ }));
66
+ const { page, requestQueue, selector, clickOptions, pseudoUrls, globs, regexps, transformRequestFunction, waitForPageIdleSecs = 1, maxWaitForPageIdleSecs = 5, } = options;
67
+ const waitForPageIdleMillis = waitForPageIdleSecs * 1000;
68
+ const maxWaitForPageIdleMillis = maxWaitForPageIdleSecs * 1000;
69
+ const urlPatternObjects = [];
70
+ if (pseudoUrls?.length) {
71
+ log.deprecated('`pseudoUrls` option is deprecated, use `globs` or `regexps` instead');
72
+ urlPatternObjects.push(...(0, browser_1.constructRegExpObjectsFromPseudoUrls)(pseudoUrls));
73
+ }
74
+ if (globs?.length) {
75
+ urlPatternObjects.push(...(0, browser_1.constructGlobObjectsFromGlobs)(globs));
76
+ }
77
+ if (regexps?.length) {
78
+ urlPatternObjects.push(...(0, browser_1.constructRegExpObjectsFromRegExps)(regexps));
79
+ }
80
+ const interceptedRequests = await clickElementsAndInterceptNavigationRequests({
81
+ page,
82
+ selector,
83
+ waitForPageIdleMillis,
84
+ maxWaitForPageIdleMillis,
85
+ clickOptions,
86
+ });
87
+ let requestOptions = (0, browser_1.createRequestOptions)(interceptedRequests);
88
+ if (transformRequestFunction) {
89
+ requestOptions = requestOptions.map(transformRequestFunction).filter((r) => !!r);
90
+ }
91
+ const requests = (0, browser_1.createRequests)(requestOptions, urlPatternObjects);
92
+ return requestQueue.addRequests(requests);
93
+ }
94
+ exports.enqueueLinksByClickingElements = enqueueLinksByClickingElements;
95
+ /**
96
+ * Clicks all elements of given page matching given selector.
97
+ * Catches and intercepts all initiated navigation requests and opened pages.
98
+ * Returns a list of all target URLs.
99
+ * @ignore
100
+ */
101
+ async function clickElementsAndInterceptNavigationRequests(options) {
102
+ const { page, selector, waitForPageIdleMillis, maxWaitForPageIdleMillis, clickOptions, } = options;
103
+ const uniqueRequests = new Set();
104
+ const browser = page.browser();
105
+ const onInterceptedRequest = createInterceptRequestHandler(page, uniqueRequests);
106
+ const onTargetCreated = createTargetCreatedHandler(page, uniqueRequests);
107
+ const onFrameNavigated = createFrameNavigatedHandler(page, uniqueRequests);
108
+ await (0, puppeteer_request_interception_1.addInterceptRequestHandler)(page, onInterceptedRequest);
109
+ browser.on("targetcreated" /* TargetCreated */, onTargetCreated);
110
+ page.on("framenavigated" /* FrameNavigated */, onFrameNavigated);
111
+ await preventHistoryNavigation(page);
112
+ await clickElements(page, selector, clickOptions);
113
+ await waitForPageIdle({ page, waitForPageIdleMillis, maxWaitForPageIdleMillis });
114
+ await restoreHistoryNavigationAndSaveCapturedUrls(page, uniqueRequests);
115
+ browser.off("targetcreated" /* TargetCreated */, onTargetCreated);
116
+ page.off("framenavigated" /* FrameNavigated */, onFrameNavigated);
117
+ await (0, puppeteer_request_interception_1.removeInterceptRequestHandler)(page, onInterceptedRequest);
118
+ const serializedRequests = Array.from(uniqueRequests);
119
+ return serializedRequests.map((r) => JSON.parse(r));
120
+ }
121
+ exports.clickElementsAndInterceptNavigationRequests = clickElementsAndInterceptNavigationRequests;
122
+ /**
123
+ * @ignore
124
+ */
125
+ function createInterceptRequestHandler(page, requests) {
126
+ return async function onInterceptedRequest(req) {
127
+ if (!isTopFrameNavigationRequest(page, req))
128
+ return req.continue();
129
+ const url = req.url();
130
+ requests.add(JSON.stringify({
131
+ url,
132
+ headers: req.headers(),
133
+ method: req.method(),
134
+ payload: req.postData(),
135
+ }));
136
+ if (req.redirectChain().length) {
137
+ await req.respond({ body: '' }); // Prevents 301/302 redirect
138
+ }
139
+ else {
140
+ await req.abort('aborted'); // Prevents navigation by js
141
+ }
142
+ };
143
+ }
144
+ /**
145
+ * @ignore
146
+ */
147
+ function isTopFrameNavigationRequest(page, req) {
148
+ return req.isNavigationRequest()
149
+ && req.frame() === page.mainFrame();
150
+ }
151
+ /**
152
+ * @ignore
153
+ */
154
+ function createTargetCreatedHandler(page, requests) {
155
+ return async function onTargetCreated(target) {
156
+ if (!isTargetRelevant(page, target))
157
+ return;
158
+ const url = target.url();
159
+ requests.add(JSON.stringify({ url }));
160
+ // We want to close the page but don't care about
161
+ // possible errors like target closed.
162
+ try {
163
+ const createdPage = await target.page();
164
+ await createdPage.close();
165
+ }
166
+ catch (err) {
167
+ log.debug('enqueueLinksByClickingElements: Could not close spawned page.', { error: err.stack });
168
+ }
169
+ };
170
+ }
171
+ /**
172
+ * We're only interested in pages created by the page we're currently clicking in.
173
+ * There will generally be a lot of other targets being created in the browser.
174
+ */
175
+ function isTargetRelevant(page, target) {
176
+ return target.type() === 'page'
177
+ && page.target() === target.opener();
178
+ }
179
+ exports.isTargetRelevant = isTargetRelevant;
180
+ /**
181
+ * @ignore
182
+ */
183
+ function createFrameNavigatedHandler(page, requests) {
184
+ return function onFrameNavigated(frame) {
185
+ if (frame !== page.mainFrame())
186
+ return;
187
+ const url = frame.url();
188
+ requests.add(JSON.stringify({ url }));
189
+ };
190
+ }
191
+ /**
192
+ * @ignore
193
+ */
194
+ async function preventHistoryNavigation(page) {
195
+ /* istanbul ignore next */
196
+ return page.evaluate(() => {
197
+ window.__originalHistory__ = window.history; // eslint-disable-line no-underscore-dangle
198
+ delete window.history; // Simple override does not work.
199
+ window.history = {
200
+ stateHistory: [],
201
+ length: 0,
202
+ state: {},
203
+ go() { },
204
+ back() { },
205
+ forward() { },
206
+ pushState(...args) {
207
+ this.stateHistory.push(args);
208
+ },
209
+ replaceState(...args) {
210
+ this.stateHistory.push(args);
211
+ },
212
+ };
213
+ });
214
+ }
215
+ /**
216
+ * Click all elements matching the given selector. To be able to do this using
217
+ * Puppeteer's `.click()` we need to make sure the elements are reachable by mouse,
218
+ * so we first move them to the top of the page's stacking context and then click.
219
+ * We do all in series to prevent elements from hiding one another. Therefore,
220
+ * for large element sets, this will take considerable amount of time.
221
+ * @ignore
222
+ */
223
+ async function clickElements(page, selector, clickOptions) {
224
+ const elementHandles = await page.$$(selector);
225
+ log.debug(`enqueueLinksByClickingElements: There are ${elementHandles.length} elements to click.`);
226
+ let clickedElementsCount = 0;
227
+ let zIndex = STARTING_Z_INDEX;
228
+ let shouldLogWarning = true;
229
+ for (const handle of elementHandles) {
230
+ try {
231
+ await page.evaluate(updateElementCssToEnableMouseClick, handle, zIndex++);
232
+ await handle.click(clickOptions);
233
+ clickedElementsCount++;
234
+ }
235
+ catch (err) {
236
+ const e = err;
237
+ if (shouldLogWarning && e.stack.includes('is detached from document')) {
238
+ log.warning(`An element with selector ${selector} that you're trying to click has been removed from the page. `
239
+ + 'This was probably caused by an earlier click which triggered some JavaScript on the page that caused it to change. '
240
+ + 'If you\'re trying to enqueue pagination links, we suggest using the "next" button, if available and going one by one.');
241
+ shouldLogWarning = false;
242
+ }
243
+ log.debug('enqueueLinksByClickingElements: Click failed.', { stack: e.stack });
244
+ }
245
+ }
246
+ log.debug(`enqueueLinksByClickingElements: Successfully clicked ${clickedElementsCount} elements out of ${elementHandles.length}`);
247
+ }
248
+ exports.clickElements = clickElements;
249
+ /* istanbul ignore next */
250
+ /**
251
+ * This is an in browser function!
252
+ */
253
+ function updateElementCssToEnableMouseClick(el, zIndex) {
254
+ el.style.visibility = 'visible';
255
+ el.style.display = 'block';
256
+ el.style.position = 'fixed';
257
+ el.style.zIndex = String(zIndex);
258
+ el.style.left = '0';
259
+ el.style.top = '0';
260
+ const boundingRect = el.getBoundingClientRect();
261
+ if (!boundingRect.height)
262
+ el.style.height = '10px';
263
+ if (!boundingRect.width)
264
+ el.style.width = '10px';
265
+ }
266
+ /**
267
+ * This function tracks whether any requests, frame navigations or targets were emitted
268
+ * in the past idleIntervalMillis and whenever the interval registers no activity,
269
+ * the function returns.
270
+ *
271
+ * It will also return when a final timeout, represented by the timeoutMillis parameter
272
+ * is reached, to prevent blocking on pages with constant network activity.
273
+ *
274
+ * We need this to make sure we don't finish too soon when intercepting requests triggered
275
+ * by clicking in the page. They often get registered by the Node.js process only some
276
+ * milliseconds after clicking and we would lose those requests. This is especially prevalent
277
+ * when there's only a single element to click.
278
+ * @ignore
279
+ */
280
+ async function waitForPageIdle({ page, waitForPageIdleMillis, maxWaitForPageIdleMillis }) {
281
+ return new Promise((resolve) => {
282
+ let timeout;
283
+ let maxTimeout;
284
+ const context = page.browserContext();
285
+ function newTabTracker(target) {
286
+ if (isTargetRelevant(page, target))
287
+ activityHandler();
288
+ }
289
+ function activityHandler() {
290
+ clearTimeout(timeout);
291
+ timeout = setTimeout(() => {
292
+ clearTimeout(maxTimeout);
293
+ finish();
294
+ }, waitForPageIdleMillis);
295
+ }
296
+ function maxTimeoutHandler() {
297
+ log.debug(`enqueueLinksByClickingElements: Page still showed activity after ${maxWaitForPageIdleMillis}ms. `
298
+ + 'This is probably due to the website itself dispatching requests, but some links may also have been missed.');
299
+ finish();
300
+ }
301
+ function finish() {
302
+ page.off("request" /* Request */, activityHandler);
303
+ page.off("framenavigated" /* FrameNavigated */, activityHandler);
304
+ context.off("targetcreated" /* TargetCreated */, newTabTracker);
305
+ resolve();
306
+ }
307
+ maxTimeout = setTimeout(maxTimeoutHandler, maxWaitForPageIdleMillis);
308
+ activityHandler(); // We call this once manually in case there would be no requests at all.
309
+ page.on("request" /* Request */, activityHandler);
310
+ page.on("framenavigated" /* FrameNavigated */, activityHandler);
311
+ context.on("targetcreated" /* TargetCreated */, newTabTracker);
312
+ });
313
+ }
314
+ /**
315
+ * @ignore
316
+ */
317
+ async function restoreHistoryNavigationAndSaveCapturedUrls(page, requests) {
318
+ /* eslint-disable no-shadow */
319
+ /* istanbul ignore next */
320
+ const state = await page.evaluate(() => {
321
+ const { stateHistory } = window.history;
322
+ window.history = window.__originalHistory__; // eslint-disable-line no-underscore-dangle
323
+ return stateHistory;
324
+ });
325
+ state.forEach((args) => {
326
+ try {
327
+ const stateUrl = args[args.length - 1];
328
+ const url = new url_1.URL(stateUrl, page.url()).href;
329
+ requests.add(JSON.stringify({ url }));
330
+ }
331
+ catch (err) {
332
+ log.debug('enqueueLinksByClickingElements: Failed to ', { error: err.stack });
333
+ }
334
+ });
335
+ }
336
+ //# sourceMappingURL=click-elements.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"click-elements.js","sourceRoot":"","sources":["../../../src/internals/enqueue-links/click-elements.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ import { BrowserCrawler, BrowserCrawlerHandleRequest, BrowserCrawlerOptions, BrowserCrawlingContext, BrowserHook } from '@crawlee/browser';
2
+ import { PuppeteerPlugin } from '@crawlee/browser-pool';
3
+ import { HTTPResponse, LaunchOptions, Page } from 'puppeteer';
4
+ import { PuppeteerLaunchContext } from './puppeteer-launcher';
5
+ import { DirectNavigationOptions } from './utils/puppeteer_utils';
6
+ export declare type PuppeteerController = ReturnType<PuppeteerPlugin['_createController']>;
7
+ export declare type PuppeteerCrawlContext = BrowserCrawlingContext<Page, HTTPResponse, PuppeteerController>;
8
+ export declare type PuppeteerHook = BrowserHook<PuppeteerCrawlContext, PuppeteerGoToOptions>;
9
+ export declare type PuppeteerRequestHandlerParam = BrowserCrawlingContext<Page, HTTPResponse, PuppeteerController>;
10
+ export declare type PuppeteerRequestHandler = BrowserCrawlerHandleRequest<PuppeteerRequestHandlerParam>;
11
+ export declare type PuppeteerGoToOptions = Parameters<Page['goto']>[1];
12
+ export interface PuppeteerCrawlerOptions extends BrowserCrawlerOptions<PuppeteerCrawlContext, PuppeteerGoToOptions, {
13
+ browserPlugins: [PuppeteerPlugin];
14
+ }> {
15
+ /**
16
+ * Options used by {@link launchPuppeteer} to start new Puppeteer instances.
17
+ */
18
+ launchContext?: PuppeteerLaunchContext;
19
+ /**
20
+ * Async functions that are sequentially evaluated before the navigation. Good for setting additional cookies
21
+ * or browser properties before navigation. The function accepts two parameters, `crawlingContext` and `gotoOptions`,
22
+ * which are passed to the `page.goto()` function the crawler calls to navigate.
23
+ * Example:
24
+ * ```
25
+ * preNavigationHooks: [
26
+ * async (crawlingContext, gotoOptions) => {
27
+ * const { page } = crawlingContext;
28
+ * await page.evaluate((attr) => { window.foo = attr; }, 'bar');
29
+ * },
30
+ * ]
31
+ * ```
32
+ */
33
+ preNavigationHooks?: PuppeteerHook[];
34
+ /**
35
+ * Async functions that are sequentially evaluated after the navigation. Good for checking if the navigation was successful.
36
+ * The function accepts `crawlingContext` as the only parameter.
37
+ * Example:
38
+ * ```
39
+ * postNavigationHooks: [
40
+ * async (crawlingContext) => {
41
+ * const { page } = crawlingContext;
42
+ * if (hasCaptcha(page)) {
43
+ * await solveCaptcha (page);
44
+ * }
45
+ * },
46
+ * ]
47
+ * ```
48
+ */
49
+ postNavigationHooks?: PuppeteerHook[];
50
+ }
51
+ /**
52
+ * Provides a simple framework for parallel crawling of web pages
53
+ * using headless Chrome with [Puppeteer](https://github.com/puppeteer/puppeteer).
54
+ * The URLs to crawl are fed either from a static list of URLs
55
+ * or from a dynamic queue of URLs enabling recursive crawling of websites.
56
+ *
57
+ * Since `PuppeteerCrawler` uses headless Chrome to download web pages and extract data,
58
+ * it is useful for crawling of websites that require to execute JavaScript.
59
+ * If the target website doesn't need JavaScript, consider using {@link CheerioCrawler},
60
+ * which downloads the pages using raw HTTP requests and is about 10x faster.
61
+ *
62
+ * The source URLs are represented using {@link Request} objects that are fed from
63
+ * {@link RequestList} or {@link RequestQueue} instances provided by the {@link PuppeteerCrawlerOptions.requestList}
64
+ * or {@link PuppeteerCrawlerOptions.requestQueue} constructor options, respectively.
65
+ *
66
+ * If both {@link PuppeteerCrawlerOptions.requestList} and {@link PuppeteerCrawlerOptions.requestQueue} are used,
67
+ * the instance first processes URLs from the {@link RequestList} and automatically enqueues all of them
68
+ * to {@link RequestQueue} before it starts their processing. This ensures that a single URL is not crawled multiple times.
69
+ *
70
+ * The crawler finishes when there are no more {@link Request} objects to crawl.
71
+ *
72
+ * `PuppeteerCrawler` opens a new Chrome page (i.e. tab) for each {@link Request} object to crawl
73
+ * and then calls the function provided by user as the {@link PuppeteerCrawlerOptions.handlePageFunction} option.
74
+ *
75
+ * New pages are only opened when there is enough free CPU and memory available,
76
+ * using the functionality provided by the {@link AutoscaledPool} class.
77
+ * All {@link AutoscaledPool} configuration options can be passed to the {@link PuppeteerCrawlerOptions.autoscaledPoolOptions}
78
+ * parameter of the `PuppeteerCrawler` constructor. For user convenience, the `minConcurrency` and `maxConcurrency`
79
+ * {@link AutoscaledPoolOptions} are available directly in the `PuppeteerCrawler` constructor.
80
+ *
81
+ * Note that the pool of Puppeteer instances is internally managed by the [BrowserPool](https://github.com/apify/browser-pool) class.
82
+ *
83
+ * **Example usage:**
84
+ *
85
+ * ```javascript
86
+ * const crawler = new PuppeteerCrawler({
87
+ * requestList,
88
+ * handlePageFunction: async ({ page, request }) => {
89
+ * // This function is called to extract data from a single web page
90
+ * // 'page' is an instance of Puppeteer.Page with page.goto(request.url) already called
91
+ * // 'request' is an instance of Request class with information about the page to load
92
+ * await Actor.pushData({
93
+ * title: await page.title(),
94
+ * url: request.url,
95
+ * succeeded: true,
96
+ * })
97
+ * },
98
+ * handleFailedRequestFunction: async ({ request }) => {
99
+ * // This function is called when the crawling of a request failed too many times
100
+ * await Actor.pushData({
101
+ * url: request.url,
102
+ * succeeded: false,
103
+ * errors: request.errorMessages,
104
+ * })
105
+ * },
106
+ * });
107
+ *
108
+ * await crawler.run();
109
+ * ```
110
+ * @category Crawlers
111
+ */
112
+ export declare class PuppeteerCrawler extends BrowserCrawler<{
113
+ browserPlugins: [PuppeteerPlugin];
114
+ }, LaunchOptions, PuppeteerCrawlContext> {
115
+ protected static optionsShape: {
116
+ browserPoolOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
117
+ launchContext: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
118
+ handlePageFunction: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
119
+ gotoFunction: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
120
+ gotoTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
121
+ navigationTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
122
+ preNavigationHooks: import("ow").ArrayPredicate<unknown> & import("ow").BasePredicate<unknown[] | undefined>;
123
+ postNavigationHooks: import("ow").ArrayPredicate<unknown> & import("ow").BasePredicate<unknown[] | undefined>;
124
+ sessionPoolOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
125
+ persistCookiesPerSession: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
126
+ useSessionPool: import("ow").BooleanPredicate & import("ow").BasePredicate<boolean | undefined>;
127
+ proxyConfiguration: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
128
+ requestList: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
129
+ requestQueue: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
130
+ requestHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
131
+ handleRequestFunction: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
132
+ requestHandlerTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
133
+ handleRequestTimeoutSecs: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
134
+ failedRequestHandler: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
135
+ handleFailedRequestFunction: import("ow").Predicate<Function> & import("ow").BasePredicate<Function | undefined>;
136
+ maxRequestRetries: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
137
+ maxRequestsPerCrawl: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
138
+ autoscaledPoolOptions: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
139
+ minConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
140
+ maxConcurrency: import("ow").NumberPredicate & import("ow").BasePredicate<number | undefined>;
141
+ log: import("ow").ObjectPredicate<object> & import("ow").BasePredicate<object | undefined>;
142
+ };
143
+ /**
144
+ * All `PuppeteerCrawler` parameters are passed via an options object.
145
+ */
146
+ constructor(options: PuppeteerCrawlerOptions);
147
+ protected _navigationHandler(crawlingContext: PuppeteerCrawlContext, gotoOptions: DirectNavigationOptions): Promise<any>;
148
+ }
149
+ //# sourceMappingURL=puppeteer-crawler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puppeteer-crawler.d.ts","sourceRoot":"","sources":["../../src/internals/puppeteer-crawler.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,cAAc,EACd,2BAA2B,EAC3B,qBAAqB,EACrB,sBAAsB,EACtB,WAAW,EACd,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAAsB,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAqB,MAAM,sBAAsB,CAAC;AAEjF,OAAO,EAAE,uBAAuB,EAAgB,MAAM,yBAAyB,CAAC;AAEhF,oBAAY,mBAAmB,GAAG,UAAU,CAAC,eAAe,CAAC,mBAAmB,CAAC,CAAC,CAAC;AAEnF,oBAAY,qBAAqB,GAAG,sBAAsB,CAAC,IAAI,EAAE,YAAY,EAAE,mBAAmB,CAAC,CAAA;AAEnG,oBAAY,aAAa,GAAG,WAAW,CAAC,qBAAqB,EAAE,oBAAoB,CAAC,CAAC;AAErF,oBAAY,4BAA4B,GAAG,sBAAsB,CAAC,IAAI,EAAE,YAAY,EAAE,mBAAmB,CAAC,CAAA;AAE1G,oBAAY,uBAAuB,GAAG,2BAA2B,CAAC,4BAA4B,CAAC,CAAC;AAEhG,oBAAY,oBAAoB,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAE/D,MAAM,WAAW,uBAAwB,SAAQ,qBAAqB,CAClE,qBAAqB,EACrB,oBAAoB,EACpB;IAAE,cAAc,EAAE,CAAC,eAAe,CAAC,CAAA;CAAE,CACxC;IACG;;OAEG;IACH,aAAa,CAAC,EAAE,sBAAsB,CAAC;IAEvC;;;;;;;;;;;;;OAaG;IACH,kBAAkB,CAAC,EAAE,aAAa,EAAE,CAAC;IAErC;;;;;;;;;;;;;;OAcG;IACH,mBAAmB,CAAC,EAAE,aAAa,EAAE,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,qBAAa,gBAAiB,SAAQ,cAAc,CAAC;IAAE,cAAc,EAAE,CAAC,eAAe,CAAC,CAAA;CAAE,EAAE,aAAa,EAAE,qBAAqB,CAAC;IAC7H,iBAA0B,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;MAIpC;IAEF;;OAEG;gBACS,OAAO,EAAE,uBAAuB;cAqCnB,kBAAkB,CAAC,eAAe,EAAE,qBAAqB,EAAE,WAAW,EAAE,uBAAuB;CAQ3H"}
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PuppeteerCrawler = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const browser_1 = require("@crawlee/browser");
6
+ const ow_1 = tslib_1.__importDefault(require("ow"));
7
+ const puppeteer_launcher_1 = require("./puppeteer-launcher");
8
+ const stealth_1 = require("./stealth");
9
+ const puppeteer_utils_1 = require("./utils/puppeteer_utils");
10
+ /**
11
+ * Provides a simple framework for parallel crawling of web pages
12
+ * using headless Chrome with [Puppeteer](https://github.com/puppeteer/puppeteer).
13
+ * The URLs to crawl are fed either from a static list of URLs
14
+ * or from a dynamic queue of URLs enabling recursive crawling of websites.
15
+ *
16
+ * Since `PuppeteerCrawler` uses headless Chrome to download web pages and extract data,
17
+ * it is useful for crawling of websites that require to execute JavaScript.
18
+ * If the target website doesn't need JavaScript, consider using {@link CheerioCrawler},
19
+ * which downloads the pages using raw HTTP requests and is about 10x faster.
20
+ *
21
+ * The source URLs are represented using {@link Request} objects that are fed from
22
+ * {@link RequestList} or {@link RequestQueue} instances provided by the {@link PuppeteerCrawlerOptions.requestList}
23
+ * or {@link PuppeteerCrawlerOptions.requestQueue} constructor options, respectively.
24
+ *
25
+ * If both {@link PuppeteerCrawlerOptions.requestList} and {@link PuppeteerCrawlerOptions.requestQueue} are used,
26
+ * the instance first processes URLs from the {@link RequestList} and automatically enqueues all of them
27
+ * to {@link RequestQueue} before it starts their processing. This ensures that a single URL is not crawled multiple times.
28
+ *
29
+ * The crawler finishes when there are no more {@link Request} objects to crawl.
30
+ *
31
+ * `PuppeteerCrawler` opens a new Chrome page (i.e. tab) for each {@link Request} object to crawl
32
+ * and then calls the function provided by user as the {@link PuppeteerCrawlerOptions.handlePageFunction} option.
33
+ *
34
+ * New pages are only opened when there is enough free CPU and memory available,
35
+ * using the functionality provided by the {@link AutoscaledPool} class.
36
+ * All {@link AutoscaledPool} configuration options can be passed to the {@link PuppeteerCrawlerOptions.autoscaledPoolOptions}
37
+ * parameter of the `PuppeteerCrawler` constructor. For user convenience, the `minConcurrency` and `maxConcurrency`
38
+ * {@link AutoscaledPoolOptions} are available directly in the `PuppeteerCrawler` constructor.
39
+ *
40
+ * Note that the pool of Puppeteer instances is internally managed by the [BrowserPool](https://github.com/apify/browser-pool) class.
41
+ *
42
+ * **Example usage:**
43
+ *
44
+ * ```javascript
45
+ * const crawler = new PuppeteerCrawler({
46
+ * requestList,
47
+ * handlePageFunction: async ({ page, request }) => {
48
+ * // This function is called to extract data from a single web page
49
+ * // 'page' is an instance of Puppeteer.Page with page.goto(request.url) already called
50
+ * // 'request' is an instance of Request class with information about the page to load
51
+ * await Actor.pushData({
52
+ * title: await page.title(),
53
+ * url: request.url,
54
+ * succeeded: true,
55
+ * })
56
+ * },
57
+ * handleFailedRequestFunction: async ({ request }) => {
58
+ * // This function is called when the crawling of a request failed too many times
59
+ * await Actor.pushData({
60
+ * url: request.url,
61
+ * succeeded: false,
62
+ * errors: request.errorMessages,
63
+ * })
64
+ * },
65
+ * });
66
+ *
67
+ * await crawler.run();
68
+ * ```
69
+ * @category Crawlers
70
+ */
71
+ class PuppeteerCrawler extends browser_1.BrowserCrawler {
72
+ /**
73
+ * All `PuppeteerCrawler` parameters are passed via an options object.
74
+ */
75
+ constructor(options) {
76
+ (0, ow_1.default)(options, 'PuppeteerCrawlerOptions', ow_1.default.object.exactShape(PuppeteerCrawler.optionsShape));
77
+ const { launchContext = {}, browserPoolOptions = {}, proxyConfiguration, ...browserCrawlerOptions } = options;
78
+ const { stealth = false } = launchContext;
79
+ if (launchContext.proxyUrl) {
80
+ throw new Error('PuppeteerCrawlerOptions.launchContext.proxyUrl is not allowed in PuppeteerCrawler.'
81
+ + 'Use PuppeteerCrawlerOptions.proxyConfiguration');
82
+ }
83
+ const puppeteerLauncher = new puppeteer_launcher_1.PuppeteerLauncher(launchContext);
84
+ browserPoolOptions.browserPlugins = [
85
+ puppeteerLauncher.createBrowserPlugin(),
86
+ ];
87
+ super({ ...browserCrawlerOptions, proxyConfiguration, browserPoolOptions });
88
+ if (stealth) {
89
+ this.browserPool.postLaunchHooks.push(async (_pageId, browserController) => {
90
+ // TODO: We can do this better now. It is not necessary to override the page.
91
+ // we can modify the page in the postPageCreateHook
92
+ const { hideWebDriver, ...newStealthOptions } = puppeteerLauncher.stealthOptions;
93
+ (0, stealth_1.applyStealthToBrowser)(browserController.browser, newStealthOptions);
94
+ });
95
+ }
96
+ this.launchContext = launchContext;
97
+ }
98
+ async _navigationHandler(crawlingContext, gotoOptions) {
99
+ if (this.gotoFunction) {
100
+ this.log.deprecated('PuppeteerCrawlerOptions.gotoFunction is deprecated. Use "preNavigationHooks" and "postNavigationHooks" instead.');
101
+ return this.gotoFunction(crawlingContext, gotoOptions);
102
+ }
103
+ return (0, puppeteer_utils_1.gotoExtended)(crawlingContext.page, crawlingContext.request, gotoOptions);
104
+ }
105
+ }
106
+ exports.PuppeteerCrawler = PuppeteerCrawler;
107
+ Object.defineProperty(PuppeteerCrawler, "optionsShape", {
108
+ enumerable: true,
109
+ configurable: true,
110
+ writable: true,
111
+ value: {
112
+ ...browser_1.BrowserCrawler.optionsShape,
113
+ browserPoolOptions: ow_1.default.optional.object,
114
+ launchContext: ow_1.default.optional.object,
115
+ }
116
+ });
117
+ //# sourceMappingURL=puppeteer-crawler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puppeteer-crawler.js","sourceRoot":"","sources":["../../src/internals/puppeteer-crawler.ts"],"names":[],"mappings":";;;;AAAA,8CAM0B;AAK1B,oDAAoB;AAEpB,6DAAiF;AACjF,uCAAkD;AAClD,6DAAgF;AA0DhF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,MAAa,gBAAiB,SAAQ,wBAA2F;IAO7H;;OAEG;IACH,YAAY,OAAgC;QACxC,IAAA,YAAE,EAAC,OAAO,EAAE,yBAAyB,EAAE,YAAE,CAAC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC;QAE5F,MAAM,EACF,aAAa,GAAG,EAAE,EAClB,kBAAkB,GAAG,EAAwB,EAC7C,kBAAkB,EAClB,GAAG,qBAAqB,EAC3B,GAAG,OAAO,CAAC;QAEZ,MAAM,EAAE,OAAO,GAAG,KAAK,EAAE,GAAG,aAAa,CAAC;QAE1C,IAAI,aAAa,CAAC,QAAQ,EAAE;YACxB,MAAM,IAAI,KAAK,CAAC,oFAAoF;kBAC9F,gDAAgD,CAAC,CAAC;SAC3D;QAED,MAAM,iBAAiB,GAAG,IAAI,sCAAiB,CAAC,aAAa,CAAC,CAAC;QAE/D,kBAAkB,CAAC,cAAc,GAAG;YAChC,iBAAiB,CAAC,mBAAmB,EAAE;SAC1C,CAAC;QAEF,KAAK,CAAC,EAAE,GAAG,qBAAqB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAE5E,IAAI,OAAO,EAAE;YACT,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE;gBACvE,6EAA6E;gBAC7E,oDAAoD;gBACpD,MAAM,EAAE,aAAa,EAAE,GAAG,iBAAiB,EAAE,GAAG,iBAAiB,CAAC,cAAe,CAAC;gBAClF,IAAA,+BAAqB,EAAC,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,CAAC,CAAC;YACxE,CAAC,CAAC,CAAC;SACN;QAED,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;IACvC,CAAC;IAEkB,KAAK,CAAC,kBAAkB,CAAC,eAAsC,EAAE,WAAoC;QACpH,IAAI,IAAI,CAAC,YAAY,EAAE;YACnB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,iHAAiH,CAAC,CAAC;YAEvI,OAAO,IAAI,CAAC,YAAY,CAAC,eAAe,EAAE,WAAyB,CAAC,CAAC;SACxE;QACD,OAAO,IAAA,8BAAY,EAAC,eAAe,CAAC,IAAI,EAAE,eAAe,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IACpF,CAAC;;AAtDL,4CAuDC;AAtDG;;;;WAAyC;QACrC,GAAG,wBAAc,CAAC,YAAY;QAC9B,kBAAkB,EAAE,YAAE,CAAC,QAAQ,CAAC,MAAM;QACtC,aAAa,EAAE,YAAE,CAAC,QAAQ,CAAC,MAAM;KACpC;GAAC"}