@crawlee/puppeteer 3.0.0-alpha.2 → 3.0.0-alpha.5
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/index.d.ts +12 -0
- package/index.d.ts.map +1 -0
- package/index.js +12 -0
- package/index.js.map +1 -0
- package/index.mjs +76 -0
- package/internals/enqueue-links/click-elements.d.ts +188 -0
- package/internals/enqueue-links/click-elements.d.ts.map +1 -0
- package/internals/enqueue-links/click-elements.js +336 -0
- package/internals/enqueue-links/click-elements.js.map +1 -0
- package/internals/puppeteer-crawler.d.ts +149 -0
- package/internals/puppeteer-crawler.d.ts.map +1 -0
- package/internals/puppeteer-crawler.js +117 -0
- package/internals/puppeteer-crawler.js.map +1 -0
- package/internals/puppeteer-launcher.d.ts +142 -0
- package/internals/puppeteer-launcher.d.ts.map +1 -0
- package/internals/puppeteer-launcher.js +150 -0
- package/internals/puppeteer-launcher.js.map +1 -0
- package/internals/stealth/hiding_tricks.d.ts +10 -0
- package/internals/stealth/hiding_tricks.d.ts.map +1 -0
- package/internals/stealth/hiding_tricks.js +334 -0
- package/internals/stealth/hiding_tricks.js.map +1 -0
- package/internals/stealth/index.d.ts +40 -0
- package/internals/stealth/index.d.ts.map +1 -0
- package/internals/stealth/index.js +108 -0
- package/internals/stealth/index.js.map +1 -0
- package/internals/utils/puppeteer_request_interception.d.ts +60 -0
- package/internals/utils/puppeteer_request_interception.d.ts.map +1 -0
- package/internals/utils/puppeteer_request_interception.js +225 -0
- package/internals/utils/puppeteer_request_interception.js.map +1 -0
- package/internals/utils/puppeteer_utils.d.ts +298 -0
- package/internals/utils/puppeteer_utils.d.ts.map +1 -0
- package/internals/utils/puppeteer_utils.js +468 -0
- package/internals/utils/puppeteer_utils.js.map +1 -0
- package/package.json +2 -5
- package/tsconfig.build.tsbuildinfo +1 -0
package/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from '@crawlee/browser';
|
|
2
|
+
export * from './internals/puppeteer-crawler';
|
|
3
|
+
export * from './internals/puppeteer-launcher';
|
|
4
|
+
export * as puppeteerStealth from './internals/stealth';
|
|
5
|
+
export type { StealthOptions } from './internals/stealth';
|
|
6
|
+
export * as puppeteerRequestInterception from './internals/utils/puppeteer_request_interception';
|
|
7
|
+
export type { InterceptHandler } from './internals/utils/puppeteer_request_interception';
|
|
8
|
+
export * as puppeteerUtils from './internals/utils/puppeteer_utils';
|
|
9
|
+
export type { BlockRequestsOptions, CompiledScriptFunction, CompiledScriptParams, DirectNavigationOptions as PuppeteerDirectNavigationOptions, InfiniteScrollOptions, InjectFileOptions, SaveSnapshotOptions, } from './internals/utils/puppeteer_utils';
|
|
10
|
+
export * as puppeteerClickElements from './internals/enqueue-links/click-elements';
|
|
11
|
+
export type { EnqueueLinksByClickingElementsOptions } from './internals/enqueue-links/click-elements';
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAE/C,OAAO,KAAK,gBAAgB,MAAM,qBAAqB,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,4BAA4B,MAAM,kDAAkD,CAAC;AACjG,YAAY,EAAE,gBAAgB,EAAE,MAAM,kDAAkD,CAAC;AAEzF,OAAO,KAAK,cAAc,MAAM,mCAAmC,CAAC;AACpE,YAAY,EACR,oBAAoB,EACpB,sBAAsB,EACtB,oBAAoB,EACpB,uBAAuB,IAAI,gCAAgC,EAC3D,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,GACtB,MAAM,mCAAmC,CAAC;AAE3C,OAAO,KAAK,sBAAsB,MAAM,0CAA0C,CAAC;AACnF,YAAY,EAAE,qCAAqC,EAAE,MAAM,0CAA0C,CAAC"}
|
package/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.puppeteerClickElements = exports.puppeteerUtils = exports.puppeteerRequestInterception = exports.puppeteerStealth = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
tslib_1.__exportStar(require("@crawlee/browser"), exports);
|
|
6
|
+
tslib_1.__exportStar(require("./internals/puppeteer-crawler"), exports);
|
|
7
|
+
tslib_1.__exportStar(require("./internals/puppeteer-launcher"), exports);
|
|
8
|
+
exports.puppeteerStealth = tslib_1.__importStar(require("./internals/stealth"));
|
|
9
|
+
exports.puppeteerRequestInterception = tslib_1.__importStar(require("./internals/utils/puppeteer_request_interception"));
|
|
10
|
+
exports.puppeteerUtils = tslib_1.__importStar(require("./internals/utils/puppeteer_utils"));
|
|
11
|
+
exports.puppeteerClickElements = tslib_1.__importStar(require("./internals/enqueue-links/click-elements"));
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;AAAA,2DAAiC;AACjC,wEAA8C;AAC9C,yEAA+C;AAE/C,gFAAwD;AAGxD,yHAAiG;AAGjG,4FAAoE;AAWpE,2GAAmF"}
|
package/index.mjs
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import mod from "./index.js";
|
|
2
|
+
|
|
3
|
+
export default mod;
|
|
4
|
+
export const API_PROCESSED_REQUESTS_DELAY_MILLIS = mod.API_PROCESSED_REQUESTS_DELAY_MILLIS;
|
|
5
|
+
export const AutoscaledPool = mod.AutoscaledPool;
|
|
6
|
+
export const BASIC_CRAWLER_TIMEOUT_BUFFER_SECS = mod.BASIC_CRAWLER_TIMEOUT_BUFFER_SECS;
|
|
7
|
+
export const BasicCrawler = mod.BasicCrawler;
|
|
8
|
+
export const BrowserCrawler = mod.BrowserCrawler;
|
|
9
|
+
export const BrowserLauncher = mod.BrowserLauncher;
|
|
10
|
+
export const Configuration = mod.Configuration;
|
|
11
|
+
export const CookieParseError = mod.CookieParseError;
|
|
12
|
+
export const CrawlerExtension = mod.CrawlerExtension;
|
|
13
|
+
export const DATASET_ITERATORS_DEFAULT_LIMIT = mod.DATASET_ITERATORS_DEFAULT_LIMIT;
|
|
14
|
+
export const Dataset = mod.Dataset;
|
|
15
|
+
export const EVENT_SESSION_RETIRED = mod.EVENT_SESSION_RETIRED;
|
|
16
|
+
export const EnqueueStrategy = mod.EnqueueStrategy;
|
|
17
|
+
export const EventManager = mod.EventManager;
|
|
18
|
+
export const EventType = mod.EventType;
|
|
19
|
+
export const KeyValueStore = mod.KeyValueStore;
|
|
20
|
+
export const LocalEventManager = mod.LocalEventManager;
|
|
21
|
+
export const Log = mod.Log;
|
|
22
|
+
export const LogLevel = mod.LogLevel;
|
|
23
|
+
export const Logger = mod.Logger;
|
|
24
|
+
export const LoggerJson = mod.LoggerJson;
|
|
25
|
+
export const LoggerText = mod.LoggerText;
|
|
26
|
+
export const MAX_QUERIES_FOR_CONSISTENCY = mod.MAX_QUERIES_FOR_CONSISTENCY;
|
|
27
|
+
export const ProxyConfiguration = mod.ProxyConfiguration;
|
|
28
|
+
export const PuppeteerCrawler = mod.PuppeteerCrawler;
|
|
29
|
+
export const PuppeteerLauncher = mod.PuppeteerLauncher;
|
|
30
|
+
export const QUERY_HEAD_BUFFER = mod.QUERY_HEAD_BUFFER;
|
|
31
|
+
export const QUERY_HEAD_MIN_LENGTH = mod.QUERY_HEAD_MIN_LENGTH;
|
|
32
|
+
export const REQUESTS_PERSISTENCE_KEY = mod.REQUESTS_PERSISTENCE_KEY;
|
|
33
|
+
export const Request = mod.Request;
|
|
34
|
+
export const RequestList = mod.RequestList;
|
|
35
|
+
export const RequestQueue = mod.RequestQueue;
|
|
36
|
+
export const STATE_PERSISTENCE_KEY = mod.STATE_PERSISTENCE_KEY;
|
|
37
|
+
export const STATUS_CODES_BLOCKED = mod.STATUS_CODES_BLOCKED;
|
|
38
|
+
export const STORAGE_CONSISTENCY_DELAY_MILLIS = mod.STORAGE_CONSISTENCY_DELAY_MILLIS;
|
|
39
|
+
export const Session = mod.Session;
|
|
40
|
+
export const SessionPool = mod.SessionPool;
|
|
41
|
+
export const Snapshotter = mod.Snapshotter;
|
|
42
|
+
export const Statistics = mod.Statistics;
|
|
43
|
+
export const StorageManager = mod.StorageManager;
|
|
44
|
+
export const SystemStatus = mod.SystemStatus;
|
|
45
|
+
export const browserCrawlerEnqueueLinks = mod.browserCrawlerEnqueueLinks;
|
|
46
|
+
export const checkAndSerialize = mod.checkAndSerialize;
|
|
47
|
+
export const chunkBySize = mod.chunkBySize;
|
|
48
|
+
export const constructGlobObjectsFromGlobs = mod.constructGlobObjectsFromGlobs;
|
|
49
|
+
export const constructRegExpObjectsFromPseudoUrls = mod.constructRegExpObjectsFromPseudoUrls;
|
|
50
|
+
export const constructRegExpObjectsFromRegExps = mod.constructRegExpObjectsFromRegExps;
|
|
51
|
+
export const createDeserialize = mod.createDeserialize;
|
|
52
|
+
export const createRequestOptions = mod.createRequestOptions;
|
|
53
|
+
export const createRequests = mod.createRequests;
|
|
54
|
+
export const deserializeArray = mod.deserializeArray;
|
|
55
|
+
export const diffCookies = mod.diffCookies;
|
|
56
|
+
export const enqueueLinks = mod.enqueueLinks;
|
|
57
|
+
export const getCookiesFromResponse = mod.getCookiesFromResponse;
|
|
58
|
+
export const getRequestId = mod.getRequestId;
|
|
59
|
+
export const handleRequestTimeout = mod.handleRequestTimeout;
|
|
60
|
+
export const launchPuppeteer = mod.launchPuppeteer;
|
|
61
|
+
export const log = mod.log;
|
|
62
|
+
export const maybeStringify = mod.maybeStringify;
|
|
63
|
+
export const mergeCookies = mod.mergeCookies;
|
|
64
|
+
export const openDataset = mod.openDataset;
|
|
65
|
+
export const puppeteerClickElements = mod.puppeteerClickElements;
|
|
66
|
+
export const puppeteerRequestInterception = mod.puppeteerRequestInterception;
|
|
67
|
+
export const puppeteerStealth = mod.puppeteerStealth;
|
|
68
|
+
export const puppeteerUtils = mod.puppeteerUtils;
|
|
69
|
+
export const pushData = mod.pushData;
|
|
70
|
+
export const resolveBaseUrl = mod.resolveBaseUrl;
|
|
71
|
+
export const serializeArray = mod.serializeArray;
|
|
72
|
+
export const storage = mod.storage;
|
|
73
|
+
export const throwOnBlockedRequest = mod.throwOnBlockedRequest;
|
|
74
|
+
export const updateEnqueueLinksPatternCache = mod.updateEnqueueLinksPatternCache;
|
|
75
|
+
export const validateGlobPattern = mod.validateGlobPattern;
|
|
76
|
+
export const validators = mod.validators;
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { GlobInput, PseudoUrlInput, RegExpInput, RequestTransform, RequestQueue, storage } from '@crawlee/browser';
|
|
2
|
+
import { Dictionary } from '@crawlee/utils';
|
|
3
|
+
import { ClickOptions, Page, Target } from 'puppeteer';
|
|
4
|
+
export interface EnqueueLinksByClickingElementsOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Puppeteer [`Page`](https://pptr.dev/#?product=Puppeteer&show=api-class-page) object.
|
|
7
|
+
*/
|
|
8
|
+
page: Page;
|
|
9
|
+
/**
|
|
10
|
+
* A request queue to which the URLs will be enqueued.
|
|
11
|
+
*/
|
|
12
|
+
requestQueue: RequestQueue;
|
|
13
|
+
/**
|
|
14
|
+
* A CSS selector matching elements to be clicked on. Unlike in {@link enqueueLinks}, there is no default
|
|
15
|
+
* value. This is to prevent suboptimal use of this function by using it too broadly.
|
|
16
|
+
*/
|
|
17
|
+
selector: string;
|
|
18
|
+
/**
|
|
19
|
+
* Click options for use in Puppeteer's click handler.
|
|
20
|
+
*/
|
|
21
|
+
clickOptions?: ClickOptions;
|
|
22
|
+
/**
|
|
23
|
+
* An array of glob pattern strings or plain objects
|
|
24
|
+
* containing glob pattern strings matching the URLs to be enqueued.
|
|
25
|
+
*
|
|
26
|
+
* The plain objects must include at least the `glob` property, which holds the glob pattern string.
|
|
27
|
+
* All remaining keys will be used as request options for the corresponding enqueued {@link Request} objects.
|
|
28
|
+
*
|
|
29
|
+
* The matching is always case-insensitive.
|
|
30
|
+
* If you need case-sensitive matching, use `regexps` property directly.
|
|
31
|
+
*
|
|
32
|
+
* If `globs` is an empty array or `undefined`, then the function
|
|
33
|
+
* enqueues all the intercepted navigation requests produced by the page
|
|
34
|
+
* after clicking on elements matching the provided CSS selector.
|
|
35
|
+
*/
|
|
36
|
+
globs?: GlobInput[];
|
|
37
|
+
/**
|
|
38
|
+
* An array of regular expressions or plain objects
|
|
39
|
+
* containing regular expressions matching the URLs to be enqueued.
|
|
40
|
+
*
|
|
41
|
+
* The plain objects must include at least the `regexp` property, which holds the regular expression.
|
|
42
|
+
* All remaining keys will be used as request options for the corresponding enqueued {@link Request} objects.
|
|
43
|
+
*
|
|
44
|
+
* If `regexps` is an empty array or `undefined`, then the function
|
|
45
|
+
* enqueues all the intercepted navigation requests produced by the page
|
|
46
|
+
* after clicking on elements matching the provided CSS selector.
|
|
47
|
+
*/
|
|
48
|
+
regexps?: RegExpInput[];
|
|
49
|
+
/**
|
|
50
|
+
* *NOTE:* In future versions of SDK the options will be removed.
|
|
51
|
+
* Please use `globs` or `regexps` instead.
|
|
52
|
+
*
|
|
53
|
+
* An array of {@link PseudoUrl} strings or plain objects
|
|
54
|
+
* containing {@link PseudoUrl} strings matching the URLs to be enqueued.
|
|
55
|
+
*
|
|
56
|
+
* The plain objects must include at least the `purl` property, which holds the pseudo-URL pattern string.
|
|
57
|
+
* All remaining keys will be used as request options for the corresponding enqueued {@link Request} objects.
|
|
58
|
+
*
|
|
59
|
+
* With a pseudo-URL string, the matching is always case-insensitive.
|
|
60
|
+
* If you need case-sensitive matching, use `regexps` property directly.
|
|
61
|
+
*
|
|
62
|
+
* If `pseudoUrls` is an empty array or `undefined`, then the function
|
|
63
|
+
* enqueues all the intercepted navigation requests produced by the page
|
|
64
|
+
* after clicking on elements matching the provided CSS selector.
|
|
65
|
+
*
|
|
66
|
+
* @deprecated prefer using `globs` or `regexps` instead
|
|
67
|
+
*/
|
|
68
|
+
pseudoUrls?: PseudoUrlInput[];
|
|
69
|
+
/**
|
|
70
|
+
* Just before a new {@link Request} is constructed and enqueued to the {@link RequestQueue}, this function can be used
|
|
71
|
+
* to remove it or modify its contents such as `userData`, `payload` or, most importantly `uniqueKey`. This is useful
|
|
72
|
+
* when you need to enqueue multiple `Requests` to the queue that share the same URL, but differ in methods or payloads,
|
|
73
|
+
* or to dynamically update or create `userData`.
|
|
74
|
+
*
|
|
75
|
+
* For example: by adding `useExtendedUniqueKey: true` to the `request` object, `uniqueKey` will be computed from
|
|
76
|
+
* a combination of `url`, `method` and `payload` which enables crawling of websites that navigate using form submits
|
|
77
|
+
* (POST requests).
|
|
78
|
+
*
|
|
79
|
+
* **Example:**
|
|
80
|
+
* ```javascript
|
|
81
|
+
* {
|
|
82
|
+
* transformRequestFunction: (request) => {
|
|
83
|
+
* request.userData.foo = 'bar';
|
|
84
|
+
* request.useExtendedUniqueKey = true;
|
|
85
|
+
* return request;
|
|
86
|
+
* }
|
|
87
|
+
* }
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
transformRequestFunction?: RequestTransform;
|
|
91
|
+
/**
|
|
92
|
+
* Clicking in the page triggers various asynchronous operations that lead to new URLs being shown
|
|
93
|
+
* by the browser. It could be a simple JavaScript redirect or opening of a new tab in the browser.
|
|
94
|
+
* These events often happen only some time after the actual click. Requests typically take milliseconds
|
|
95
|
+
* while new tabs open in hundreds of milliseconds.
|
|
96
|
+
*
|
|
97
|
+
* To be able to capture all those events, the `enqueueLinksByClickingElements()` function repeatedly waits
|
|
98
|
+
* for the `waitForPageIdleSecs`. By repeatedly we mean that whenever a relevant event is triggered, the timer
|
|
99
|
+
* is restarted. As long as new events keep coming, the function will not return, unless
|
|
100
|
+
* the below `maxWaitForPageIdleSecs` timeout is reached.
|
|
101
|
+
*
|
|
102
|
+
* You may want to reduce this for example when you're sure that your clicks do not open new tabs,
|
|
103
|
+
* or increase when you're not getting all the expected URLs.
|
|
104
|
+
* @default 1
|
|
105
|
+
*/
|
|
106
|
+
waitForPageIdleSecs?: number;
|
|
107
|
+
/**
|
|
108
|
+
* This is the maximum period for which the function will keep tracking events, even if more events keep coming.
|
|
109
|
+
* Its purpose is to prevent a deadlock in the page by periodic events, often unrelated to the clicking itself.
|
|
110
|
+
* See `waitForPageIdleSecs` above for an explanation.
|
|
111
|
+
* @default 5
|
|
112
|
+
*/
|
|
113
|
+
maxWaitForPageIdleSecs?: number;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The function finds elements matching a specific CSS selector in a Puppeteer page,
|
|
117
|
+
* clicks all those elements using a mouse move and a left mouse button click and intercepts
|
|
118
|
+
* all the navigation requests that are subsequently produced by the page. The intercepted
|
|
119
|
+
* requests, including their methods, headers and payloads are then enqueued to a provided
|
|
120
|
+
* {@link RequestQueue}. This is useful to crawl JavaScript heavy pages where links are not available
|
|
121
|
+
* in `href` elements, but rather navigations are triggered in click handlers.
|
|
122
|
+
* If you're looking to find URLs in `href` attributes of the page, see {@link enqueueLinks}.
|
|
123
|
+
*
|
|
124
|
+
* Optionally, the function allows you to filter the target links' URLs using an array of {@link PseudoUrl} objects
|
|
125
|
+
* and override settings of the enqueued {@link Request} objects.
|
|
126
|
+
*
|
|
127
|
+
* **IMPORTANT**: To be able to do this, this function uses various mutations on the page,
|
|
128
|
+
* such as changing the Z-index of elements being clicked and their visibility. Therefore,
|
|
129
|
+
* it is recommended to only use this function as the last operation in the page.
|
|
130
|
+
*
|
|
131
|
+
* **USING HEADFUL BROWSER**: When using a headful browser, this function will only be able to click elements
|
|
132
|
+
* in the focused tab, effectively limiting concurrency to 1. In headless mode, full concurrency can be achieved.
|
|
133
|
+
*
|
|
134
|
+
* **PERFORMANCE**: Clicking elements with a mouse and intercepting requests is not a low level operation
|
|
135
|
+
* that takes nanoseconds. It's not very CPU intensive, but it takes time. We strongly recommend limiting
|
|
136
|
+
* the scope of the clicking as much as possible by using a specific selector that targets only the elements
|
|
137
|
+
* that you assume or know will produce a navigation. You can certainly click everything by using
|
|
138
|
+
* the `*` selector, but be prepared to wait minutes to get results on a large and complex page.
|
|
139
|
+
*
|
|
140
|
+
* **Example usage**
|
|
141
|
+
*
|
|
142
|
+
* ```javascript
|
|
143
|
+
* await Actor.utils.puppeteer.enqueueLinksByClickingElements({
|
|
144
|
+
* page,
|
|
145
|
+
* requestQueue,
|
|
146
|
+
* selector: 'a.product-detail',
|
|
147
|
+
* pseudoUrls: [
|
|
148
|
+
* 'https://www.example.com/handbags/[.*]'
|
|
149
|
+
* 'https://www.example.com/purses/[.*]'
|
|
150
|
+
* ],
|
|
151
|
+
* });
|
|
152
|
+
* ```
|
|
153
|
+
*
|
|
154
|
+
* @returns Promise that resolves to {@link BatchAddRequestsResult} object.
|
|
155
|
+
*/
|
|
156
|
+
export declare function enqueueLinksByClickingElements(options: EnqueueLinksByClickingElementsOptions): Promise<storage.BatchAddRequestsResult>;
|
|
157
|
+
interface WaitForPageIdleOptions {
|
|
158
|
+
page: Page;
|
|
159
|
+
waitForPageIdleMillis?: number;
|
|
160
|
+
maxWaitForPageIdleMillis?: number;
|
|
161
|
+
}
|
|
162
|
+
interface ClickElementsAndInterceptNavigationRequestsOptions extends WaitForPageIdleOptions {
|
|
163
|
+
selector: string;
|
|
164
|
+
clickOptions?: ClickOptions;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Clicks all elements of given page matching given selector.
|
|
168
|
+
* Catches and intercepts all initiated navigation requests and opened pages.
|
|
169
|
+
* Returns a list of all target URLs.
|
|
170
|
+
* @ignore
|
|
171
|
+
*/
|
|
172
|
+
export declare function clickElementsAndInterceptNavigationRequests(options: ClickElementsAndInterceptNavigationRequestsOptions): Promise<Dictionary[]>;
|
|
173
|
+
/**
|
|
174
|
+
* We're only interested in pages created by the page we're currently clicking in.
|
|
175
|
+
* There will generally be a lot of other targets being created in the browser.
|
|
176
|
+
*/
|
|
177
|
+
export declare function isTargetRelevant(page: Page, target: Target): boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Click all elements matching the given selector. To be able to do this using
|
|
180
|
+
* Puppeteer's `.click()` we need to make sure the elements are reachable by mouse,
|
|
181
|
+
* so we first move them to the top of the page's stacking context and then click.
|
|
182
|
+
* We do all in series to prevent elements from hiding one another. Therefore,
|
|
183
|
+
* for large element sets, this will take considerable amount of time.
|
|
184
|
+
* @ignore
|
|
185
|
+
*/
|
|
186
|
+
export declare function clickElements(page: Page, selector: string, clickOptions?: ClickOptions): Promise<void>;
|
|
187
|
+
export {};
|
|
188
|
+
//# sourceMappingURL=click-elements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"click-elements.d.ts","sourceRoot":"","sources":["../../../src/internals/enqueue-links/click-elements.ts"],"names":[],"mappings":"AAAA,OAAO,EAMH,SAAS,EACT,cAAc,EACd,WAAW,EACX,gBAAgB,EAEhB,YAAY,EACZ,OAAO,EACV,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,OAAO,EAGH,YAAY,EAGZ,IAAI,EAEJ,MAAM,EACT,MAAM,WAAW,CAAC;AAOnB,MAAM,WAAW,qCAAqC;IAClD;;OAEG;IACH,IAAI,EAAE,IAAI,CAAC;IAEX;;OAEG;IACH,YAAY,EAAE,YAAY,CAAC;IAE3B;;;OAGG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,YAAY,CAAC,EAAE,YAAY,CAAC;IAE5B;;;;;;;;;;;;;OAaG;IACH,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC;IAEpB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IAExB;;;;;;;;;;;;;;;;;;OAkBG;IACH,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAE9B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,wBAAwB,CAAC,EAAE,gBAAgB,CAAC;IAE5C;;;;;;;;;;;;;;OAcG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAsB,8BAA8B,CAAC,OAAO,EAAE,qCAAqC,GAAG,OAAO,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAmE5I;AAED,UAAU,sBAAsB;IAC5B,IAAI,EAAE,IAAI,CAAC;IACX,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED,UAAU,kDAAmD,SAAQ,sBAAsB;IACvF,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAsB,2CAA2C,CAAC,OAAO,EAAE,kDAAkD,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAiCpJ;AAoDD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAGpE;AAiDD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB5G"}
|
|
@@ -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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"}
|