@letsscrapedata/controller 0.0.52 → 0.0.54
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/dist/index.cjs +2003 -130
- package/dist/index.d.cts +37 -23
- package/dist/index.d.ts +37 -23
- package/dist/index.js +2005 -132
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -931,6 +931,18 @@ var PlaywrightPage = class extends import_node_events.default {
|
|
|
931
931
|
const buffer = await this.#page.pdf(options);
|
|
932
932
|
return buffer;
|
|
933
933
|
}
|
|
934
|
+
async reload() {
|
|
935
|
+
if (!this.#page) {
|
|
936
|
+
throw new Error("No valid page");
|
|
937
|
+
}
|
|
938
|
+
try {
|
|
939
|
+
await this.#page.reload();
|
|
940
|
+
return true;
|
|
941
|
+
} catch (err) {
|
|
942
|
+
loginfo(err);
|
|
943
|
+
return false;
|
|
944
|
+
}
|
|
945
|
+
}
|
|
934
946
|
async screenshot(options) {
|
|
935
947
|
if (!this.#page) {
|
|
936
948
|
throw new Error("No valid page");
|
|
@@ -1650,7 +1662,11 @@ var PlaywrightBrowserContext = class extends import_node_events2.default {
|
|
|
1650
1662
|
};
|
|
1651
1663
|
|
|
1652
1664
|
// src/playwright/browser.ts
|
|
1653
|
-
var PlaywrightBrowser = class extends import_node_events3.default {
|
|
1665
|
+
var PlaywrightBrowser = class _PlaywrightBrowser extends import_node_events3.default {
|
|
1666
|
+
static #supportedBrowserTypes = ["chromium", "firefox", "webkit"];
|
|
1667
|
+
static doesSupport(browserType) {
|
|
1668
|
+
return _PlaywrightBrowser.#supportedBrowserTypes.includes(browserType);
|
|
1669
|
+
}
|
|
1654
1670
|
#browser;
|
|
1655
1671
|
#browserIdx;
|
|
1656
1672
|
#pid;
|
|
@@ -1679,7 +1695,7 @@ var PlaywrightBrowser = class extends import_node_events3.default {
|
|
|
1679
1695
|
return this.#options.maxPageFreeSeconds ? this.#options.maxPageFreeSeconds : 900;
|
|
1680
1696
|
}
|
|
1681
1697
|
// constructor: called only by LsdBrowserController.launch/connect
|
|
1682
|
-
constructor(browser,
|
|
1698
|
+
constructor(browser, browserType, browserCreateMethod, options, browserIdx = 0, pid = 0) {
|
|
1683
1699
|
if (!browser || typeof browser.contexts !== "function") {
|
|
1684
1700
|
throw new Error(`Invalid playwright browser parameter`);
|
|
1685
1701
|
}
|
|
@@ -1691,7 +1707,10 @@ var PlaywrightBrowser = class extends import_node_events3.default {
|
|
|
1691
1707
|
this.#createTime = (0, import_utils5.getCurrentUnixTime)();
|
|
1692
1708
|
this.#lsdBrowserContexts = [];
|
|
1693
1709
|
this.#browserControllerType = "playwright";
|
|
1694
|
-
this.#browserType =
|
|
1710
|
+
this.#browserType = browserType;
|
|
1711
|
+
if (!_PlaywrightBrowser.#supportedBrowserTypes.includes(browserType)) {
|
|
1712
|
+
throw new Error(`Browser controller ${this.#browserControllerType} doesnot support browserType ${browserType}`);
|
|
1713
|
+
}
|
|
1695
1714
|
this.#browserCreationMethod = browserCreateMethod;
|
|
1696
1715
|
this.#headless = headless;
|
|
1697
1716
|
this.#proxy = options?.proxy ? Object.assign({}, options.proxy) : null;
|
|
@@ -2644,6 +2663,18 @@ var PuppeteerPage = class extends import_node_events4.default {
|
|
|
2644
2663
|
const buffer = await this.#page.pdf(options);
|
|
2645
2664
|
return buffer;
|
|
2646
2665
|
}
|
|
2666
|
+
async reload() {
|
|
2667
|
+
if (!this.#page) {
|
|
2668
|
+
throw new Error("No valid page");
|
|
2669
|
+
}
|
|
2670
|
+
try {
|
|
2671
|
+
await this.#page.reload();
|
|
2672
|
+
return true;
|
|
2673
|
+
} catch (err) {
|
|
2674
|
+
loginfo(err);
|
|
2675
|
+
return false;
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2647
2678
|
async screenshot(options) {
|
|
2648
2679
|
if (!this.#page) {
|
|
2649
2680
|
throw new Error("No valid page");
|
|
@@ -3331,7 +3362,11 @@ var PuppeteerBrowserContext = class extends import_node_events5.default {
|
|
|
3331
3362
|
};
|
|
3332
3363
|
|
|
3333
3364
|
// src/puppeteer/browser.ts
|
|
3334
|
-
var PuppeteerBrowser = class extends import_node_events6.default {
|
|
3365
|
+
var PuppeteerBrowser = class _PuppeteerBrowser extends import_node_events6.default {
|
|
3366
|
+
static #supportedBrowserTypes = ["chromium"];
|
|
3367
|
+
static doesSupport(browserType) {
|
|
3368
|
+
return _PuppeteerBrowser.#supportedBrowserTypes.includes(browserType);
|
|
3369
|
+
}
|
|
3335
3370
|
#browser;
|
|
3336
3371
|
#browserIdx;
|
|
3337
3372
|
#pid;
|
|
@@ -3363,7 +3398,7 @@ var PuppeteerBrowser = class extends import_node_events6.default {
|
|
|
3363
3398
|
return this.#options.userAgent ? this.#options.userAgent : "";
|
|
3364
3399
|
}
|
|
3365
3400
|
// constructor: called only by LsdBrowserController.launch/connect
|
|
3366
|
-
constructor(browser,
|
|
3401
|
+
constructor(browser, browserType, browserCreateMethod, options, browserIdx = 0, pid = 0) {
|
|
3367
3402
|
if (!browser || typeof browser.browserContexts !== "function") {
|
|
3368
3403
|
throw new Error(`Invalid puppeteer browser parameter`);
|
|
3369
3404
|
}
|
|
@@ -3375,7 +3410,10 @@ var PuppeteerBrowser = class extends import_node_events6.default {
|
|
|
3375
3410
|
this.#createTime = (0, import_utils9.getCurrentUnixTime)();
|
|
3376
3411
|
this.#lsdBrowserContexts = [];
|
|
3377
3412
|
this.#browserControllerType = "puppeteer";
|
|
3378
|
-
this.#browserType =
|
|
3413
|
+
this.#browserType = browserType;
|
|
3414
|
+
if (!_PuppeteerBrowser.#supportedBrowserTypes.includes(browserType)) {
|
|
3415
|
+
throw new Error(`Browser controller ${this.#browserControllerType} doesnot support browserType ${browserType}`);
|
|
3416
|
+
}
|
|
3379
3417
|
this.#browserCreationMethod = browserCreateMethod;
|
|
3380
3418
|
this.#headless = headless;
|
|
3381
3419
|
this.#proxy = options?.proxy ? Object.assign({}, options.proxy) : null;
|
|
@@ -3799,6 +3837,9 @@ var CheerioPage = class extends import_node_events7.default {
|
|
|
3799
3837
|
async pdf() {
|
|
3800
3838
|
throw new Error("Not supported in CheerioPage.");
|
|
3801
3839
|
}
|
|
3840
|
+
async reload() {
|
|
3841
|
+
throw new Error("Not supported in CheerioPage.");
|
|
3842
|
+
}
|
|
3802
3843
|
async screenshot() {
|
|
3803
3844
|
throw new Error("Not supported in CheerioPage.");
|
|
3804
3845
|
}
|
|
@@ -3871,148 +3912,1934 @@ var CheerioPage = class extends import_node_events7.default {
|
|
|
3871
3912
|
var import_os = __toESM(require("os"), 1);
|
|
3872
3913
|
var import_puppeteer = __toESM(require("puppeteer"), 1);
|
|
3873
3914
|
var import_playwright = __toESM(require("playwright"), 1);
|
|
3874
|
-
var
|
|
3875
|
-
|
|
3876
|
-
|
|
3915
|
+
var import_patchright = __toESM(require("patchright"), 1);
|
|
3916
|
+
|
|
3917
|
+
// src/patchright/browser.ts
|
|
3918
|
+
var import_node_events10 = __toESM(require("events"), 1);
|
|
3919
|
+
var import_utils13 = require("@letsscrapedata/utils");
|
|
3920
|
+
|
|
3921
|
+
// src/patchright/context.ts
|
|
3922
|
+
var import_node_events9 = __toESM(require("events"), 1);
|
|
3923
|
+
var import_utils12 = require("@letsscrapedata/utils");
|
|
3924
|
+
|
|
3925
|
+
// src/patchright/page.ts
|
|
3926
|
+
var import_node_events8 = __toESM(require("events"), 1);
|
|
3927
|
+
var import_utils11 = require("@letsscrapedata/utils");
|
|
3928
|
+
|
|
3929
|
+
// src/patchright/element.ts
|
|
3877
3930
|
var import_utils10 = require("@letsscrapedata/utils");
|
|
3878
|
-
var
|
|
3879
|
-
|
|
3880
|
-
#
|
|
3881
|
-
|
|
3882
|
-
|
|
3883
|
-
|
|
3884
|
-
* Possible values are 'aix', 'darwin', 'freebsd','linux', 'openbsd', 'sunos', and 'win32'.
|
|
3885
|
-
*/
|
|
3886
|
-
#osPlatform;
|
|
3887
|
-
constructor() {
|
|
3888
|
-
if (_LsdBrowserController.#forbidConstructor) {
|
|
3889
|
-
throw new Error("Only one LsdBrowserController instance can be created!");
|
|
3931
|
+
var PatchrightElement = class _PatchrightElement {
|
|
3932
|
+
#frame;
|
|
3933
|
+
#locator;
|
|
3934
|
+
constructor(locator, frame) {
|
|
3935
|
+
if (!frame.locator || !locator.click) {
|
|
3936
|
+
throw new Error("Invalid paras in new PatchrightElement");
|
|
3890
3937
|
}
|
|
3891
|
-
this.#
|
|
3892
|
-
|
|
3893
|
-
this.#playwrightBrowserTypes = { chromium: chromium2, firefox: firefox2, webkit: webkit2 };
|
|
3894
|
-
this.#osPlatform = import_os.default.platform();
|
|
3895
|
-
this.#nextBrowserIdx = 1;
|
|
3896
|
-
_LsdBrowserController.#forbidConstructor = true;
|
|
3938
|
+
this.#frame = frame;
|
|
3939
|
+
this.#locator = locator;
|
|
3897
3940
|
}
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
} else if (connectFlag) {
|
|
3902
|
-
throw new Error(`playwright only can connect to chromium browser, not support ${browserType} browser`);
|
|
3903
|
-
} else if (browserType === "firefox") {
|
|
3904
|
-
return this.#playwrightBrowserTypes.firefox;
|
|
3905
|
-
} else if (browserType === "webkit") {
|
|
3906
|
-
return this.#playwrightBrowserTypes.webkit;
|
|
3907
|
-
} else {
|
|
3908
|
-
throw new Error(`Invalid playwright browserType ${browserType}`);
|
|
3909
|
-
}
|
|
3941
|
+
async attribute(attributeName) {
|
|
3942
|
+
const attributeValue = await this.#locator.getAttribute(attributeName);
|
|
3943
|
+
return attributeValue ? attributeValue : "";
|
|
3910
3944
|
}
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3945
|
+
async attributeNames() {
|
|
3946
|
+
const names = await this.#locator.evaluate((node) => node.getAttributeNames());
|
|
3947
|
+
return names;
|
|
3948
|
+
}
|
|
3949
|
+
async dataset() {
|
|
3950
|
+
try {
|
|
3951
|
+
const dataset = await this.#locator.evaluate((node) => node.dataset);
|
|
3952
|
+
return dataset;
|
|
3953
|
+
} catch (err) {
|
|
3954
|
+
return {};
|
|
3916
3955
|
}
|
|
3917
3956
|
}
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3957
|
+
async evaluate(func, args) {
|
|
3958
|
+
try {
|
|
3959
|
+
const frame = this.#frame;
|
|
3960
|
+
;
|
|
3961
|
+
if (typeof frame.parentFrame === "function") {
|
|
3962
|
+
return await frame.evaluate(func, args);
|
|
3963
|
+
} else {
|
|
3964
|
+
const locator = this.#frame.owner();
|
|
3965
|
+
return await locator.evaluate(func, args);
|
|
3966
|
+
}
|
|
3967
|
+
} catch (err) {
|
|
3968
|
+
logerr(err);
|
|
3969
|
+
return "";
|
|
3923
3970
|
}
|
|
3924
|
-
return true;
|
|
3925
3971
|
}
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3972
|
+
/*
|
|
3973
|
+
async #getChildFrame(parentFrame: Frame, iframeOption: IframeOption): Promise<Frame | null> {
|
|
3974
|
+
if (!parentFrame) {
|
|
3975
|
+
throw new Error("Invalid parent frame");
|
|
3976
|
+
}
|
|
3977
|
+
|
|
3978
|
+
let { src = "" } = iframeOption;
|
|
3979
|
+
if (!src) {
|
|
3980
|
+
throw new Error("Invalid src in IframeOption");
|
|
3981
|
+
}
|
|
3982
|
+
|
|
3983
|
+
// src: use childFrames()
|
|
3984
|
+
const childFrames = parentFrame.childFrames();
|
|
3985
|
+
for (const childFrame of childFrames) {
|
|
3986
|
+
const url = childFrame.url();
|
|
3987
|
+
if (typeof src === "string") {
|
|
3988
|
+
// src: string
|
|
3989
|
+
if (url.startsWith(src)) {
|
|
3990
|
+
return childFrame;
|
|
3991
|
+
} else if (url.toLowerCase().startsWith(src)) {
|
|
3992
|
+
return childFrame;
|
|
3993
|
+
}
|
|
3931
3994
|
} else {
|
|
3932
|
-
|
|
3995
|
+
// src: RegExp
|
|
3996
|
+
if (url.match(src)) {
|
|
3997
|
+
return childFrame;
|
|
3998
|
+
}
|
|
3933
3999
|
}
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
4000
|
+
}
|
|
4001
|
+
|
|
4002
|
+
return null;
|
|
4003
|
+
}
|
|
4004
|
+
*/
|
|
4005
|
+
async #getChildFrameLocator(parent, iframeOption) {
|
|
4006
|
+
return parent.frameLocator(getIframeSelector(iframeOption));
|
|
4007
|
+
}
|
|
4008
|
+
async #getDescendantFrame(parent, iframeOptions) {
|
|
4009
|
+
try {
|
|
4010
|
+
if (iframeOptions.length <= 0) {
|
|
4011
|
+
return null;
|
|
4012
|
+
}
|
|
4013
|
+
let frameLocator = parent.frameLocator(getIframeSelector(iframeOptions[0]));
|
|
4014
|
+
for (const iframeOption of iframeOptions.slice(1)) {
|
|
4015
|
+
if (!frameLocator) {
|
|
4016
|
+
return null;
|
|
3940
4017
|
}
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
4018
|
+
frameLocator = await this.#getChildFrameLocator(frameLocator, iframeOption);
|
|
4019
|
+
}
|
|
4020
|
+
return frameLocator;
|
|
4021
|
+
} catch (err) {
|
|
4022
|
+
throw new Error(`No child iframe: ${JSON.stringify(iframeOptions)}`);
|
|
4023
|
+
}
|
|
4024
|
+
}
|
|
4025
|
+
async #findElementHandles(selector, absolute = false, iframeOptions = []) {
|
|
4026
|
+
let parent = absolute ? this.#frame : this.#locator;
|
|
4027
|
+
let frame = this.#frame;
|
|
4028
|
+
const retObj = { frame, locators: [] };
|
|
4029
|
+
if (iframeOptions.length > 0) {
|
|
4030
|
+
const childFrame = await this.#getDescendantFrame(frame, iframeOptions);
|
|
4031
|
+
if (!childFrame) {
|
|
4032
|
+
return retObj;
|
|
4033
|
+
}
|
|
4034
|
+
retObj.frame = childFrame;
|
|
4035
|
+
parent = childFrame;
|
|
4036
|
+
}
|
|
4037
|
+
try {
|
|
4038
|
+
let locators = [];
|
|
4039
|
+
if (selector.startsWith("./") || selector.startsWith("/") || selector.startsWith("..")) {
|
|
4040
|
+
locators = await parent.locator(`xpath=${selector}`).all();
|
|
4041
|
+
} else {
|
|
4042
|
+
if (selector !== ".") {
|
|
4043
|
+
locators = await parent.locator(selector).all();
|
|
3945
4044
|
} else {
|
|
3946
|
-
|
|
4045
|
+
locators = [this.#locator];
|
|
3947
4046
|
}
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
4047
|
+
}
|
|
4048
|
+
retObj.locators = locators;
|
|
4049
|
+
return retObj;
|
|
4050
|
+
} catch (err) {
|
|
4051
|
+
loginfo(err);
|
|
4052
|
+
return retObj;
|
|
3951
4053
|
}
|
|
3952
|
-
return true;
|
|
3953
4054
|
}
|
|
3954
|
-
async
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
maxPagesPerBrowserContext = 20,
|
|
3959
|
-
maxPageFreeSeconds = 900,
|
|
3960
|
-
maxViewportOfNewPage = true,
|
|
3961
|
-
proxy = null,
|
|
3962
|
-
timeout = 3e4,
|
|
3963
|
-
args = [],
|
|
3964
|
-
executablePath = "",
|
|
3965
|
-
maxWindowSize = true,
|
|
3966
|
-
headless = true,
|
|
3967
|
-
minBrowserContexts = 1,
|
|
3968
|
-
// incognito
|
|
3969
|
-
proxyPerBrowserContext = false,
|
|
3970
|
-
userDataDir = "",
|
|
3971
|
-
userAgent = ""
|
|
3972
|
-
} = options ? options : {};
|
|
3973
|
-
let browserPid = 0;
|
|
3974
|
-
const incognito = typeof options?.incognito === "boolean" ? options.incognito : browserControllerType === "puppeteer" ? false : true;
|
|
3975
|
-
const actOptions = { closeFreePagesIntervalSeconds, maxBrowserContextsPerBrowser, maxPagesPerBrowserContext, maxPageFreeSeconds, maxViewportOfNewPage, proxy, timeout, args, executablePath, maxWindowSize, headless, minBrowserContexts, incognito, proxyPerBrowserContext, userDataDir, userAgent };
|
|
3976
|
-
let idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--incoginto"));
|
|
3977
|
-
if (idx >= 0) {
|
|
3978
|
-
logwarn(`Please use options.incognito instead when launching new browser.`);
|
|
3979
|
-
args.splice(idx, 1);
|
|
3980
|
-
}
|
|
3981
|
-
idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--proxy-server"));
|
|
3982
|
-
if (idx >= 0) {
|
|
3983
|
-
logwarn(`Please use options.proxy instead when launching new browser.`);
|
|
3984
|
-
args.splice(idx, 1);
|
|
4055
|
+
async findElement(selectorOrXpath, iframeOptions = [], absolute = false) {
|
|
4056
|
+
const selectors = typeof selectorOrXpath === "string" ? [selectorOrXpath] : selectorOrXpath;
|
|
4057
|
+
if (!Array.isArray(selectors)) {
|
|
4058
|
+
throw new Error(`Invalid selectorOrXpath ${selectorOrXpath} in findElement`);
|
|
3985
4059
|
}
|
|
3986
|
-
|
|
3987
|
-
|
|
3988
|
-
|
|
3989
|
-
|
|
4060
|
+
for (const selector of selectors) {
|
|
4061
|
+
const { frame, locators } = await this.#findElementHandles(selector, absolute, iframeOptions);
|
|
4062
|
+
if (locators.length > 0) {
|
|
4063
|
+
const playwrightElement = new _PatchrightElement(locators[0], frame);
|
|
4064
|
+
return playwrightElement;
|
|
4065
|
+
}
|
|
3990
4066
|
}
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
4067
|
+
return null;
|
|
4068
|
+
}
|
|
4069
|
+
async findElements(selectorOrXpath, iframeOptions = [], absolute = false) {
|
|
4070
|
+
const selectors = typeof selectorOrXpath === "string" ? [selectorOrXpath] : selectorOrXpath;
|
|
4071
|
+
if (!Array.isArray(selectors)) {
|
|
4072
|
+
throw new Error(`Invalid selectorOrXpath ${selectorOrXpath} in findElements`);
|
|
3995
4073
|
}
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
}
|
|
4002
|
-
if (maxWindowSize) {
|
|
4003
|
-
args.push("--start-maximized");
|
|
4004
|
-
}
|
|
4005
|
-
if (proxy?.proxyUrl && proxy.proxyUrl !== "local") {
|
|
4006
|
-
const { proxyUrl: server, username, password } = proxy;
|
|
4007
|
-
launchOptions.proxy = { server, username, password };
|
|
4008
|
-
} else if (proxyPerBrowserContext && browserType === "chromium" && this.#osPlatform.startsWith("win")) {
|
|
4009
|
-
launchOptions.proxy = { server: "proxyPerBrowserContext" };
|
|
4074
|
+
for (const selector of selectors) {
|
|
4075
|
+
const { frame, locators } = await this.#findElementHandles(selector, absolute, iframeOptions);
|
|
4076
|
+
if (locators.length > 0) {
|
|
4077
|
+
const playwrightElements = locators.map((locator) => new _PatchrightElement(locator, frame));
|
|
4078
|
+
return playwrightElements;
|
|
4010
4079
|
}
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4080
|
+
}
|
|
4081
|
+
return [];
|
|
4082
|
+
}
|
|
4083
|
+
async hasAttribute(attributeName) {
|
|
4084
|
+
const hasFlag = await this.#locator.evaluate((node, attr) => node.hasAttribute(attr), attributeName);
|
|
4085
|
+
return hasFlag;
|
|
4086
|
+
}
|
|
4087
|
+
async innerHtml() {
|
|
4088
|
+
const html = await this.#locator.innerHTML();
|
|
4089
|
+
return html;
|
|
4090
|
+
}
|
|
4091
|
+
async innerText(onlyChild = false) {
|
|
4092
|
+
let text = "";
|
|
4093
|
+
if (onlyChild) {
|
|
4094
|
+
text = await this.#locator.evaluate((node) => {
|
|
4095
|
+
let child = node.firstChild;
|
|
4096
|
+
let texts = [];
|
|
4097
|
+
while (child) {
|
|
4098
|
+
if (child.nodeType == 3) {
|
|
4099
|
+
texts.push(child.data);
|
|
4100
|
+
}
|
|
4101
|
+
child = child.nextSibling;
|
|
4102
|
+
}
|
|
4103
|
+
return texts.join(" ");
|
|
4104
|
+
});
|
|
4105
|
+
} else {
|
|
4106
|
+
text = await this.#locator.innerText();
|
|
4107
|
+
}
|
|
4108
|
+
return text;
|
|
4109
|
+
}
|
|
4110
|
+
async outerHtml() {
|
|
4111
|
+
const html = await this.#locator.evaluate((node) => node.outerHTML);
|
|
4112
|
+
return html;
|
|
4113
|
+
}
|
|
4114
|
+
async textContent() {
|
|
4115
|
+
const text = await this.#locator.textContent();
|
|
4116
|
+
return text ? text : "";
|
|
4117
|
+
}
|
|
4118
|
+
async click(options = {}) {
|
|
4119
|
+
const { button, clickCount: count, delay, position: offset, clickType = "click" } = options;
|
|
4120
|
+
const actOptions = { button, count, delay, offset };
|
|
4121
|
+
if (clickType === "click") {
|
|
4122
|
+
await this.#locator.click(actOptions);
|
|
4123
|
+
} else if (clickType === "evaluate") {
|
|
4124
|
+
await this.#locator.evaluate(async (ev) => await ev.click());
|
|
4125
|
+
} else {
|
|
4126
|
+
(0, import_utils10.unreachable)(clickType);
|
|
4127
|
+
}
|
|
4128
|
+
return true;
|
|
4129
|
+
}
|
|
4130
|
+
async focus() {
|
|
4131
|
+
await this.#locator.focus();
|
|
4132
|
+
return true;
|
|
4133
|
+
}
|
|
4134
|
+
async hover() {
|
|
4135
|
+
await this.#locator.hover();
|
|
4136
|
+
return true;
|
|
4137
|
+
}
|
|
4138
|
+
async input(value, options = {}) {
|
|
4139
|
+
const { delay = 0, replace = false, enter = false } = options;
|
|
4140
|
+
if (replace) {
|
|
4141
|
+
await this.#locator.click({ button: "left", clickCount: 3 });
|
|
4142
|
+
}
|
|
4143
|
+
if (delay > 0) {
|
|
4144
|
+
await this.#locator.fill(value);
|
|
4145
|
+
} else {
|
|
4146
|
+
await this.#locator.fill(value);
|
|
4147
|
+
}
|
|
4148
|
+
if (enter) {
|
|
4149
|
+
await this.#locator.press("Enter");
|
|
4150
|
+
}
|
|
4151
|
+
return true;
|
|
4152
|
+
}
|
|
4153
|
+
async press(key, options = {}) {
|
|
4154
|
+
await this.#locator.press(key, options);
|
|
4155
|
+
return true;
|
|
4156
|
+
}
|
|
4157
|
+
async screenshot(options) {
|
|
4158
|
+
return await this.#locator.screenshot(options);
|
|
4159
|
+
}
|
|
4160
|
+
async scrollIntoView() {
|
|
4161
|
+
await this.#locator.scrollIntoViewIfNeeded();
|
|
4162
|
+
return true;
|
|
4163
|
+
}
|
|
4164
|
+
async select(options) {
|
|
4165
|
+
const { type, values = [], labels = [], indexes = [] } = options;
|
|
4166
|
+
switch (type) {
|
|
4167
|
+
case "value":
|
|
4168
|
+
if (values.length > 0) {
|
|
4169
|
+
await this.#locator.selectOption(values);
|
|
4170
|
+
}
|
|
4171
|
+
break;
|
|
4172
|
+
case "label":
|
|
4173
|
+
if (labels.length > 0) {
|
|
4174
|
+
await this.#locator.selectOption(labels.map((label) => {
|
|
4175
|
+
return { label };
|
|
4176
|
+
}));
|
|
4177
|
+
}
|
|
4178
|
+
break;
|
|
4179
|
+
case "index":
|
|
4180
|
+
if (indexes.length > 0) {
|
|
4181
|
+
const indexValues = await this.#locator.evaluate(
|
|
4182
|
+
(node, indexes2) => {
|
|
4183
|
+
const options2 = node.options;
|
|
4184
|
+
const len = options2.length;
|
|
4185
|
+
const vals = [];
|
|
4186
|
+
for (const index of indexes2.filter((i) => i >= 0 && i < len)) {
|
|
4187
|
+
vals.push(options2[index].value);
|
|
4188
|
+
}
|
|
4189
|
+
return vals;
|
|
4190
|
+
},
|
|
4191
|
+
indexes
|
|
4192
|
+
);
|
|
4193
|
+
if (indexValues.length > 0) {
|
|
4194
|
+
await this.#locator.selectOption(indexValues);
|
|
4195
|
+
}
|
|
4196
|
+
}
|
|
4197
|
+
break;
|
|
4198
|
+
default:
|
|
4199
|
+
(0, import_utils10.unreachable)(type);
|
|
4200
|
+
}
|
|
4201
|
+
return true;
|
|
4202
|
+
}
|
|
4203
|
+
async setAttribute(attributeName, newValue) {
|
|
4204
|
+
await this.#locator.evaluate((node, argvs) => {
|
|
4205
|
+
node.setAttribute(argvs[0], argvs[1]);
|
|
4206
|
+
}, [attributeName, newValue]);
|
|
4207
|
+
return true;
|
|
4208
|
+
}
|
|
4209
|
+
_origElement() {
|
|
4210
|
+
return this.#locator;
|
|
4211
|
+
}
|
|
4212
|
+
};
|
|
4213
|
+
|
|
4214
|
+
// src/patchright/page.ts
|
|
4215
|
+
var PatchrightPage = class extends import_node_events8.default {
|
|
4216
|
+
#lsdBrowserContext;
|
|
4217
|
+
#page;
|
|
4218
|
+
#status;
|
|
4219
|
+
#pageId;
|
|
4220
|
+
#closeWhenFree;
|
|
4221
|
+
#resquestInterceptionOptions;
|
|
4222
|
+
#responseInterceptionOptions;
|
|
4223
|
+
#client;
|
|
4224
|
+
#responseCb;
|
|
4225
|
+
#hasValidUrl(page) {
|
|
4226
|
+
const url = page.url();
|
|
4227
|
+
return url.toLowerCase().startsWith("http");
|
|
4228
|
+
}
|
|
4229
|
+
async #clearCookies(page) {
|
|
4230
|
+
if (!this.#hasValidUrl(page)) {
|
|
4231
|
+
throw new Error("Please open related url before clearing cookies");
|
|
4232
|
+
}
|
|
4233
|
+
const browserContext = this.#lsdBrowserContext._origBrowserContext();
|
|
4234
|
+
if (!browserContext) {
|
|
4235
|
+
throw new Error(`Invalid LsdBrowserContext`);
|
|
4236
|
+
}
|
|
4237
|
+
const cookieItems = await this.#getCookies(page);
|
|
4238
|
+
const domainSet = new Set(cookieItems.map((c) => c.domain));
|
|
4239
|
+
if (domainSet.size !== 1) {
|
|
4240
|
+
logwarn(`Domains in clearCookies: ${Array.from(domainSet.values())}`);
|
|
4241
|
+
}
|
|
4242
|
+
for (const domain of domainSet.values()) {
|
|
4243
|
+
await browserContext.clearCookies({ domain });
|
|
4244
|
+
}
|
|
4245
|
+
return true;
|
|
4246
|
+
}
|
|
4247
|
+
async #getCookies(page) {
|
|
4248
|
+
if (!this.#hasValidUrl(page)) {
|
|
4249
|
+
throw new Error("Please open related url before getting cookies");
|
|
4250
|
+
}
|
|
4251
|
+
const browserContext = this.#lsdBrowserContext._origBrowserContext();
|
|
4252
|
+
if (!browserContext) {
|
|
4253
|
+
throw new Error(`Invalid LsdBrowserContext`);
|
|
4254
|
+
}
|
|
4255
|
+
const url = page.url();
|
|
4256
|
+
const origCookies = await browserContext.cookies(url);
|
|
4257
|
+
const cookies = origCookies.map((origCookie) => {
|
|
4258
|
+
const { name, value, domain, path, expires, httpOnly, secure, sameSite = "Lax" } = origCookie;
|
|
4259
|
+
return { name, value, domain, path, expires, httpOnly, secure, sameSite };
|
|
4260
|
+
});
|
|
4261
|
+
return cookies;
|
|
4262
|
+
}
|
|
4263
|
+
async #setCookies(page, cookies) {
|
|
4264
|
+
if (!page) {
|
|
4265
|
+
throw new Error("No valid page");
|
|
4266
|
+
}
|
|
4267
|
+
if (Array.isArray(cookies) && cookies.length > 0 && cookies.every((c) => typeof c.name === "string")) {
|
|
4268
|
+
const browserContext = this.#lsdBrowserContext._origBrowserContext();
|
|
4269
|
+
if (!browserContext) {
|
|
4270
|
+
throw new Error(`Invalid LsdBrowserContext`);
|
|
4271
|
+
}
|
|
4272
|
+
await browserContext.addCookies(cookies);
|
|
4273
|
+
return true;
|
|
4274
|
+
} else {
|
|
4275
|
+
return false;
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
async #clearLocalStorage(page) {
|
|
4279
|
+
if (!this.#hasValidUrl(page)) {
|
|
4280
|
+
throw new Error("Please open related url before clearing localStorage");
|
|
4281
|
+
}
|
|
4282
|
+
await page.evaluate(() => window.localStorage.clear());
|
|
4283
|
+
return true;
|
|
4284
|
+
}
|
|
4285
|
+
async #getLocalStorage(page) {
|
|
4286
|
+
if (!this.#hasValidUrl(page)) {
|
|
4287
|
+
throw new Error("Please open related url before getting localStorage");
|
|
4288
|
+
}
|
|
4289
|
+
const localStorageStr = await page.evaluate(() => JSON.stringify(window.localStorage));
|
|
4290
|
+
const localStorageObj = JSON.parse(localStorageStr);
|
|
4291
|
+
const localStorageItems = Object.keys(localStorageObj).map((name) => ({ name, value: localStorageObj[name] }));
|
|
4292
|
+
const url = new URL(page.url());
|
|
4293
|
+
return [{ origin: url.origin, localStorage: localStorageItems }];
|
|
4294
|
+
}
|
|
4295
|
+
async #setLocalStorage(page, localStorageItems) {
|
|
4296
|
+
if (!this.#hasValidUrl(page)) {
|
|
4297
|
+
throw new Error("Please open related url before setting localStorage");
|
|
4298
|
+
}
|
|
4299
|
+
await page.evaluate((items) => {
|
|
4300
|
+
for (const item of items) {
|
|
4301
|
+
window.localStorage.setItem(item.name, item.value);
|
|
4302
|
+
}
|
|
4303
|
+
}, localStorageItems);
|
|
4304
|
+
return true;
|
|
4305
|
+
}
|
|
4306
|
+
async #clearIndexedDB(page) {
|
|
4307
|
+
if (!this.#hasValidUrl(page)) {
|
|
4308
|
+
throw new Error("Please open related url before clearing indexedDB");
|
|
4309
|
+
}
|
|
4310
|
+
await page.evaluate(async () => {
|
|
4311
|
+
for (const db of await indexedDB.databases?.() || []) {
|
|
4312
|
+
if (db.name)
|
|
4313
|
+
indexedDB.deleteDatabase(db.name);
|
|
4314
|
+
}
|
|
4315
|
+
});
|
|
4316
|
+
return true;
|
|
4317
|
+
}
|
|
4318
|
+
/*
|
|
4319
|
+
async #getChildFrame(parentFrame: Frame, iframeOption: IframeOption): Promise<Frame | null> {
|
|
4320
|
+
if (!parentFrame) {
|
|
4321
|
+
throw new Error("Invalid parent frame");
|
|
4322
|
+
}
|
|
4323
|
+
|
|
4324
|
+
let { src = "" } = iframeOption;
|
|
4325
|
+
if (!src) {
|
|
4326
|
+
throw new Error("Invalid src in IframeOption");
|
|
4327
|
+
}
|
|
4328
|
+
|
|
4329
|
+
// src: use childFrames()
|
|
4330
|
+
const childFrames = parentFrame.childFrames();
|
|
4331
|
+
for (const childFrame of childFrames) {
|
|
4332
|
+
const url = childFrame.url();
|
|
4333
|
+
if (typeof src === "string") {
|
|
4334
|
+
// src: string
|
|
4335
|
+
if (url.startsWith(src)) {
|
|
4336
|
+
return childFrame;
|
|
4337
|
+
} else if (url.toLowerCase().startsWith(src)) {
|
|
4338
|
+
return childFrame;
|
|
4339
|
+
}
|
|
4340
|
+
} else {
|
|
4341
|
+
// src: RegExp
|
|
4342
|
+
if (url.match(src)) {
|
|
4343
|
+
return childFrame;
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4346
|
+
}
|
|
4347
|
+
|
|
4348
|
+
return null;
|
|
4349
|
+
}
|
|
4350
|
+
*/
|
|
4351
|
+
async #findDescendantFrame(src, id) {
|
|
4352
|
+
if (!this.#page) {
|
|
4353
|
+
throw new Error("No valid page");
|
|
4354
|
+
}
|
|
4355
|
+
const frames = this.#page.frames();
|
|
4356
|
+
for (const frame of frames) {
|
|
4357
|
+
const url = frame.url();
|
|
4358
|
+
if (typeof src === "string" && src) {
|
|
4359
|
+
if (url.startsWith(src)) {
|
|
4360
|
+
return frame;
|
|
4361
|
+
} else if (url.toLowerCase().startsWith(src)) {
|
|
4362
|
+
return frame;
|
|
4363
|
+
}
|
|
4364
|
+
} else if (src instanceof RegExp) {
|
|
4365
|
+
if (url.match(src)) {
|
|
4366
|
+
return frame;
|
|
4367
|
+
}
|
|
4368
|
+
} else if (id) {
|
|
4369
|
+
const element = await frame.frameElement();
|
|
4370
|
+
if (element) {
|
|
4371
|
+
const frameId = await frame.evaluate(([ele, attr]) => ele.getAttribute(attr), [element, "id"]);
|
|
4372
|
+
if (frameId === id) {
|
|
4373
|
+
return frame;
|
|
4374
|
+
}
|
|
4375
|
+
}
|
|
4376
|
+
}
|
|
4377
|
+
}
|
|
4378
|
+
return null;
|
|
4379
|
+
}
|
|
4380
|
+
async #getChildFrameLocator(parent, iframeOption) {
|
|
4381
|
+
return parent.frameLocator(getIframeSelector(iframeOption));
|
|
4382
|
+
}
|
|
4383
|
+
async #getDescendantFrame(mainFrame, iframeOptions) {
|
|
4384
|
+
try {
|
|
4385
|
+
if (iframeOptions.length <= 0) {
|
|
4386
|
+
return null;
|
|
4387
|
+
}
|
|
4388
|
+
if (iframeOptions.length === 1 && !iframeOptions[0].selector) {
|
|
4389
|
+
const { src = "", id = "" } = iframeOptions[0];
|
|
4390
|
+
const frame = await this.#findDescendantFrame(src, id);
|
|
4391
|
+
return frame;
|
|
4392
|
+
} else {
|
|
4393
|
+
let frameLocator = mainFrame.frameLocator(getIframeSelector(iframeOptions[0]));
|
|
4394
|
+
for (const iframeOption of iframeOptions.slice(1)) {
|
|
4395
|
+
if (!frameLocator) {
|
|
4396
|
+
return null;
|
|
4397
|
+
}
|
|
4398
|
+
frameLocator = await this.#getChildFrameLocator(frameLocator, iframeOption);
|
|
4399
|
+
}
|
|
4400
|
+
return frameLocator;
|
|
4401
|
+
}
|
|
4402
|
+
} catch (err) {
|
|
4403
|
+
throw new Error(`No child iframe: ${JSON.stringify(iframeOptions)}`);
|
|
4404
|
+
}
|
|
4405
|
+
}
|
|
4406
|
+
async #findElementHandles(selector, iframeOptions = []) {
|
|
4407
|
+
if (!this.#page) {
|
|
4408
|
+
throw new Error("No valid page");
|
|
4409
|
+
}
|
|
4410
|
+
let frame = this.#page.mainFrame();
|
|
4411
|
+
const retObj = { frame, locators: [] };
|
|
4412
|
+
if (iframeOptions.length > 0) {
|
|
4413
|
+
frame = await this.#getDescendantFrame(frame, iframeOptions);
|
|
4414
|
+
if (!frame) {
|
|
4415
|
+
return retObj;
|
|
4416
|
+
}
|
|
4417
|
+
retObj.frame = frame;
|
|
4418
|
+
}
|
|
4419
|
+
try {
|
|
4420
|
+
let locators = [];
|
|
4421
|
+
if (selector.startsWith("./") || selector.startsWith("/") || selector.startsWith("..")) {
|
|
4422
|
+
locators = await frame.locator(`xpath=${selector}`).all();
|
|
4423
|
+
} else {
|
|
4424
|
+
if (selector !== ".") {
|
|
4425
|
+
locators = await frame.locator(selector).all();
|
|
4426
|
+
} else {
|
|
4427
|
+
throw new Error("Cannot use selector '.' on page");
|
|
4428
|
+
}
|
|
4429
|
+
}
|
|
4430
|
+
retObj.locators = locators;
|
|
4431
|
+
return retObj;
|
|
4432
|
+
} catch (err) {
|
|
4433
|
+
loginfo(err);
|
|
4434
|
+
return retObj;
|
|
4435
|
+
}
|
|
4436
|
+
}
|
|
4437
|
+
#addPageOn() {
|
|
4438
|
+
if (!this.#page) {
|
|
4439
|
+
throw new Error("No valid page");
|
|
4440
|
+
}
|
|
4441
|
+
const page = this.#page;
|
|
4442
|
+
const pageId = this.#pageId;
|
|
4443
|
+
page.on("close", async () => {
|
|
4444
|
+
loginfo(`##browser ${pageId} closed`);
|
|
4445
|
+
if (!page.pageInfo) {
|
|
4446
|
+
logerr(`Logic error in page.on("close")`);
|
|
4447
|
+
}
|
|
4448
|
+
this.emit("pageClose");
|
|
4449
|
+
this.#lsdBrowserContext.emit("pageClose", this);
|
|
4450
|
+
});
|
|
4451
|
+
page.on("popup", (p) => {
|
|
4452
|
+
if (p) {
|
|
4453
|
+
let evtData = null;
|
|
4454
|
+
const pageInfo = p.pageInfo;
|
|
4455
|
+
let popupPageId = "page";
|
|
4456
|
+
if (pageInfo) {
|
|
4457
|
+
const { browserIdx, browserContextIdx, pageIdx } = pageInfo;
|
|
4458
|
+
popupPageId = `page-${browserIdx}-${browserContextIdx}-${pageIdx}`;
|
|
4459
|
+
pageInfo.openType = "popup";
|
|
4460
|
+
evtData = this.browserContext().page(pageIdx);
|
|
4461
|
+
if (evtData && page.pageInfo?.taskId) {
|
|
4462
|
+
pageInfo.relatedId = page.pageInfo.taskId;
|
|
4463
|
+
}
|
|
4464
|
+
} else {
|
|
4465
|
+
logerr(`##browser ${pageId} has popup without page.pageInfo`);
|
|
4466
|
+
}
|
|
4467
|
+
loginfo(`##browser ${pageId} has popup ${popupPageId}`);
|
|
4468
|
+
this.emit("pagePopup", evtData);
|
|
4469
|
+
} else {
|
|
4470
|
+
logerr(`##browser ${pageId} has popup page with null page`);
|
|
4471
|
+
}
|
|
4472
|
+
});
|
|
4473
|
+
}
|
|
4474
|
+
constructor(browserContext, page, pageInfo) {
|
|
4475
|
+
if (!browserContext.pages || !page?.goto) {
|
|
4476
|
+
throw new Error("Invalid paras in new LsdPage");
|
|
4477
|
+
}
|
|
4478
|
+
super();
|
|
4479
|
+
this.#lsdBrowserContext = browserContext;
|
|
4480
|
+
this.#page = page;
|
|
4481
|
+
this.#status = "free";
|
|
4482
|
+
const currentTime = (0, import_utils11.getCurrentUnixTime)();
|
|
4483
|
+
const { browserIdx = 0, browserContextIdx = 0, pageIdx = 0, openType = "other", openTime = currentTime, lastStatusUpdateTime = currentTime, taskId = 0, relatedId = 0, misc = {} } = pageInfo ? pageInfo : {};
|
|
4484
|
+
this.#page.pageInfo = { browserIdx, browserContextIdx, pageIdx, openType, openTime, lastStatusUpdateTime, taskId, relatedId, misc };
|
|
4485
|
+
this.#pageId = `page-${browserIdx}-${browserContextIdx}-${pageIdx}`;
|
|
4486
|
+
this.#closeWhenFree = false;
|
|
4487
|
+
this.#resquestInterceptionOptions = [];
|
|
4488
|
+
this.#responseInterceptionOptions = [];
|
|
4489
|
+
this.#client = null;
|
|
4490
|
+
this.#responseCb = null;
|
|
4491
|
+
this.#addPageOn();
|
|
4492
|
+
}
|
|
4493
|
+
async addPreloadScript(scriptOrFunc, arg) {
|
|
4494
|
+
if (!this.#page) {
|
|
4495
|
+
throw new Error("No valid page");
|
|
4496
|
+
}
|
|
4497
|
+
if (typeof scriptOrFunc === "string") {
|
|
4498
|
+
await this.#page.addInitScript({ content: scriptOrFunc });
|
|
4499
|
+
} else if (typeof scriptOrFunc === "function") {
|
|
4500
|
+
await this.#page.addInitScript(scriptOrFunc, arg);
|
|
4501
|
+
} else {
|
|
4502
|
+
throw new Error(`Invalid type of scriptOrFunc ${typeof scriptOrFunc}`);
|
|
4503
|
+
}
|
|
4504
|
+
return true;
|
|
4505
|
+
}
|
|
4506
|
+
async addScriptTag(options) {
|
|
4507
|
+
if (!this.#page) {
|
|
4508
|
+
throw new Error("No valid page");
|
|
4509
|
+
}
|
|
4510
|
+
return this.#page.addScriptTag(options);
|
|
4511
|
+
}
|
|
4512
|
+
apiContext() {
|
|
4513
|
+
return this.browserContext().apiContext();
|
|
4514
|
+
}
|
|
4515
|
+
async bringToFront() {
|
|
4516
|
+
if (!this.#page) {
|
|
4517
|
+
throw new Error("No valid page");
|
|
4518
|
+
}
|
|
4519
|
+
await this.#page.bringToFront();
|
|
4520
|
+
return true;
|
|
4521
|
+
}
|
|
4522
|
+
browserContext() {
|
|
4523
|
+
return this.#lsdBrowserContext;
|
|
4524
|
+
}
|
|
4525
|
+
async clearCookies() {
|
|
4526
|
+
if (!this.#page) {
|
|
4527
|
+
throw new Error("No valid page");
|
|
4528
|
+
}
|
|
4529
|
+
return await this.#clearCookies(this.#page);
|
|
4530
|
+
}
|
|
4531
|
+
async clearLocalStorage() {
|
|
4532
|
+
if (!this.#page) {
|
|
4533
|
+
throw new Error("No valid page");
|
|
4534
|
+
}
|
|
4535
|
+
return await this.#clearLocalStorage(this.#page);
|
|
4536
|
+
}
|
|
4537
|
+
async clearRequestInterceptions() {
|
|
4538
|
+
if (!this.#page) {
|
|
4539
|
+
throw new Error("No valid page");
|
|
4540
|
+
}
|
|
4541
|
+
await this.#page.unrouteAll();
|
|
4542
|
+
return true;
|
|
4543
|
+
}
|
|
4544
|
+
async clearResponseInterceptions() {
|
|
4545
|
+
if (!this.#page) {
|
|
4546
|
+
throw new Error("No valid page");
|
|
4547
|
+
}
|
|
4548
|
+
try {
|
|
4549
|
+
if (this.#responseInterceptionOptions.length > 0) {
|
|
4550
|
+
if (this.#responseCb) {
|
|
4551
|
+
this.#page.removeListener("response", this.#responseCb);
|
|
4552
|
+
}
|
|
4553
|
+
this.#responseInterceptionOptions = [];
|
|
4554
|
+
}
|
|
4555
|
+
return true;
|
|
4556
|
+
} catch (err) {
|
|
4557
|
+
logerr(err);
|
|
4558
|
+
return false;
|
|
4559
|
+
}
|
|
4560
|
+
}
|
|
4561
|
+
async clearStateData() {
|
|
4562
|
+
if (!this.#page) {
|
|
4563
|
+
throw new Error("No valid page");
|
|
4564
|
+
}
|
|
4565
|
+
await this.#clearCookies(this.#page);
|
|
4566
|
+
await this.#clearIndexedDB(this.#page);
|
|
4567
|
+
return await this.#clearLocalStorage(this.#page);
|
|
4568
|
+
}
|
|
4569
|
+
async close() {
|
|
4570
|
+
if (this.#status === "closed") {
|
|
4571
|
+
logwarn(`Page ${this.#pageId} is already closed.`);
|
|
4572
|
+
return true;
|
|
4573
|
+
} else if (this.#status === "busy") {
|
|
4574
|
+
throw new Error(`Page ${this.#pageId} cannot be closed because it is busy.`);
|
|
4575
|
+
}
|
|
4576
|
+
if (!this.#page) {
|
|
4577
|
+
throw new Error("No valid page");
|
|
4578
|
+
}
|
|
4579
|
+
await this.#page.close();
|
|
4580
|
+
this.#page = null;
|
|
4581
|
+
this.#status = "closed";
|
|
4582
|
+
return true;
|
|
4583
|
+
}
|
|
4584
|
+
closeWhenFree() {
|
|
4585
|
+
return this.#closeWhenFree;
|
|
4586
|
+
}
|
|
4587
|
+
async content(iframeOptions = []) {
|
|
4588
|
+
if (!this.#page) {
|
|
4589
|
+
throw new Error("No valid page");
|
|
4590
|
+
}
|
|
4591
|
+
let content = "";
|
|
4592
|
+
if (iframeOptions.length > 0) {
|
|
4593
|
+
const frameLocator = await this.#getDescendantFrame(this.#page.mainFrame(), iframeOptions);
|
|
4594
|
+
if (frameLocator) {
|
|
4595
|
+
content = await frameLocator.locator(":root").evaluate(() => document.documentElement.outerHTML);
|
|
4596
|
+
}
|
|
4597
|
+
} else {
|
|
4598
|
+
content = await this.#page.content();
|
|
4599
|
+
}
|
|
4600
|
+
return content;
|
|
4601
|
+
}
|
|
4602
|
+
async cookies() {
|
|
4603
|
+
if (!this.#page) {
|
|
4604
|
+
throw new Error("No valid page");
|
|
4605
|
+
}
|
|
4606
|
+
return this.#getCookies(this.#page);
|
|
4607
|
+
}
|
|
4608
|
+
async documentHeight() {
|
|
4609
|
+
if (!this.#page) {
|
|
4610
|
+
throw new Error("No valid page");
|
|
4611
|
+
}
|
|
4612
|
+
const height = await this.#page.evaluate(() => document.documentElement.scrollHeight);
|
|
4613
|
+
return height;
|
|
4614
|
+
}
|
|
4615
|
+
async evaluate(func, args) {
|
|
4616
|
+
if (!this.#page) {
|
|
4617
|
+
throw new Error("No valid page");
|
|
4618
|
+
}
|
|
4619
|
+
return this.#page.evaluate(func, args);
|
|
4620
|
+
}
|
|
4621
|
+
async exposeFunction(name, callbackFunction) {
|
|
4622
|
+
if (!this.#page) {
|
|
4623
|
+
throw new Error("No valid page");
|
|
4624
|
+
}
|
|
4625
|
+
await this.#page.exposeFunction(name, callbackFunction);
|
|
4626
|
+
return;
|
|
4627
|
+
}
|
|
4628
|
+
async findElement(selectorOrXpath, iframeOptions = []) {
|
|
4629
|
+
if (!this.#page) {
|
|
4630
|
+
throw new Error("No valid page");
|
|
4631
|
+
}
|
|
4632
|
+
const selectors = typeof selectorOrXpath === "string" ? [selectorOrXpath] : selectorOrXpath;
|
|
4633
|
+
if (!Array.isArray(selectors)) {
|
|
4634
|
+
throw new Error(`Invalid selectorOrXpath ${selectorOrXpath} in findElement`);
|
|
4635
|
+
}
|
|
4636
|
+
for (const selector of selectors) {
|
|
4637
|
+
const { frame, locators } = await this.#findElementHandles(selector, iframeOptions);
|
|
4638
|
+
if (locators.length > 0) {
|
|
4639
|
+
const playwrightElement = new PatchrightElement(locators[0], frame);
|
|
4640
|
+
return playwrightElement;
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
return null;
|
|
4644
|
+
}
|
|
4645
|
+
async findElements(selectorOrXpath, iframeOptions = []) {
|
|
4646
|
+
if (!this.#page) {
|
|
4647
|
+
throw new Error("No valid page");
|
|
4648
|
+
}
|
|
4649
|
+
const selectors = typeof selectorOrXpath === "string" ? [selectorOrXpath] : selectorOrXpath;
|
|
4650
|
+
if (!Array.isArray(selectors)) {
|
|
4651
|
+
throw new Error(`Invalid selectorOrXpath ${selectorOrXpath} in findElements`);
|
|
4652
|
+
}
|
|
4653
|
+
for (const selector of selectors) {
|
|
4654
|
+
const { frame, locators } = await this.#findElementHandles(selector, iframeOptions);
|
|
4655
|
+
if (locators.length > 0) {
|
|
4656
|
+
const playwrightElements = locators.map((locator) => new PatchrightElement(locator, frame));
|
|
4657
|
+
return playwrightElements;
|
|
4658
|
+
}
|
|
4659
|
+
}
|
|
4660
|
+
return [];
|
|
4661
|
+
}
|
|
4662
|
+
async free() {
|
|
4663
|
+
if (this.#status === "free") {
|
|
4664
|
+
logwarn(`Page ${this.#pageId} is already free.`);
|
|
4665
|
+
}
|
|
4666
|
+
this.#status = "free";
|
|
4667
|
+
await this.clearRequestInterceptions();
|
|
4668
|
+
await this.clearResponseInterceptions();
|
|
4669
|
+
return true;
|
|
4670
|
+
}
|
|
4671
|
+
#getWaitUntil(origWaitUntil) {
|
|
4672
|
+
if (origWaitUntil === "networkidle0" || origWaitUntil === "networkidle2") {
|
|
4673
|
+
return "networkidle";
|
|
4674
|
+
} else {
|
|
4675
|
+
return origWaitUntil;
|
|
4676
|
+
}
|
|
4677
|
+
}
|
|
4678
|
+
async goto(url, options) {
|
|
4679
|
+
if (!this.#page) {
|
|
4680
|
+
throw new Error("No valid page");
|
|
4681
|
+
}
|
|
4682
|
+
if (options) {
|
|
4683
|
+
const { referer, timeout, waitUntil = "load" } = options;
|
|
4684
|
+
const newOptions = {};
|
|
4685
|
+
if (referer) {
|
|
4686
|
+
newOptions.referer = referer;
|
|
4687
|
+
}
|
|
4688
|
+
if (timeout) {
|
|
4689
|
+
newOptions.timeout = timeout;
|
|
4690
|
+
}
|
|
4691
|
+
newOptions.waitUntil = this.#getWaitUntil(waitUntil);
|
|
4692
|
+
await this.#page.goto(url, newOptions);
|
|
4693
|
+
} else {
|
|
4694
|
+
await this.#page.goto(url);
|
|
4695
|
+
}
|
|
4696
|
+
return true;
|
|
4697
|
+
}
|
|
4698
|
+
id() {
|
|
4699
|
+
return this.#pageId;
|
|
4700
|
+
}
|
|
4701
|
+
isFree() {
|
|
4702
|
+
return this.#status === "free";
|
|
4703
|
+
}
|
|
4704
|
+
async localStroage() {
|
|
4705
|
+
if (!this.#page) {
|
|
4706
|
+
throw new Error("No valid page");
|
|
4707
|
+
}
|
|
4708
|
+
return this.#getLocalStorage(this.#page);
|
|
4709
|
+
}
|
|
4710
|
+
load() {
|
|
4711
|
+
throw new Error("Not supported in PatchrightPage.");
|
|
4712
|
+
}
|
|
4713
|
+
mainFrame() {
|
|
4714
|
+
if (!this.#page) {
|
|
4715
|
+
throw new Error("No valid page");
|
|
4716
|
+
}
|
|
4717
|
+
return this.#page.mainFrame();
|
|
4718
|
+
}
|
|
4719
|
+
async maximizeViewport() {
|
|
4720
|
+
const height = await this.pageHeight();
|
|
4721
|
+
const width = await this.pageWidth();
|
|
4722
|
+
return await this.setViewportSize({ height, width });
|
|
4723
|
+
}
|
|
4724
|
+
async pageHeight() {
|
|
4725
|
+
if (!this.#page) {
|
|
4726
|
+
throw new Error("No valid page");
|
|
4727
|
+
}
|
|
4728
|
+
const bodyHeight = await this.#page.evaluate(() => document.body.scrollHeight);
|
|
4729
|
+
const documentHeight = await this.#page.evaluate(() => document.documentElement.scrollHeight);
|
|
4730
|
+
const windowHeight = await this.#page.evaluate(() => window.outerHeight);
|
|
4731
|
+
const pageHeight = Math.max(bodyHeight, documentHeight, windowHeight);
|
|
4732
|
+
return pageHeight;
|
|
4733
|
+
}
|
|
4734
|
+
pageInfo() {
|
|
4735
|
+
if (!this.#page) {
|
|
4736
|
+
throw new Error("No valid page");
|
|
4737
|
+
}
|
|
4738
|
+
return Object.assign({}, this.#page.pageInfo);
|
|
4739
|
+
}
|
|
4740
|
+
async pageWidth() {
|
|
4741
|
+
if (!this.#page) {
|
|
4742
|
+
throw new Error("No valid page");
|
|
4743
|
+
}
|
|
4744
|
+
const offsetWidth = await this.#page.evaluate(() => document.documentElement.offsetWidth);
|
|
4745
|
+
const windowWidth = await this.#page.evaluate(() => window.outerWidth);
|
|
4746
|
+
const pageWidth = Math.max(offsetWidth, windowWidth);
|
|
4747
|
+
return pageWidth;
|
|
4748
|
+
}
|
|
4749
|
+
async pdf(options) {
|
|
4750
|
+
if (!this.#page) {
|
|
4751
|
+
throw new Error("No valid page");
|
|
4752
|
+
}
|
|
4753
|
+
const buffer = await this.#page.pdf(options);
|
|
4754
|
+
return buffer;
|
|
4755
|
+
}
|
|
4756
|
+
async reload() {
|
|
4757
|
+
if (!this.#page) {
|
|
4758
|
+
throw new Error("No valid page");
|
|
4759
|
+
}
|
|
4760
|
+
try {
|
|
4761
|
+
await this.#page.reload();
|
|
4762
|
+
return true;
|
|
4763
|
+
} catch (err) {
|
|
4764
|
+
loginfo(err);
|
|
4765
|
+
return false;
|
|
4766
|
+
}
|
|
4767
|
+
}
|
|
4768
|
+
async screenshot(options) {
|
|
4769
|
+
if (!this.#page) {
|
|
4770
|
+
throw new Error("No valid page");
|
|
4771
|
+
}
|
|
4772
|
+
return await this.#page.screenshot(options);
|
|
4773
|
+
}
|
|
4774
|
+
async scrollBy(x, y) {
|
|
4775
|
+
if (!this.#page) {
|
|
4776
|
+
throw new Error("No valid page");
|
|
4777
|
+
}
|
|
4778
|
+
await this.#page.evaluate(
|
|
4779
|
+
([x2, y2]) => {
|
|
4780
|
+
window.scrollBy(x2, y2);
|
|
4781
|
+
},
|
|
4782
|
+
[x, y]
|
|
4783
|
+
);
|
|
4784
|
+
return true;
|
|
4785
|
+
}
|
|
4786
|
+
async scrollTo(x, y) {
|
|
4787
|
+
if (!this.#page) {
|
|
4788
|
+
throw new Error("No valid page");
|
|
4789
|
+
}
|
|
4790
|
+
await this.#page.evaluate(
|
|
4791
|
+
([x2, y2]) => {
|
|
4792
|
+
window.scrollTo(x2, y2);
|
|
4793
|
+
},
|
|
4794
|
+
[x, y]
|
|
4795
|
+
);
|
|
4796
|
+
return true;
|
|
4797
|
+
}
|
|
4798
|
+
async sendCDPMessage(method, params = null, detach = true) {
|
|
4799
|
+
if (!this.#client) {
|
|
4800
|
+
const origContext = this.browserContext()._origBrowserContext();
|
|
4801
|
+
if (!origContext) {
|
|
4802
|
+
throw new Error(`Invalid playwright browserContext`);
|
|
4803
|
+
}
|
|
4804
|
+
this.#client = await origContext.newCDPSession(this.#page);
|
|
4805
|
+
}
|
|
4806
|
+
if (!this.#client) {
|
|
4807
|
+
throw new Error("No valid CDP session to send message");
|
|
4808
|
+
}
|
|
4809
|
+
const response = params ? await this.#client.send(method, params) : await this.#client.send(method);
|
|
4810
|
+
if (detach) {
|
|
4811
|
+
await this.#client.detach();
|
|
4812
|
+
this.#client = null;
|
|
4813
|
+
}
|
|
4814
|
+
return response;
|
|
4815
|
+
}
|
|
4816
|
+
setCloseWhenFree(closeWhenFree) {
|
|
4817
|
+
this.#closeWhenFree = closeWhenFree;
|
|
4818
|
+
return true;
|
|
4819
|
+
}
|
|
4820
|
+
async setCookies(cookies) {
|
|
4821
|
+
if (!this.#page) {
|
|
4822
|
+
throw new Error("No valid page");
|
|
4823
|
+
}
|
|
4824
|
+
return await this.#setCookies(this.#page, cookies);
|
|
4825
|
+
}
|
|
4826
|
+
async setExtraHTTPHeaders(headers) {
|
|
4827
|
+
if (!this.#page) {
|
|
4828
|
+
throw new Error("No valid page");
|
|
4829
|
+
}
|
|
4830
|
+
await this.#page.setExtraHTTPHeaders(headers);
|
|
4831
|
+
return true;
|
|
4832
|
+
}
|
|
4833
|
+
async setLocalStroage(localStorageItems) {
|
|
4834
|
+
if (!this.#page) {
|
|
4835
|
+
throw new Error("No valid page");
|
|
4836
|
+
}
|
|
4837
|
+
return await this.#setLocalStorage(this.#page, localStorageItems);
|
|
4838
|
+
}
|
|
4839
|
+
setPageInfo(pageInfo) {
|
|
4840
|
+
if (!this.#page?.pageInfo) {
|
|
4841
|
+
throw new Error("No valid page or pageInfo");
|
|
4842
|
+
}
|
|
4843
|
+
if (!pageInfo) {
|
|
4844
|
+
throw new Error("Invalid paras in setPageInfo");
|
|
4845
|
+
}
|
|
4846
|
+
const actPageInfo = this.#page.pageInfo;
|
|
4847
|
+
const { lastStatusUpdateTime, taskId, relatedId, misc } = pageInfo;
|
|
4848
|
+
if (typeof lastStatusUpdateTime === "number") {
|
|
4849
|
+
actPageInfo.lastStatusUpdateTime = lastStatusUpdateTime;
|
|
4850
|
+
}
|
|
4851
|
+
if (typeof taskId === "number") {
|
|
4852
|
+
actPageInfo.taskId = taskId;
|
|
4853
|
+
}
|
|
4854
|
+
if (typeof relatedId === "number") {
|
|
4855
|
+
actPageInfo.relatedId = relatedId;
|
|
4856
|
+
}
|
|
4857
|
+
if (misc && typeof misc === "object") {
|
|
4858
|
+
for (const key of Object.keys(misc)) {
|
|
4859
|
+
actPageInfo.misc[key] = misc[key];
|
|
4860
|
+
}
|
|
4861
|
+
}
|
|
4862
|
+
return true;
|
|
4863
|
+
}
|
|
4864
|
+
#checkRequestMatch(request, requestMatch) {
|
|
4865
|
+
try {
|
|
4866
|
+
if (!request) {
|
|
4867
|
+
return false;
|
|
4868
|
+
}
|
|
4869
|
+
const { methods, postData, resourceTypes, url } = requestMatch;
|
|
4870
|
+
if (methods && !methods.includes(request.method().toUpperCase())) {
|
|
4871
|
+
return false;
|
|
4872
|
+
}
|
|
4873
|
+
if (resourceTypes && !resourceTypes.includes(request.resourceType())) {
|
|
4874
|
+
return false;
|
|
4875
|
+
}
|
|
4876
|
+
if (url && !request.url().match(url)) {
|
|
4877
|
+
return false;
|
|
4878
|
+
}
|
|
4879
|
+
const origData = request.postData();
|
|
4880
|
+
const data = origData ? origData : "";
|
|
4881
|
+
if (postData && !data.match(postData)) {
|
|
4882
|
+
return false;
|
|
4883
|
+
}
|
|
4884
|
+
return true;
|
|
4885
|
+
} catch (err) {
|
|
4886
|
+
logerr(err);
|
|
4887
|
+
return false;
|
|
4888
|
+
}
|
|
4889
|
+
}
|
|
4890
|
+
async setRequestInterception(options) {
|
|
4891
|
+
if (!this.#page) {
|
|
4892
|
+
throw new Error("No valid page");
|
|
4893
|
+
}
|
|
4894
|
+
const actOptions = Array.isArray(options) ? options : [options];
|
|
4895
|
+
if (actOptions.length <= 0) {
|
|
4896
|
+
logwarn("Invalid paras in setRequestInterception");
|
|
4897
|
+
return false;
|
|
4898
|
+
}
|
|
4899
|
+
const firstRequestInterception = this.#resquestInterceptionOptions.length <= 0;
|
|
4900
|
+
for (const option of actOptions) {
|
|
4901
|
+
switch (option.action) {
|
|
4902
|
+
case "abort":
|
|
4903
|
+
case "fulfill":
|
|
4904
|
+
this.#resquestInterceptionOptions.push(option);
|
|
4905
|
+
break;
|
|
4906
|
+
default:
|
|
4907
|
+
(0, import_utils11.unreachable)(option.action);
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
if (firstRequestInterception && this.#resquestInterceptionOptions.length > 0) {
|
|
4911
|
+
this.#page.route("**", async (route) => {
|
|
4912
|
+
try {
|
|
4913
|
+
for (const option of actOptions) {
|
|
4914
|
+
const { requestMatch, action, fulfill } = option;
|
|
4915
|
+
const request = route.request();
|
|
4916
|
+
const matchedFlag = !requestMatch || this.#checkRequestMatch(request, requestMatch);
|
|
4917
|
+
if (matchedFlag) {
|
|
4918
|
+
switch (action) {
|
|
4919
|
+
case "abort":
|
|
4920
|
+
await route.abort();
|
|
4921
|
+
break;
|
|
4922
|
+
case "fulfill":
|
|
4923
|
+
const body = fulfill ? fulfill : `<html><body><h1>${request.url()}</h1></body></html>`;
|
|
4924
|
+
route.fulfill({
|
|
4925
|
+
status: 200,
|
|
4926
|
+
// contentType: "text/html; charset=utf-8", // "text/plain",
|
|
4927
|
+
body
|
|
4928
|
+
});
|
|
4929
|
+
break;
|
|
4930
|
+
default:
|
|
4931
|
+
(0, import_utils11.unreachable)(action);
|
|
4932
|
+
}
|
|
4933
|
+
return true;
|
|
4934
|
+
} else {
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
4937
|
+
await route.continue();
|
|
4938
|
+
return true;
|
|
4939
|
+
} catch (err) {
|
|
4940
|
+
logerr(err);
|
|
4941
|
+
return false;
|
|
4942
|
+
}
|
|
4943
|
+
});
|
|
4944
|
+
}
|
|
4945
|
+
return true;
|
|
4946
|
+
}
|
|
4947
|
+
async #responseListener(response) {
|
|
4948
|
+
try {
|
|
4949
|
+
const pageUrl = this.#page ? this.#page.url() : "";
|
|
4950
|
+
if (!response.ok()) {
|
|
4951
|
+
return;
|
|
4952
|
+
}
|
|
4953
|
+
const request = response.request();
|
|
4954
|
+
if (!request) {
|
|
4955
|
+
return;
|
|
4956
|
+
}
|
|
4957
|
+
for (const option of this.#responseInterceptionOptions) {
|
|
4958
|
+
const { requestMatch, responseMatch, responseItems, handler, handlerOptions = {} } = option;
|
|
4959
|
+
let matchedFlag = !requestMatch || this.#checkRequestMatch(request, requestMatch);
|
|
4960
|
+
if (matchedFlag && responseMatch) {
|
|
4961
|
+
const { minLength, maxLength } = responseMatch;
|
|
4962
|
+
const text = await response.text();
|
|
4963
|
+
const len = text.length;
|
|
4964
|
+
if (minLength && minLength > 0 && len < minLength || maxLength && maxLength > 0 && len > maxLength) {
|
|
4965
|
+
matchedFlag = false;
|
|
4966
|
+
}
|
|
4967
|
+
}
|
|
4968
|
+
if (!matchedFlag) {
|
|
4969
|
+
continue;
|
|
4970
|
+
}
|
|
4971
|
+
if (Array.isArray(responseItems)) {
|
|
4972
|
+
const requestMethod = request.method();
|
|
4973
|
+
const requestUrl = request.url();
|
|
4974
|
+
const reqData2 = request.postData();
|
|
4975
|
+
const requestData = reqData2 ? reqData2 : "";
|
|
4976
|
+
const responseData = await response.text();
|
|
4977
|
+
responseItems.push({
|
|
4978
|
+
pageUrl,
|
|
4979
|
+
requestMethod,
|
|
4980
|
+
requestUrl,
|
|
4981
|
+
requestData,
|
|
4982
|
+
responseData
|
|
4983
|
+
});
|
|
4984
|
+
loginfo(`##browser cache matched response: ${requestUrl}`);
|
|
4985
|
+
}
|
|
4986
|
+
if (typeof handler === "function") {
|
|
4987
|
+
const pageData = { pageUrl, cookies: "" };
|
|
4988
|
+
await handler(response, handlerOptions, pageData);
|
|
4989
|
+
}
|
|
4990
|
+
}
|
|
4991
|
+
return;
|
|
4992
|
+
} catch (err) {
|
|
4993
|
+
logerr(err);
|
|
4994
|
+
return;
|
|
4995
|
+
}
|
|
4996
|
+
}
|
|
4997
|
+
async setResponseInterception(options) {
|
|
4998
|
+
if (!this.#page) {
|
|
4999
|
+
throw new Error("No valid page");
|
|
5000
|
+
}
|
|
5001
|
+
const actOptions = Array.isArray(options) ? options : [options];
|
|
5002
|
+
if (actOptions.length <= 0) {
|
|
5003
|
+
logwarn("Invalid paras in setResponseInterception");
|
|
5004
|
+
return false;
|
|
5005
|
+
}
|
|
5006
|
+
const firstResponseInterception = this.#responseInterceptionOptions.length <= 0;
|
|
5007
|
+
for (const option of actOptions) {
|
|
5008
|
+
if (option?.responseItems || option?.handler) {
|
|
5009
|
+
this.#responseInterceptionOptions.push(option);
|
|
5010
|
+
} else {
|
|
5011
|
+
throw new Error(`Invalid ResponseInterceptionOption`);
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
5014
|
+
if (firstResponseInterception && this.#responseInterceptionOptions.length > 0) {
|
|
5015
|
+
this.#responseCb = this.#responseListener.bind(this);
|
|
5016
|
+
this.#page.on("response", this.#responseCb);
|
|
5017
|
+
}
|
|
5018
|
+
return true;
|
|
5019
|
+
}
|
|
5020
|
+
async setStateData(stateData) {
|
|
5021
|
+
return await this.#lsdBrowserContext.setStateData(stateData);
|
|
5022
|
+
}
|
|
5023
|
+
async setUserAgent(userAgent) {
|
|
5024
|
+
if (userAgent) {
|
|
5025
|
+
throw new Error(`Patchright does not support page.setUserAgent by now`);
|
|
5026
|
+
}
|
|
5027
|
+
return false;
|
|
5028
|
+
}
|
|
5029
|
+
async setViewportSize(viewPortSize) {
|
|
5030
|
+
if (!this.#page) {
|
|
5031
|
+
throw new Error("No valid page");
|
|
5032
|
+
}
|
|
5033
|
+
await this.#page.setViewportSize(viewPortSize);
|
|
5034
|
+
return true;
|
|
5035
|
+
}
|
|
5036
|
+
async stateData() {
|
|
5037
|
+
if (!this.#page) {
|
|
5038
|
+
throw new Error("No valid page");
|
|
5039
|
+
}
|
|
5040
|
+
const cookies = await this.#getCookies(this.#page);
|
|
5041
|
+
const localStorage = await this.#getLocalStorage(this.#page);
|
|
5042
|
+
return { cookies, localStorage };
|
|
5043
|
+
}
|
|
5044
|
+
status() {
|
|
5045
|
+
return this.#status;
|
|
5046
|
+
}
|
|
5047
|
+
async title() {
|
|
5048
|
+
if (!this.#page) {
|
|
5049
|
+
throw new Error("No valid page");
|
|
5050
|
+
}
|
|
5051
|
+
return await this.#page.title();
|
|
5052
|
+
}
|
|
5053
|
+
url() {
|
|
5054
|
+
if (!this.#page) {
|
|
5055
|
+
throw new Error("No valid page");
|
|
5056
|
+
}
|
|
5057
|
+
return this.#page.url();
|
|
5058
|
+
}
|
|
5059
|
+
use() {
|
|
5060
|
+
if (this.#status === "busy") {
|
|
5061
|
+
throw new Error(`Page ${this.#pageId} is already busy!!!`);
|
|
5062
|
+
}
|
|
5063
|
+
this.#status = "busy";
|
|
5064
|
+
return true;
|
|
5065
|
+
}
|
|
5066
|
+
async waitForElement(selector, options = {}) {
|
|
5067
|
+
if (!this.#page) {
|
|
5068
|
+
throw new Error("No valid page");
|
|
5069
|
+
}
|
|
5070
|
+
const locator = this.#page.locator(selector);
|
|
5071
|
+
const { timeout = 3e4, state = "visible" } = options;
|
|
5072
|
+
await locator.waitFor({ state, timeout });
|
|
5073
|
+
return true;
|
|
5074
|
+
}
|
|
5075
|
+
async waitForNavigation(options) {
|
|
5076
|
+
if (!this.#page) {
|
|
5077
|
+
throw new Error("No valid page");
|
|
5078
|
+
}
|
|
5079
|
+
const { url = "", timeout = 3e4, waitUntil = "load" } = options;
|
|
5080
|
+
const newWaitUntil = this.#getWaitUntil(waitUntil);
|
|
5081
|
+
if (url) {
|
|
5082
|
+
await this.#page.waitForURL(url, { timeout, waitUntil: newWaitUntil });
|
|
5083
|
+
} else if (newWaitUntil === "commit") {
|
|
5084
|
+
throw new Error("commit is not supported in PatchrightPage.waitForNavigation");
|
|
5085
|
+
} else {
|
|
5086
|
+
await this.#page.waitForLoadState(newWaitUntil, { timeout });
|
|
5087
|
+
}
|
|
5088
|
+
return true;
|
|
5089
|
+
}
|
|
5090
|
+
async windowMember(keys) {
|
|
5091
|
+
if (!this.#page) {
|
|
5092
|
+
throw new Error("No valid page");
|
|
5093
|
+
}
|
|
5094
|
+
if (!this.#page || !Array.isArray(keys) || keys.length <= 0 || keys.length > 20) {
|
|
5095
|
+
return "";
|
|
5096
|
+
}
|
|
5097
|
+
const content = await this.#page.evaluate(
|
|
5098
|
+
(keys2) => {
|
|
5099
|
+
let retObj = window;
|
|
5100
|
+
for (const key of keys2) {
|
|
5101
|
+
if (!key) {
|
|
5102
|
+
break;
|
|
5103
|
+
} else if (typeof retObj !== "object" || !retObj) {
|
|
5104
|
+
return "";
|
|
5105
|
+
} else {
|
|
5106
|
+
retObj = retObj[key];
|
|
5107
|
+
}
|
|
5108
|
+
}
|
|
5109
|
+
if (typeof retObj === "string") {
|
|
5110
|
+
return retObj;
|
|
5111
|
+
} else if (typeof retObj === "number") {
|
|
5112
|
+
return String(retObj);
|
|
5113
|
+
} else if (typeof retObj === "boolean") {
|
|
5114
|
+
return String(Number(retObj));
|
|
5115
|
+
} else if (!retObj) {
|
|
5116
|
+
return "";
|
|
5117
|
+
} else if (typeof retObj === "object") {
|
|
5118
|
+
try {
|
|
5119
|
+
return JSON.stringify(retObj);
|
|
5120
|
+
} catch (err) {
|
|
5121
|
+
return "";
|
|
5122
|
+
}
|
|
5123
|
+
} else if (typeof retObj === "bigint") {
|
|
5124
|
+
return String(retObj);
|
|
5125
|
+
} else {
|
|
5126
|
+
return "";
|
|
5127
|
+
}
|
|
5128
|
+
},
|
|
5129
|
+
keys
|
|
5130
|
+
);
|
|
5131
|
+
return content;
|
|
5132
|
+
}
|
|
5133
|
+
_origPage() {
|
|
5134
|
+
return this.#page;
|
|
5135
|
+
}
|
|
5136
|
+
};
|
|
5137
|
+
|
|
5138
|
+
// src/patchright/api.ts
|
|
5139
|
+
var PatchrightApiContext = class {
|
|
5140
|
+
#apiRequestContext;
|
|
5141
|
+
#status;
|
|
5142
|
+
constructor(apiRequestContext) {
|
|
5143
|
+
this.#apiRequestContext = apiRequestContext;
|
|
5144
|
+
this.#status = "normal";
|
|
5145
|
+
}
|
|
5146
|
+
async fetch(url, options = {}) {
|
|
5147
|
+
if (this.#status !== "normal") {
|
|
5148
|
+
throw new Error(`ApiContext has already been destroyed`);
|
|
5149
|
+
}
|
|
5150
|
+
const apiResponse = await this.#apiRequestContext.fetch(url, options);
|
|
5151
|
+
const headers = apiResponse.headers();
|
|
5152
|
+
const status = apiResponse.status();
|
|
5153
|
+
const statusText = apiResponse.statusText();
|
|
5154
|
+
const text = await apiResponse.text();
|
|
5155
|
+
const responseUrl = apiResponse.url();
|
|
5156
|
+
return { headers, status, statusText, text, url: responseUrl };
|
|
5157
|
+
}
|
|
5158
|
+
async stateData() {
|
|
5159
|
+
if (this.#status !== "normal") {
|
|
5160
|
+
throw new Error(`ApiContext has already been destroyed`);
|
|
5161
|
+
}
|
|
5162
|
+
const storageState = await this.#apiRequestContext.storageState();
|
|
5163
|
+
const { cookies, origins: localStorage } = storageState;
|
|
5164
|
+
return { cookies, localStorage };
|
|
5165
|
+
}
|
|
5166
|
+
async destroy() {
|
|
5167
|
+
await this.#apiRequestContext.dispose();
|
|
5168
|
+
this.#status = "destroyed";
|
|
5169
|
+
return true;
|
|
5170
|
+
}
|
|
5171
|
+
};
|
|
5172
|
+
|
|
5173
|
+
// src/patchright/context.ts
|
|
5174
|
+
var PatchrightBrowserContext = class extends import_node_events9.default {
|
|
5175
|
+
#lsdBrowser;
|
|
5176
|
+
#browserIdx;
|
|
5177
|
+
#browserContextIdx;
|
|
5178
|
+
#browserContext;
|
|
5179
|
+
#browserContextCreationMethod;
|
|
5180
|
+
#apiContext;
|
|
5181
|
+
#createTime;
|
|
5182
|
+
#lastStatusUpdateTime;
|
|
5183
|
+
#status;
|
|
5184
|
+
#incognito;
|
|
5185
|
+
#proxy;
|
|
5186
|
+
#maxPagesPerBrowserContext;
|
|
5187
|
+
#maxPageFreeSeconds;
|
|
5188
|
+
#maxViewportOfNewPage;
|
|
5189
|
+
#lsdPages;
|
|
5190
|
+
#nextPageIdx;
|
|
5191
|
+
#gettingPage;
|
|
5192
|
+
async #initPages() {
|
|
5193
|
+
if (!this.#browserContext) {
|
|
5194
|
+
throw new Error("Invalid browserContext");
|
|
5195
|
+
}
|
|
5196
|
+
const pages = this.#browserContext.pages();
|
|
5197
|
+
const openType = this.#lsdBrowser.browserCreationMethod();
|
|
5198
|
+
const lastStatusUpdateTime = (0, import_utils12.getCurrentUnixTime)();
|
|
5199
|
+
for (const page of pages) {
|
|
5200
|
+
const pageInfo = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType, openTime: this.#createTime, lastStatusUpdateTime, taskId: 0, relatedId: 0, misc: {} };
|
|
5201
|
+
const lsdPage = new PatchrightPage(this, page, pageInfo);
|
|
5202
|
+
if (this.#maxViewportOfNewPage) {
|
|
5203
|
+
await lsdPage.maximizeViewport();
|
|
5204
|
+
}
|
|
5205
|
+
this.#lsdPages.push(lsdPage);
|
|
5206
|
+
loginfo(`##browser ${lsdPage.id()} ${openType}ed`);
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
constructor(lsdBrowser, browserContext, browserContextCreationMethod, incognito = false, proxy = null, browserIdx = 0, browserContextIdx = 0, maxPagesPerBrowserContext = 20, maxPageFreeSeconds = 0, maxViewportOfNewPage = true) {
|
|
5210
|
+
if (!lsdBrowser || typeof lsdBrowser.browserContexts !== "function") {
|
|
5211
|
+
throw new Error(`Invalid lsdBrowser parameter`);
|
|
5212
|
+
}
|
|
5213
|
+
if (!browserContext || typeof browserContext.setOffline !== "function") {
|
|
5214
|
+
throw new Error(`Invalid playwright browserContext parameter`);
|
|
5215
|
+
}
|
|
5216
|
+
super();
|
|
5217
|
+
this.#lsdBrowser = lsdBrowser;
|
|
5218
|
+
this.#browserIdx = browserIdx;
|
|
5219
|
+
this.#browserContextIdx = browserContextIdx;
|
|
5220
|
+
this.#browserContext = browserContext;
|
|
5221
|
+
this.#browserContextCreationMethod = browserContextCreationMethod;
|
|
5222
|
+
const apiRequestContext = browserContext.request;
|
|
5223
|
+
this.#apiContext = new PatchrightApiContext(apiRequestContext);
|
|
5224
|
+
const currentTime = (0, import_utils12.getCurrentUnixTime)();
|
|
5225
|
+
this.#createTime = currentTime;
|
|
5226
|
+
this.#lastStatusUpdateTime = currentTime;
|
|
5227
|
+
this.#status = "free";
|
|
5228
|
+
this.#incognito = incognito === false ? false : true;
|
|
5229
|
+
this.#proxy = proxy?.proxyUrl ? proxy : null;
|
|
5230
|
+
this.#maxPagesPerBrowserContext = maxPagesPerBrowserContext;
|
|
5231
|
+
this.#maxPageFreeSeconds = maxPageFreeSeconds;
|
|
5232
|
+
this.#maxViewportOfNewPage = maxViewportOfNewPage;
|
|
5233
|
+
this.#lsdPages = [];
|
|
5234
|
+
this.#nextPageIdx = 1;
|
|
5235
|
+
this.#gettingPage = false;
|
|
5236
|
+
this.#initPages();
|
|
5237
|
+
browserContext.on("page", async (page) => {
|
|
5238
|
+
const pageInfo = page.pageInfo;
|
|
5239
|
+
if (pageInfo) {
|
|
5240
|
+
const { browserIdx: browserIdx2, browserContextIdx: browserContextIdx2, pageIdx } = pageInfo;
|
|
5241
|
+
logwarn(`##browser page-${browserIdx2}-${browserContextIdx2}-${pageIdx} has been already created`);
|
|
5242
|
+
} else {
|
|
5243
|
+
const currentTime2 = (0, import_utils12.getCurrentUnixTime)();
|
|
5244
|
+
const pageInfo2 = { browserIdx: this.#browserIdx, browserContextIdx: this.#browserContextIdx, pageIdx: this.#nextPageIdx++, openType: "other", openTime: currentTime2, lastStatusUpdateTime: currentTime2, taskId: 0, relatedId: 0, misc: {} };
|
|
5245
|
+
const lsdPage = new PatchrightPage(this, page, pageInfo2);
|
|
5246
|
+
if (this.#maxViewportOfNewPage) {
|
|
5247
|
+
await lsdPage.maximizeViewport();
|
|
5248
|
+
}
|
|
5249
|
+
this.#lsdPages.push(lsdPage);
|
|
5250
|
+
loginfo(`##page ${lsdPage.id()} created`);
|
|
5251
|
+
}
|
|
5252
|
+
});
|
|
5253
|
+
browserContext.on("close", (bc) => {
|
|
5254
|
+
if (browserContext !== bc) {
|
|
5255
|
+
logerr(`##browser different browserContext in browserContext.on("close")`);
|
|
5256
|
+
}
|
|
5257
|
+
this.#lsdBrowser.emit("browserContextClose", this);
|
|
5258
|
+
});
|
|
5259
|
+
this.on("pageClose", (lsdPage) => {
|
|
5260
|
+
if (!(lsdPage instanceof PatchrightPage)) {
|
|
5261
|
+
logerr(`Invalid data in LsdBrowserContext.on("pageClose)`);
|
|
5262
|
+
return;
|
|
5263
|
+
}
|
|
5264
|
+
const idx = this.#lsdPages.findIndex((p) => p === lsdPage);
|
|
5265
|
+
if (idx < 0) {
|
|
5266
|
+
logerr(`Invalid lsdPage in LsdBrowserContext.on("pageClose)`);
|
|
5267
|
+
return;
|
|
5268
|
+
}
|
|
5269
|
+
this.#lsdPages.splice(idx, 1);
|
|
5270
|
+
return;
|
|
5271
|
+
});
|
|
5272
|
+
}
|
|
5273
|
+
apiContext() {
|
|
5274
|
+
return this.#apiContext;
|
|
5275
|
+
}
|
|
5276
|
+
browser() {
|
|
5277
|
+
return this.#lsdBrowser;
|
|
5278
|
+
}
|
|
5279
|
+
async close() {
|
|
5280
|
+
if (this.#browserContext) {
|
|
5281
|
+
this.#status = "closed";
|
|
5282
|
+
this.#lastStatusUpdateTime = (0, import_utils12.getCurrentUnixTime)();
|
|
5283
|
+
loginfo(`browserContext ${this.id()} closed at ${this.#lastStatusUpdateTime}`);
|
|
5284
|
+
await this.#browserContext.close();
|
|
5285
|
+
}
|
|
5286
|
+
return true;
|
|
5287
|
+
}
|
|
5288
|
+
async #tryToGetGettingLock() {
|
|
5289
|
+
let i = 0;
|
|
5290
|
+
for (i = 0; i < 50; i++) {
|
|
5291
|
+
if (!this.#gettingPage) {
|
|
5292
|
+
this.#gettingPage = true;
|
|
5293
|
+
return true;
|
|
5294
|
+
} else {
|
|
5295
|
+
await (0, import_utils12.sleep)(200);
|
|
5296
|
+
}
|
|
5297
|
+
}
|
|
5298
|
+
logwarn(`Cannot get the gettingLock.`);
|
|
5299
|
+
return false;
|
|
5300
|
+
}
|
|
5301
|
+
#freeGettingLock() {
|
|
5302
|
+
if (!this.#gettingPage) {
|
|
5303
|
+
logwarn(`Getting lock is already free now.`);
|
|
5304
|
+
}
|
|
5305
|
+
this.#gettingPage = false;
|
|
5306
|
+
}
|
|
5307
|
+
async closeFreePages(maxPageFreeSeconds = 0) {
|
|
5308
|
+
if (maxPageFreeSeconds <= 0) {
|
|
5309
|
+
maxPageFreeSeconds = this.#maxPageFreeSeconds;
|
|
5310
|
+
}
|
|
5311
|
+
if (maxPageFreeSeconds <= 0) {
|
|
5312
|
+
logwarn(`Please set valid maxPageFreeSeconds to close free pages`);
|
|
5313
|
+
return false;
|
|
5314
|
+
}
|
|
5315
|
+
const gotLock = await this.#tryToGetGettingLock();
|
|
5316
|
+
if (!gotLock) {
|
|
5317
|
+
return false;
|
|
5318
|
+
}
|
|
5319
|
+
try {
|
|
5320
|
+
const maxUpdateTime = (0, import_utils12.getCurrentUnixTime)() - this.#maxPageFreeSeconds;
|
|
5321
|
+
let freePages = this.#lsdPages.filter((p) => p.isFree() && p.pageInfo().lastStatusUpdateTime < maxUpdateTime);
|
|
5322
|
+
if (freePages.length === this.#lsdPages.length) {
|
|
5323
|
+
freePages = freePages.slice(1);
|
|
5324
|
+
}
|
|
5325
|
+
for (const lsdPage of freePages) {
|
|
5326
|
+
await lsdPage.close();
|
|
5327
|
+
}
|
|
5328
|
+
this.#freeGettingLock();
|
|
5329
|
+
return true;
|
|
5330
|
+
} catch (err) {
|
|
5331
|
+
logerr(err);
|
|
5332
|
+
this.#freeGettingLock();
|
|
5333
|
+
return false;
|
|
5334
|
+
}
|
|
5335
|
+
}
|
|
5336
|
+
creationMethod() {
|
|
5337
|
+
return this.#browserContextCreationMethod;
|
|
5338
|
+
}
|
|
5339
|
+
doesMeetBrowserContextRequirements(browserContextRequirements) {
|
|
5340
|
+
if (!this.#lsdBrowser.doesMeetBrowserContextRequirements(browserContextRequirements)) {
|
|
5341
|
+
return false;
|
|
5342
|
+
}
|
|
5343
|
+
const { browserIncognitos: incognitos } = browserContextRequirements;
|
|
5344
|
+
return incognitos.length === 0 || incognitos.includes(this.#incognito);
|
|
5345
|
+
}
|
|
5346
|
+
async getPage(always = false) {
|
|
5347
|
+
if (!this.#browserContext) {
|
|
5348
|
+
throw new Error("Invalid browserContext");
|
|
5349
|
+
}
|
|
5350
|
+
const gotLock = await this.#tryToGetGettingLock();
|
|
5351
|
+
if (!gotLock) {
|
|
5352
|
+
return null;
|
|
5353
|
+
}
|
|
5354
|
+
try {
|
|
5355
|
+
let lsdPage = this.#lsdPages.find((p) => p.isFree());
|
|
5356
|
+
if (lsdPage) {
|
|
5357
|
+
lsdPage.use();
|
|
5358
|
+
this.#freeGettingLock();
|
|
5359
|
+
return lsdPage;
|
|
5360
|
+
}
|
|
5361
|
+
if (this.#lsdPages.length >= this.#maxPagesPerBrowserContext && !always) {
|
|
5362
|
+
this.#freeGettingLock();
|
|
5363
|
+
return null;
|
|
5364
|
+
}
|
|
5365
|
+
const page = await this.#browserContext.newPage();
|
|
5366
|
+
await (0, import_utils12.sleep)(2e3);
|
|
5367
|
+
const pageInfo = page.pageInfo;
|
|
5368
|
+
if (!pageInfo) {
|
|
5369
|
+
throw new Error(`Logic error in getPage`);
|
|
5370
|
+
} else {
|
|
5371
|
+
pageInfo.openType = "newpage";
|
|
5372
|
+
}
|
|
5373
|
+
lsdPage = this.#lsdPages.find((p) => p.isFree());
|
|
5374
|
+
if (lsdPage) {
|
|
5375
|
+
lsdPage.use();
|
|
5376
|
+
this.#freeGettingLock();
|
|
5377
|
+
return lsdPage;
|
|
5378
|
+
} else {
|
|
5379
|
+
this.#freeGettingLock();
|
|
5380
|
+
return null;
|
|
5381
|
+
}
|
|
5382
|
+
} catch (err) {
|
|
5383
|
+
logerr(err);
|
|
5384
|
+
this.#freeGettingLock();
|
|
5385
|
+
return null;
|
|
5386
|
+
}
|
|
5387
|
+
}
|
|
5388
|
+
free(clearStateData = false) {
|
|
5389
|
+
if (this.#status === "busy") {
|
|
5390
|
+
this.#status = "free";
|
|
5391
|
+
this.#lastStatusUpdateTime = (0, import_utils12.getCurrentUnixTime)();
|
|
5392
|
+
if (clearStateData) {
|
|
5393
|
+
}
|
|
5394
|
+
return true;
|
|
5395
|
+
} else {
|
|
5396
|
+
return false;
|
|
5397
|
+
}
|
|
5398
|
+
}
|
|
5399
|
+
hasFreePage(pageNum = 1) {
|
|
5400
|
+
if (this.#maxPagesPerBrowserContext - this.#lsdPages.length > pageNum) {
|
|
5401
|
+
return true;
|
|
5402
|
+
} else if (this.#maxPagesPerBrowserContext - this.#lsdPages.filter((p) => !p.isFree()).length > pageNum) {
|
|
5403
|
+
return true;
|
|
5404
|
+
} else {
|
|
5405
|
+
return false;
|
|
5406
|
+
}
|
|
5407
|
+
}
|
|
5408
|
+
id() {
|
|
5409
|
+
return `browserContext-${this.#browserIdx}-${this.#browserContextIdx}`;
|
|
5410
|
+
}
|
|
5411
|
+
isFree() {
|
|
5412
|
+
return this.#status === "free";
|
|
5413
|
+
}
|
|
5414
|
+
isIncognito() {
|
|
5415
|
+
return this.#incognito;
|
|
5416
|
+
}
|
|
5417
|
+
page(pageIdx) {
|
|
5418
|
+
const lsdPage = this.#lsdPages.find((p) => p.pageInfo().pageIdx === pageIdx);
|
|
5419
|
+
return lsdPage ? lsdPage : null;
|
|
5420
|
+
}
|
|
5421
|
+
pages() {
|
|
5422
|
+
return this.#lsdPages;
|
|
5423
|
+
}
|
|
5424
|
+
proxy() {
|
|
5425
|
+
return this.#proxy;
|
|
5426
|
+
}
|
|
5427
|
+
async setStateData(stateData) {
|
|
5428
|
+
if (!this.#browserContext) {
|
|
5429
|
+
throw new Error("No valid browserContext");
|
|
5430
|
+
}
|
|
5431
|
+
try {
|
|
5432
|
+
const { cookies, localStorage: localStorageOrigins } = stateData;
|
|
5433
|
+
const page = await this.getPage();
|
|
5434
|
+
if (!page) {
|
|
5435
|
+
return false;
|
|
5436
|
+
}
|
|
5437
|
+
const origPage = page._origPage();
|
|
5438
|
+
if (cookies.length > 0) {
|
|
5439
|
+
await this.#browserContext.addCookies(cookies);
|
|
5440
|
+
}
|
|
5441
|
+
if (localStorageOrigins.length > 0) {
|
|
5442
|
+
await origPage.route("**/*", async (route) => {
|
|
5443
|
+
const request = route.request();
|
|
5444
|
+
await route.fulfill({
|
|
5445
|
+
status: 200,
|
|
5446
|
+
// contentType: "text/html; charset=utf-8", // "text/plain",
|
|
5447
|
+
body: `<html><body><h1>${request.url()}</h1></body></html>`
|
|
5448
|
+
});
|
|
5449
|
+
});
|
|
5450
|
+
for (const localStorageOrigin of localStorageOrigins) {
|
|
5451
|
+
const { origin, localStorage } = localStorageOrigin;
|
|
5452
|
+
await origPage.goto(origin);
|
|
5453
|
+
await origPage.evaluate((localStorageItems) => {
|
|
5454
|
+
for (const item of localStorageItems) {
|
|
5455
|
+
window.localStorage.setItem(item.name, item.value);
|
|
5456
|
+
}
|
|
5457
|
+
}, localStorage);
|
|
5458
|
+
}
|
|
5459
|
+
}
|
|
5460
|
+
await (0, import_utils12.sleep)(2e3);
|
|
5461
|
+
await origPage.unrouteAll();
|
|
5462
|
+
await page.free();
|
|
5463
|
+
return true;
|
|
5464
|
+
} catch (err) {
|
|
5465
|
+
logerr(err);
|
|
5466
|
+
return false;
|
|
5467
|
+
}
|
|
5468
|
+
}
|
|
5469
|
+
status() {
|
|
5470
|
+
return this.#status;
|
|
5471
|
+
}
|
|
5472
|
+
use() {
|
|
5473
|
+
if (this.#status === "free") {
|
|
5474
|
+
this.#status = "busy";
|
|
5475
|
+
this.#lastStatusUpdateTime = (0, import_utils12.getCurrentUnixTime)();
|
|
5476
|
+
return true;
|
|
5477
|
+
} else {
|
|
5478
|
+
return false;
|
|
5479
|
+
}
|
|
5480
|
+
}
|
|
5481
|
+
_origBrowserContext() {
|
|
5482
|
+
return this.#browserContext;
|
|
5483
|
+
}
|
|
5484
|
+
};
|
|
5485
|
+
|
|
5486
|
+
// src/patchright/browser.ts
|
|
5487
|
+
var PatchrightBrowser = class _PatchrightBrowser extends import_node_events10.default {
|
|
5488
|
+
static #supportedBrowserTypes = ["chromium", "firefox", "webkit"];
|
|
5489
|
+
static doesSupport(browserType) {
|
|
5490
|
+
return _PatchrightBrowser.#supportedBrowserTypes.includes(browserType);
|
|
5491
|
+
}
|
|
5492
|
+
#browser;
|
|
5493
|
+
#browserIdx;
|
|
5494
|
+
#pid;
|
|
5495
|
+
#createTime;
|
|
5496
|
+
#lsdBrowserContexts;
|
|
5497
|
+
#browserControllerType;
|
|
5498
|
+
#browserType;
|
|
5499
|
+
#browserCreationMethod;
|
|
5500
|
+
#headless;
|
|
5501
|
+
#options;
|
|
5502
|
+
#proxy;
|
|
5503
|
+
/**
|
|
5504
|
+
* launch: actual path of executable app
|
|
5505
|
+
* connect: ""
|
|
5506
|
+
*/
|
|
5507
|
+
#executablePath;
|
|
5508
|
+
#nextBrowserContextIdx;
|
|
5509
|
+
#closeFreePagesIntervalId;
|
|
5510
|
+
#maxBrowserContextsPerBrowser() {
|
|
5511
|
+
return this.#options.maxBrowserContextsPerBrowser ? this.#options.maxBrowserContextsPerBrowser : 10;
|
|
5512
|
+
}
|
|
5513
|
+
#maxPagesPerBrowserContext() {
|
|
5514
|
+
return this.#options.maxPagesPerBrowserContext ? this.#options.maxPagesPerBrowserContext : 20;
|
|
5515
|
+
}
|
|
5516
|
+
#maxPageFreeSeconds() {
|
|
5517
|
+
return this.#options.maxPageFreeSeconds ? this.#options.maxPageFreeSeconds : 900;
|
|
5518
|
+
}
|
|
5519
|
+
// constructor: called only by LsdBrowserController.launch/connect
|
|
5520
|
+
constructor(browser, browserType, browserCreateMethod, options, browserIdx = 0, pid = 0) {
|
|
5521
|
+
if (!browser || typeof browser.contexts !== "function") {
|
|
5522
|
+
throw new Error(`Invalid playwright browser parameter`);
|
|
5523
|
+
}
|
|
5524
|
+
super();
|
|
5525
|
+
const { closeFreePagesIntervalSeconds = 300, maxPageFreeSeconds = 900, maxViewportOfNewPage = true, headless = false, executablePath = "" } = options;
|
|
5526
|
+
this.#browser = browser;
|
|
5527
|
+
this.#browserIdx = browserIdx;
|
|
5528
|
+
this.#pid = pid;
|
|
5529
|
+
this.#createTime = (0, import_utils13.getCurrentUnixTime)();
|
|
5530
|
+
this.#lsdBrowserContexts = [];
|
|
5531
|
+
this.#browserControllerType = "playwright";
|
|
5532
|
+
this.#browserType = browserType;
|
|
5533
|
+
if (!_PatchrightBrowser.#supportedBrowserTypes.includes(browserType)) {
|
|
5534
|
+
throw new Error(`Browser controller ${this.#browserControllerType} doesnot support browserType ${browserType}`);
|
|
5535
|
+
}
|
|
5536
|
+
this.#browserCreationMethod = browserCreateMethod;
|
|
5537
|
+
this.#headless = headless;
|
|
5538
|
+
this.#proxy = options?.proxy ? Object.assign({}, options.proxy) : null;
|
|
5539
|
+
this.#options = Object.assign({}, options, { closeFreePagesIntervalSeconds, maxPageFreeSeconds, maxViewportOfNewPage, headless, executablePath, proxy: this.#proxy });
|
|
5540
|
+
this.#executablePath = executablePath;
|
|
5541
|
+
this.#nextBrowserContextIdx = 1;
|
|
5542
|
+
this.#closeFreePagesIntervalId = null;
|
|
5543
|
+
loginfo(`##browser ${this.id()} ${this.#browserCreationMethod}ed by ${this.#browserControllerType}`);
|
|
5544
|
+
const browserContexts = browser.contexts();
|
|
5545
|
+
if (browserContexts.length > 0) {
|
|
5546
|
+
logwarn(`There are ${browserContexts.length} new browserContexts when playwright launches new browser`);
|
|
5547
|
+
}
|
|
5548
|
+
const incognito = typeof options?.incognito === "boolean" ? options.incognito : true;
|
|
5549
|
+
for (const browserContext of browserContexts) {
|
|
5550
|
+
const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "launch", incognito, this.#proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), maxViewportOfNewPage);
|
|
5551
|
+
this.#lsdBrowserContexts.push(lsdBrowserContext);
|
|
5552
|
+
loginfo(`##browserContext ${lsdBrowserContext.id()} ${this.#browserCreationMethod}ed`);
|
|
5553
|
+
}
|
|
5554
|
+
browser.on("disconnected", () => {
|
|
5555
|
+
loginfo(`##browser ${this.id()} disconnected`);
|
|
5556
|
+
if (this.#lsdBrowserContexts.length > 0) {
|
|
5557
|
+
logerr(`${this.id()} has browserContexts when disconnected`);
|
|
5558
|
+
}
|
|
5559
|
+
});
|
|
5560
|
+
this.on("browserContextClose", (lsdBrowserContext) => {
|
|
5561
|
+
if (!(lsdBrowserContext instanceof PatchrightBrowserContext)) {
|
|
5562
|
+
logerr(`Invalid data in LsdBrowser.on("browserContextClose)`);
|
|
5563
|
+
return;
|
|
5564
|
+
}
|
|
5565
|
+
const idx = this.#lsdBrowserContexts.findIndex((bc) => bc === lsdBrowserContext);
|
|
5566
|
+
if (idx < 0) {
|
|
5567
|
+
logerr(`Invalid lsdBrowserContext in LsdBrowser.on("browserContextClose)`);
|
|
5568
|
+
return;
|
|
5569
|
+
}
|
|
5570
|
+
loginfo(`##browserContext ${lsdBrowserContext.id()} closed
|
|
5571
|
+
`);
|
|
5572
|
+
this.#lsdBrowserContexts.splice(idx, 1);
|
|
5573
|
+
if (this.#lsdBrowserContexts.length === 0) {
|
|
5574
|
+
loginfo(`##browser ${this.id()} has no browserContexts now`);
|
|
5575
|
+
}
|
|
5576
|
+
return;
|
|
5577
|
+
});
|
|
5578
|
+
if (closeFreePagesIntervalSeconds > 0 && maxPageFreeSeconds > 0) {
|
|
5579
|
+
this.#closeFreePagesIntervalId = setInterval(async () => {
|
|
5580
|
+
await this.#closeFreePagesHandler();
|
|
5581
|
+
}, closeFreePagesIntervalSeconds * 1e3);
|
|
5582
|
+
}
|
|
5583
|
+
}
|
|
5584
|
+
async #closeFreePagesHandler() {
|
|
5585
|
+
for (const lsdBrowserContext of this.#lsdBrowserContexts) {
|
|
5586
|
+
await lsdBrowserContext.closeFreePages();
|
|
5587
|
+
}
|
|
5588
|
+
}
|
|
5589
|
+
async newBrowserContext(options) {
|
|
5590
|
+
if (this.#lsdBrowserContexts.length >= this.#maxBrowserContextsPerBrowser()) {
|
|
5591
|
+
logwarn(`##browser ${this.id()} can not create more new browserContext`);
|
|
5592
|
+
return null;
|
|
5593
|
+
}
|
|
5594
|
+
const browserContextOptions = {};
|
|
5595
|
+
if (this.#options.maxWindowSize) {
|
|
5596
|
+
browserContextOptions.viewport = null;
|
|
5597
|
+
}
|
|
5598
|
+
const proxy = options?.proxy ? Object.assign({}, options.proxy) : this.#proxy;
|
|
5599
|
+
if (proxy) {
|
|
5600
|
+
const { proxyUrl: server, username, password } = proxy;
|
|
5601
|
+
browserContextOptions.proxy = { server, username, password };
|
|
5602
|
+
}
|
|
5603
|
+
if (options?.userAgent) {
|
|
5604
|
+
browserContextOptions.userAgent = options.userAgent;
|
|
5605
|
+
}
|
|
5606
|
+
const browserContext = await this.#browser.newContext(browserContextOptions);
|
|
5607
|
+
const { maxViewportOfNewPage = this.#options.maxViewportOfNewPage } = options ? options : {};
|
|
5608
|
+
const lsdBrowserContext = new PatchrightBrowserContext(this, browserContext, "new", true, proxy, this.#browserIdx, this.#nextBrowserContextIdx++, this.#maxPagesPerBrowserContext(), this.#maxPageFreeSeconds(), maxViewportOfNewPage);
|
|
5609
|
+
this.#lsdBrowserContexts.push(lsdBrowserContext);
|
|
5610
|
+
loginfo(`##browser ${lsdBrowserContext.id()} created`);
|
|
5611
|
+
return lsdBrowserContext;
|
|
5612
|
+
}
|
|
5613
|
+
async close() {
|
|
5614
|
+
if (this.#closeFreePagesIntervalId) {
|
|
5615
|
+
clearInterval(this.#closeFreePagesIntervalId);
|
|
5616
|
+
}
|
|
5617
|
+
for (const lsdBrowserContext of this.#lsdBrowserContexts) {
|
|
5618
|
+
await lsdBrowserContext.close();
|
|
5619
|
+
}
|
|
5620
|
+
await this.#browser.close();
|
|
5621
|
+
return true;
|
|
5622
|
+
}
|
|
5623
|
+
browserContexts() {
|
|
5624
|
+
return this.#lsdBrowserContexts;
|
|
5625
|
+
}
|
|
5626
|
+
browserControllerType() {
|
|
5627
|
+
return this.#browserControllerType;
|
|
5628
|
+
}
|
|
5629
|
+
browserCreationMethod() {
|
|
5630
|
+
return this.#browserCreationMethod;
|
|
5631
|
+
}
|
|
5632
|
+
browserType() {
|
|
5633
|
+
return this.#browserType;
|
|
5634
|
+
}
|
|
5635
|
+
createTime() {
|
|
5636
|
+
return this.#createTime;
|
|
5637
|
+
}
|
|
5638
|
+
doesMeetBrowserContextRequirements(browserContextRequirements) {
|
|
5639
|
+
const { browserControllerTypes, browserTypes, browserHeadlesses } = browserContextRequirements;
|
|
5640
|
+
return (browserControllerTypes.length === 0 || browserControllerTypes.includes(this.#browserControllerType)) && (browserTypes.length === 0 || browserTypes.includes(this.#browserType)) && (browserHeadlesses.length === 0 || browserHeadlesses.includes(this.#headless));
|
|
5641
|
+
}
|
|
5642
|
+
executablePath() {
|
|
5643
|
+
return this.#executablePath;
|
|
5644
|
+
}
|
|
5645
|
+
id() {
|
|
5646
|
+
return `browser-${this.#browserType}-${this.#browserIdx}`;
|
|
5647
|
+
}
|
|
5648
|
+
isConnected() {
|
|
5649
|
+
return this.#browser.isConnected();
|
|
5650
|
+
}
|
|
5651
|
+
isHeadless() {
|
|
5652
|
+
return this.#headless;
|
|
5653
|
+
}
|
|
5654
|
+
options() {
|
|
5655
|
+
return this.#options;
|
|
5656
|
+
}
|
|
5657
|
+
pid() {
|
|
5658
|
+
return this.#pid;
|
|
5659
|
+
}
|
|
5660
|
+
async pidUsage() {
|
|
5661
|
+
if (this.#pid > 0) {
|
|
5662
|
+
const usage = await (0, import_utils13.getPerformanceOfPidTree)(this.#pid, "MB");
|
|
5663
|
+
return usage;
|
|
5664
|
+
} else {
|
|
5665
|
+
return { cpu: 0, memory: 0 };
|
|
5666
|
+
}
|
|
5667
|
+
}
|
|
5668
|
+
proxy() {
|
|
5669
|
+
return this.#proxy;
|
|
5670
|
+
}
|
|
5671
|
+
async version() {
|
|
5672
|
+
const version = await this.#browser.version();
|
|
5673
|
+
return version;
|
|
5674
|
+
}
|
|
5675
|
+
_origBrowser() {
|
|
5676
|
+
return this.#browser;
|
|
5677
|
+
}
|
|
5678
|
+
};
|
|
5679
|
+
|
|
5680
|
+
// src/controller/controller.ts
|
|
5681
|
+
var import_utils14 = require("@letsscrapedata/utils");
|
|
5682
|
+
var LsdBrowserController = class _LsdBrowserController {
|
|
5683
|
+
static #forbidConstructor = false;
|
|
5684
|
+
#puppeteer;
|
|
5685
|
+
#playwrightBrowserTypes;
|
|
5686
|
+
#patchrightBrowserTypes;
|
|
5687
|
+
#nextBrowserIdx;
|
|
5688
|
+
/**
|
|
5689
|
+
* Possible values are 'aix', 'darwin', 'freebsd','linux', 'openbsd', 'sunos', and 'win32'.
|
|
5690
|
+
*/
|
|
5691
|
+
#osPlatform;
|
|
5692
|
+
constructor() {
|
|
5693
|
+
if (_LsdBrowserController.#forbidConstructor) {
|
|
5694
|
+
throw new Error("Only one LsdBrowserController instance can be created!");
|
|
5695
|
+
}
|
|
5696
|
+
this.#puppeteer = import_puppeteer.default;
|
|
5697
|
+
this.#playwrightBrowserTypes = {
|
|
5698
|
+
chromium: import_playwright.default.chromium,
|
|
5699
|
+
firefox: import_playwright.default.firefox,
|
|
5700
|
+
webkit: import_playwright.default.webkit
|
|
5701
|
+
};
|
|
5702
|
+
this.#patchrightBrowserTypes = {
|
|
5703
|
+
chromium: import_patchright.default.chromium,
|
|
5704
|
+
firefox: import_patchright.default.firefox,
|
|
5705
|
+
webkit: import_patchright.default.webkit
|
|
5706
|
+
};
|
|
5707
|
+
this.#osPlatform = import_os.default.platform();
|
|
5708
|
+
this.#nextBrowserIdx = 1;
|
|
5709
|
+
_LsdBrowserController.#forbidConstructor = true;
|
|
5710
|
+
}
|
|
5711
|
+
#playwrightBrowserType(browserType, connectFlag = false) {
|
|
5712
|
+
if (browserType === "chromium") {
|
|
5713
|
+
return this.#playwrightBrowserTypes.chromium;
|
|
5714
|
+
} else if (connectFlag) {
|
|
5715
|
+
throw new Error(`playwright only can connect to chromium browser, not support ${browserType} browser`);
|
|
5716
|
+
} else if (browserType === "firefox") {
|
|
5717
|
+
return this.#playwrightBrowserTypes.firefox;
|
|
5718
|
+
} else if (browserType === "webkit") {
|
|
5719
|
+
return this.#playwrightBrowserTypes.webkit;
|
|
5720
|
+
} else {
|
|
5721
|
+
throw new Error(`Invalid playwright browserType ${browserType}`);
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5724
|
+
#patchrightBrowserType(browserType, connectFlag = false) {
|
|
5725
|
+
if (browserType === "chromium") {
|
|
5726
|
+
return this.#patchrightBrowserTypes.chromium;
|
|
5727
|
+
} else if (connectFlag) {
|
|
5728
|
+
throw new Error(`patchright only can connect to chromium browser, not support ${browserType} browser`);
|
|
5729
|
+
} else if (browserType === "firefox") {
|
|
5730
|
+
return this.#patchrightBrowserTypes.firefox;
|
|
5731
|
+
} else if (browserType === "webkit") {
|
|
5732
|
+
return this.#patchrightBrowserTypes.webkit;
|
|
5733
|
+
} else {
|
|
5734
|
+
throw new Error(`Invalid patchright browserType ${browserType}`);
|
|
5735
|
+
}
|
|
5736
|
+
}
|
|
5737
|
+
#puppeteerProduct(browserType) {
|
|
5738
|
+
if (browserType === "chromium") {
|
|
5739
|
+
return "chrome";
|
|
5740
|
+
} else {
|
|
5741
|
+
throw new Error(`Invalid puppeteer product ${browserType}`);
|
|
5742
|
+
}
|
|
5743
|
+
}
|
|
5744
|
+
setBrowserPlugin(browserControllerType, browserType, plugin) {
|
|
5745
|
+
if (browserControllerType === "puppeteer") {
|
|
5746
|
+
if (!PuppeteerBrowser.doesSupport(browserType)) {
|
|
5747
|
+
throw new Error(`BrowserControllerType ${browserControllerType} doesnot support browserType ${browserType}`);
|
|
5748
|
+
}
|
|
5749
|
+
this.#puppeteer = plugin;
|
|
5750
|
+
} else if (browserControllerType === "playwright") {
|
|
5751
|
+
if (!PlaywrightBrowser.doesSupport(browserType)) {
|
|
5752
|
+
throw new Error(`BrowserControllerType ${browserControllerType} doesnot support browserType ${browserType}`);
|
|
5753
|
+
}
|
|
5754
|
+
switch (browserType) {
|
|
5755
|
+
case "chromium":
|
|
5756
|
+
case "firefox":
|
|
5757
|
+
case "webkit":
|
|
5758
|
+
this.#playwrightBrowserTypes[browserType] = plugin;
|
|
5759
|
+
break;
|
|
5760
|
+
default:
|
|
5761
|
+
(0, import_utils14.unreachable)(browserType);
|
|
5762
|
+
}
|
|
5763
|
+
} else if (browserControllerType === "patchright") {
|
|
5764
|
+
if (!PatchrightBrowser.doesSupport(browserType)) {
|
|
5765
|
+
throw new Error(`BrowserControllerType ${browserControllerType} doesnot support browserType ${browserType}`);
|
|
5766
|
+
}
|
|
5767
|
+
switch (browserType) {
|
|
5768
|
+
case "chromium":
|
|
5769
|
+
case "firefox":
|
|
5770
|
+
case "webkit":
|
|
5771
|
+
this.#patchrightBrowserTypes[browserType] = plugin;
|
|
5772
|
+
break;
|
|
5773
|
+
default:
|
|
5774
|
+
(0, import_utils14.unreachable)(browserType);
|
|
5775
|
+
}
|
|
5776
|
+
} else {
|
|
5777
|
+
(0, import_utils14.unreachable)(browserControllerType);
|
|
5778
|
+
}
|
|
5779
|
+
return true;
|
|
5780
|
+
}
|
|
5781
|
+
async launch(browserControllerType, browserType, options) {
|
|
5782
|
+
let {
|
|
5783
|
+
closeFreePagesIntervalSeconds = 300,
|
|
5784
|
+
maxBrowserContextsPerBrowser = 10,
|
|
5785
|
+
maxPagesPerBrowserContext = 20,
|
|
5786
|
+
maxPageFreeSeconds = 900,
|
|
5787
|
+
maxViewportOfNewPage = true,
|
|
5788
|
+
proxy = null,
|
|
5789
|
+
timeout = 3e4,
|
|
5790
|
+
args = [],
|
|
5791
|
+
executablePath = "",
|
|
5792
|
+
maxWindowSize = true,
|
|
5793
|
+
headless = true,
|
|
5794
|
+
minBrowserContexts = 1,
|
|
5795
|
+
// incognito
|
|
5796
|
+
proxyPerBrowserContext = false,
|
|
5797
|
+
userDataDir = "",
|
|
5798
|
+
userAgent = ""
|
|
5799
|
+
} = options ? options : {};
|
|
5800
|
+
let browserPid = 0;
|
|
5801
|
+
const incognito = typeof options?.incognito === "boolean" ? options.incognito : browserControllerType === "puppeteer" ? false : true;
|
|
5802
|
+
const actOptions = { closeFreePagesIntervalSeconds, maxBrowserContextsPerBrowser, maxPagesPerBrowserContext, maxPageFreeSeconds, maxViewportOfNewPage, proxy, timeout, args, executablePath, maxWindowSize, headless, minBrowserContexts, incognito, proxyPerBrowserContext, userDataDir, userAgent };
|
|
5803
|
+
let idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--incoginto"));
|
|
5804
|
+
if (idx >= 0) {
|
|
5805
|
+
logwarn(`Please use options.incognito instead when launching new browser.`);
|
|
5806
|
+
args.splice(idx, 1);
|
|
5807
|
+
}
|
|
5808
|
+
idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--proxy-server"));
|
|
5809
|
+
if (idx >= 0) {
|
|
5810
|
+
logwarn(`Please use options.proxy instead when launching new browser.`);
|
|
5811
|
+
args.splice(idx, 1);
|
|
5812
|
+
}
|
|
5813
|
+
idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--user-data-dir"));
|
|
5814
|
+
if (idx >= 0) {
|
|
5815
|
+
logwarn(`Please use options.userDataDir instead when launching new browser.`);
|
|
5816
|
+
args.splice(idx, 1);
|
|
5817
|
+
}
|
|
5818
|
+
idx = args.findIndex((arg) => arg.toLowerCase().startsWith("--start-maximized"));
|
|
5819
|
+
if (idx >= 0) {
|
|
5820
|
+
logwarn(`Please use options.maxWindowSize instead when launching new browser.`);
|
|
5821
|
+
args.splice(idx, 1);
|
|
5822
|
+
}
|
|
5823
|
+
let lsdBrowser;
|
|
5824
|
+
if (browserControllerType === "playwright") {
|
|
5825
|
+
const launchOptions = { headless, timeout };
|
|
5826
|
+
if (executablePath) {
|
|
5827
|
+
launchOptions.executablePath = executablePath;
|
|
5828
|
+
}
|
|
5829
|
+
if (maxWindowSize) {
|
|
5830
|
+
args.push("--start-maximized");
|
|
5831
|
+
}
|
|
5832
|
+
if (proxy?.proxyUrl && proxy.proxyUrl !== "local") {
|
|
5833
|
+
const { proxyUrl: server, username, password } = proxy;
|
|
5834
|
+
launchOptions.proxy = { server, username, password };
|
|
5835
|
+
} else if (proxyPerBrowserContext && browserType === "chromium" && this.#osPlatform.startsWith("win")) {
|
|
5836
|
+
launchOptions.proxy = { server: "proxyPerBrowserContext" };
|
|
5837
|
+
}
|
|
5838
|
+
if (browserType === "chromium") {
|
|
5839
|
+
if (incognito) {
|
|
5840
|
+
args.push("--incognito");
|
|
5841
|
+
} else if (userDataDir) {
|
|
5842
|
+
args.push(`--user-data-dir=${userDataDir}`);
|
|
4016
5843
|
}
|
|
4017
5844
|
}
|
|
4018
5845
|
if (args.length > 0) {
|
|
@@ -4035,6 +5862,47 @@ var LsdBrowserController = class _LsdBrowserController {
|
|
|
4035
5862
|
const browser = await playwrightBrowserType.launch(launchOptions);
|
|
4036
5863
|
lsdBrowser = new PlaywrightBrowser(browser, browserType, "launch", actOptions, this.#nextBrowserIdx++, browserPid);
|
|
4037
5864
|
}
|
|
5865
|
+
} else if (browserControllerType === "patchright") {
|
|
5866
|
+
const launchOptions = { headless, timeout };
|
|
5867
|
+
if (executablePath) {
|
|
5868
|
+
launchOptions.executablePath = executablePath;
|
|
5869
|
+
}
|
|
5870
|
+
if (maxWindowSize) {
|
|
5871
|
+
args.push("--start-maximized");
|
|
5872
|
+
}
|
|
5873
|
+
if (proxy?.proxyUrl && proxy.proxyUrl !== "local") {
|
|
5874
|
+
const { proxyUrl: server, username, password } = proxy;
|
|
5875
|
+
launchOptions.proxy = { server, username, password };
|
|
5876
|
+
} else if (proxyPerBrowserContext && browserType === "chromium" && this.#osPlatform.startsWith("win")) {
|
|
5877
|
+
launchOptions.proxy = { server: "proxyPerBrowserContext" };
|
|
5878
|
+
}
|
|
5879
|
+
if (browserType === "chromium") {
|
|
5880
|
+
if (incognito) {
|
|
5881
|
+
args.push("--incognito");
|
|
5882
|
+
} else if (userDataDir) {
|
|
5883
|
+
args.push(`--user-data-dir=${userDataDir}`);
|
|
5884
|
+
}
|
|
5885
|
+
}
|
|
5886
|
+
if (args.length > 0) {
|
|
5887
|
+
launchOptions.args = args;
|
|
5888
|
+
}
|
|
5889
|
+
const patchrightBrowserType = this.#patchrightBrowserType(browserType);
|
|
5890
|
+
if (!actOptions.executablePath) {
|
|
5891
|
+
actOptions.executablePath = patchrightBrowserType.executablePath();
|
|
5892
|
+
}
|
|
5893
|
+
if (options.launchMethod === "launchServer") {
|
|
5894
|
+
const browserServer = await patchrightBrowserType.launchServer(launchOptions);
|
|
5895
|
+
const process = browserServer.process();
|
|
5896
|
+
if (process?.pid) {
|
|
5897
|
+
browserPid = process.pid;
|
|
5898
|
+
}
|
|
5899
|
+
const wsEndpoint = browserServer.wsEndpoint();
|
|
5900
|
+
const browser = await patchrightBrowserType.connect(wsEndpoint);
|
|
5901
|
+
lsdBrowser = new PatchrightBrowser(browser, browserType, "launch", actOptions, this.#nextBrowserIdx++, browserPid);
|
|
5902
|
+
} else {
|
|
5903
|
+
const browser = await patchrightBrowserType.launch(launchOptions);
|
|
5904
|
+
lsdBrowser = new PatchrightBrowser(browser, browserType, "launch", actOptions, this.#nextBrowserIdx++, browserPid);
|
|
5905
|
+
}
|
|
4038
5906
|
} else if (browserControllerType === "puppeteer") {
|
|
4039
5907
|
const product = this.#puppeteerProduct(browserType);
|
|
4040
5908
|
const launchOptions = { headless, timeout, product };
|
|
@@ -4100,7 +5968,7 @@ var LsdBrowserController = class _LsdBrowserController {
|
|
|
4100
5968
|
}
|
|
4101
5969
|
const u = new URL(browserUrl);
|
|
4102
5970
|
const port = u.port ? parseInt(u.port) : 80;
|
|
4103
|
-
const pids = await (0,
|
|
5971
|
+
const pids = await (0, import_utils14.getPidsListeningOnPort)(port);
|
|
4104
5972
|
let browserPid = 0;
|
|
4105
5973
|
if (pids.length !== 1) {
|
|
4106
5974
|
logerr(`##browser pids.length ${pids.length} is not 1 when trying to connect to browserUrl ${browserUrl}`);
|
|
@@ -4113,6 +5981,11 @@ var LsdBrowserController = class _LsdBrowserController {
|
|
|
4113
5981
|
const browser = await playwrightBrowserType.connectOverCDP(browserUrl);
|
|
4114
5982
|
const lsdBrowser = new PlaywrightBrowser(browser, browserType, "connect", actOptions, this.#nextBrowserIdx++, browserPid);
|
|
4115
5983
|
return lsdBrowser;
|
|
5984
|
+
} else if (browserControllerType === "patchright") {
|
|
5985
|
+
const patchrightBrowserType = this.#patchrightBrowserType(browserType, true);
|
|
5986
|
+
const browser = await patchrightBrowserType.connectOverCDP(browserUrl);
|
|
5987
|
+
const lsdBrowser = new PatchrightBrowser(browser, browserType, "connect", actOptions, this.#nextBrowserIdx++, browserPid);
|
|
5988
|
+
return lsdBrowser;
|
|
4116
5989
|
} else if (browserControllerType === "puppeteer") {
|
|
4117
5990
|
this.#puppeteerProduct(browserType);
|
|
4118
5991
|
const browser = await this.#puppeteer.connect({ browserURL: browserUrl });
|