@skrillex1224/playwright-toolkit 2.1.136 → 2.1.138
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 +103 -95
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +105 -97
- package/dist/index.js.map +3 -3
- package/index.d.ts +0 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1432,7 +1432,7 @@ var Captcha = {
|
|
|
1432
1432
|
|
|
1433
1433
|
// src/sse.js
|
|
1434
1434
|
import https from "https";
|
|
1435
|
-
import { URL
|
|
1435
|
+
import { URL } from "url";
|
|
1436
1436
|
var logger8 = createInternalLogger("Sse");
|
|
1437
1437
|
var Sse = {
|
|
1438
1438
|
/**
|
|
@@ -1542,7 +1542,7 @@ var Sse = {
|
|
|
1542
1542
|
try {
|
|
1543
1543
|
const headers = await request.allHeaders();
|
|
1544
1544
|
const postData = request.postData();
|
|
1545
|
-
const urlObj = new
|
|
1545
|
+
const urlObj = new URL(request.url());
|
|
1546
1546
|
delete headers["accept-encoding"];
|
|
1547
1547
|
delete headers["content-length"];
|
|
1548
1548
|
const reqOptions = {
|
|
@@ -1825,7 +1825,6 @@ var Interception = {
|
|
|
1825
1825
|
* @param {Object} [options] - 配置选项
|
|
1826
1826
|
* @param {string[]} [options.directDomains] - [已过时] 需要直连的域名列表,请改用 directConfig.domains
|
|
1827
1827
|
* @param {Object} [options.directConfig] - 直连配置(参考 blockingConfig),支持 domains/directAllXxx 系列开关
|
|
1828
|
-
* @param {boolean|Function} [options.enable] - 是否启用拦截处理(false 时始终 continue)
|
|
1829
1828
|
* @param {Object} [options.blockingConfig] - 资源屏蔽配置
|
|
1830
1829
|
* @param {boolean} [options.fallbackToProxy] - 直连失败时是否回退到代理(默认 true)
|
|
1831
1830
|
* @returns {Promise<void>}
|
|
@@ -1834,7 +1833,6 @@ var Interception = {
|
|
|
1834
1833
|
const {
|
|
1835
1834
|
directDomains = [],
|
|
1836
1835
|
directConfig = {},
|
|
1837
|
-
enable = true,
|
|
1838
1836
|
blockingConfig = {},
|
|
1839
1837
|
fallbackToProxy = true
|
|
1840
1838
|
} = options;
|
|
@@ -1854,6 +1852,16 @@ var Interception = {
|
|
|
1854
1852
|
)
|
|
1855
1853
|
);
|
|
1856
1854
|
const hasDirectExtensions = normalizedDirectExtensions.length > 0;
|
|
1855
|
+
const blockedExtensionsSet = new Set(blockedExtensions);
|
|
1856
|
+
const directOnlyExtensions = normalizedDirectExtensions.filter((ext) => !blockedExtensionsSet.has(ext));
|
|
1857
|
+
const directRouteMatchers = [
|
|
1858
|
+
createDomainsRegex(normalizedDirectDomains),
|
|
1859
|
+
createExtensionsRegex(directOnlyExtensions)
|
|
1860
|
+
].filter(Boolean);
|
|
1861
|
+
const blockRouteMatchers = [createExtensionsRegex(blockedExtensions)].filter(Boolean);
|
|
1862
|
+
const hasDirectRules = directRouteMatchers.length > 0;
|
|
1863
|
+
const hasBlockRules = blockRouteMatchers.length > 0;
|
|
1864
|
+
const hasInterceptionRules = hasDirectRules || hasBlockRules;
|
|
1857
1865
|
const enabledCategories = [];
|
|
1858
1866
|
if (mergedBlockingConfig.blockArchive) enabledCategories.push("\u538B\u7F29\u5305");
|
|
1859
1867
|
if (mergedBlockingConfig.blockExecutable) enabledCategories.push("\u53EF\u6267\u884C\u6587\u4EF6");
|
|
@@ -1867,110 +1875,83 @@ var Interception = {
|
|
|
1867
1875
|
if (hasDirectDomains) directRules.push(`\u76F4\u8FDE\u57DF\u540D: [${normalizedDirectDomains.length} \u4E2A]`);
|
|
1868
1876
|
if (hasDirectExtensions) directRules.push(`\u76F4\u8FDE\u6269\u5C55\u540D: [${normalizedDirectExtensions.join(", ")}]`);
|
|
1869
1877
|
logger9.start("setup", directRules.length > 0 ? `${directRules.join(" | ")} | \u5C4F\u853D: [${enabledCategories.join(", ")}]` : `\u4EC5\u8D44\u6E90\u5C4F\u853D\u6A21\u5F0F | \u5C4F\u853D: [${enabledCategories.join(", ")}]`);
|
|
1870
|
-
|
|
1871
|
-
|
|
1878
|
+
if (!hasInterceptionRules) {
|
|
1879
|
+
logger9.info("\u65E0\u547D\u4E2D\u89C4\u5219\uFF0C\u8DF3\u8FC7 page.route \u6CE8\u518C");
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
const directRouteHandler = async (route) => {
|
|
1872
1883
|
try {
|
|
1873
1884
|
const request = route.request();
|
|
1874
1885
|
const url = request.url();
|
|
1875
1886
|
const urlLower = url.toLowerCase();
|
|
1876
1887
|
const urlPath = urlLower.split("?")[0];
|
|
1877
|
-
const interceptionEnabled = typeof enable === "function" ? Boolean(enable()) : Boolean(enable);
|
|
1878
|
-
if (!interceptionEnabled) {
|
|
1879
|
-
await safeContinue(route);
|
|
1880
|
-
handled = true;
|
|
1881
|
-
return;
|
|
1882
|
-
}
|
|
1883
1888
|
const isSilent = DirectConfig.silentExtensions.some((ext) => urlPath.endsWith(ext));
|
|
1884
|
-
const
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
url,
|
|
1912
|
-
method,
|
|
1913
|
-
headers: reqHeaders,
|
|
1914
|
-
body: postData,
|
|
1915
|
-
responseType: "buffer",
|
|
1916
|
-
// 强制获取 Buffer
|
|
1917
|
-
// 移除手动 TLS 指纹配置,使用 got-scraping 默认的高质量指纹
|
|
1918
|
-
// headerGeneratorOptions: ...
|
|
1919
|
-
// 使用共享的 Agent 单例(keepAlive: false,不会池化连接)
|
|
1920
|
-
agent: {
|
|
1921
|
-
http: SHARED_HTTP_AGENT,
|
|
1922
|
-
https: SHARED_HTTPS_AGENT
|
|
1923
|
-
},
|
|
1924
|
-
// 超时时间
|
|
1925
|
-
timeout: { request: DirectConfig.directTimeout * 1e3 }
|
|
1926
|
-
});
|
|
1927
|
-
const resHeaders = {};
|
|
1928
|
-
for (const [key, value] of Object.entries(response.headers)) {
|
|
1929
|
-
if (Array.isArray(value)) {
|
|
1930
|
-
resHeaders[key] = value.join(", ");
|
|
1931
|
-
} else if (value) {
|
|
1932
|
-
resHeaders[key] = String(value);
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
delete resHeaders["content-encoding"];
|
|
1936
|
-
delete resHeaders["content-length"];
|
|
1937
|
-
delete resHeaders["transfer-encoding"];
|
|
1938
|
-
delete resHeaders["connection"];
|
|
1939
|
-
delete resHeaders["keep-alive"];
|
|
1940
|
-
isSilent ? logger9.debug(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`) : logger9.info(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`);
|
|
1941
|
-
await safeFulfill(route, {
|
|
1942
|
-
status: response.statusCode,
|
|
1943
|
-
headers: resHeaders,
|
|
1944
|
-
body: response.body
|
|
1945
|
-
});
|
|
1946
|
-
handled = true;
|
|
1947
|
-
return;
|
|
1948
|
-
} catch (e) {
|
|
1949
|
-
const isTimeout = e.code === "ETIMEDOUT" || e.message.toLowerCase().includes("timeout");
|
|
1950
|
-
const action = fallbackToProxy ? "\u56DE\u9000\u4EE3\u7406" : "\u5DF2\u653E\u5F03";
|
|
1951
|
-
const reason = isTimeout ? `\u8D85\u65F6(${DirectConfig.directTimeout}s)` : `\u5F02\u5E38: ${e.message}`;
|
|
1952
|
-
logger9.warn(`\u76F4\u8FDE${reason}\uFF0C${action}: ${urlPath}`);
|
|
1953
|
-
if (fallbackToProxy) {
|
|
1954
|
-
await safeContinue(route);
|
|
1955
|
-
} else {
|
|
1956
|
-
await route.abort();
|
|
1957
|
-
}
|
|
1958
|
-
handled = true;
|
|
1959
|
-
return;
|
|
1889
|
+
const reqHeaders = await request.allHeaders();
|
|
1890
|
+
delete reqHeaders["host"];
|
|
1891
|
+
const method = request.method();
|
|
1892
|
+
const postData = method !== "GET" && method !== "HEAD" ? request.postDataBuffer() : void 0;
|
|
1893
|
+
const response = await gotScraping({
|
|
1894
|
+
...SHARED_GOT_OPTIONS,
|
|
1895
|
+
// 应用通用配置
|
|
1896
|
+
url,
|
|
1897
|
+
method,
|
|
1898
|
+
headers: reqHeaders,
|
|
1899
|
+
body: postData,
|
|
1900
|
+
responseType: "buffer",
|
|
1901
|
+
// 强制获取 Buffer
|
|
1902
|
+
// 使用共享的 Agent 单例(keepAlive: false,不会池化连接)
|
|
1903
|
+
agent: {
|
|
1904
|
+
http: SHARED_HTTP_AGENT,
|
|
1905
|
+
https: SHARED_HTTPS_AGENT
|
|
1906
|
+
},
|
|
1907
|
+
// 超时时间
|
|
1908
|
+
timeout: { request: DirectConfig.directTimeout * 1e3 }
|
|
1909
|
+
});
|
|
1910
|
+
const resHeaders = {};
|
|
1911
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
1912
|
+
if (Array.isArray(value)) {
|
|
1913
|
+
resHeaders[key] = value.join(", ");
|
|
1914
|
+
} else if (value) {
|
|
1915
|
+
resHeaders[key] = String(value);
|
|
1960
1916
|
}
|
|
1961
1917
|
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1918
|
+
delete resHeaders["content-encoding"];
|
|
1919
|
+
delete resHeaders["content-length"];
|
|
1920
|
+
delete resHeaders["transfer-encoding"];
|
|
1921
|
+
delete resHeaders["connection"];
|
|
1922
|
+
delete resHeaders["keep-alive"];
|
|
1923
|
+
isSilent ? logger9.debug(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`) : logger9.info(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`);
|
|
1924
|
+
await safeFulfill(route, {
|
|
1925
|
+
status: response.statusCode,
|
|
1926
|
+
headers: resHeaders,
|
|
1927
|
+
body: response.body
|
|
1928
|
+
});
|
|
1964
1929
|
} catch (err) {
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1930
|
+
const message = String(err?.message || "");
|
|
1931
|
+
const isTimeout = err?.code === "ETIMEDOUT" || message.toLowerCase().includes("timeout");
|
|
1932
|
+
const action = fallbackToProxy ? "\u56DE\u9000\u4EE3\u7406" : "\u5DF2\u653E\u5F03";
|
|
1933
|
+
const reason = isTimeout ? `\u8D85\u65F6(${DirectConfig.directTimeout}s)` : `\u5F02\u5E38: ${message}`;
|
|
1934
|
+
logger9.warn(`\u76F4\u8FDE${reason}\uFF0C${action}`);
|
|
1935
|
+
if (fallbackToProxy) {
|
|
1936
|
+
await safeContinue(route);
|
|
1937
|
+
} else {
|
|
1938
|
+
await safeAbort(route);
|
|
1971
1939
|
}
|
|
1972
1940
|
}
|
|
1973
|
-
}
|
|
1941
|
+
};
|
|
1942
|
+
const blockRouteHandler = async (route) => {
|
|
1943
|
+
await safeAbort(route);
|
|
1944
|
+
};
|
|
1945
|
+
if (hasDirectRules) {
|
|
1946
|
+
for (const matcher of directRouteMatchers) {
|
|
1947
|
+
await page.route(matcher, directRouteHandler);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
if (hasBlockRules) {
|
|
1951
|
+
for (const matcher of blockRouteMatchers) {
|
|
1952
|
+
await page.route(matcher, blockRouteHandler);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1974
1955
|
}
|
|
1975
1956
|
};
|
|
1976
1957
|
async function safeFulfill(route, options) {
|
|
@@ -1990,10 +1971,37 @@ async function safeContinue(route) {
|
|
|
1990
1971
|
}
|
|
1991
1972
|
}
|
|
1992
1973
|
}
|
|
1974
|
+
async function safeAbort(route) {
|
|
1975
|
+
try {
|
|
1976
|
+
await route.abort();
|
|
1977
|
+
} catch (error) {
|
|
1978
|
+
if (!isIgnorableError(error)) {
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1993
1982
|
function isIgnorableError(error) {
|
|
1994
1983
|
const msg = error.message;
|
|
1995
1984
|
return msg.includes("already handled") || msg.includes("Target closed") || msg.includes("closed");
|
|
1996
1985
|
}
|
|
1986
|
+
function createExtensionsRegex(extensions = []) {
|
|
1987
|
+
const normalized = Array.from(new Set(
|
|
1988
|
+
extensions.map((ext) => String(ext || "").toLowerCase().trim()).filter(Boolean).map((ext) => ext.startsWith(".") ? ext : `.${ext}`)
|
|
1989
|
+
));
|
|
1990
|
+
if (!normalized.length) return null;
|
|
1991
|
+
const escaped = normalized.map((ext) => escapeRegex(ext));
|
|
1992
|
+
return new RegExp(`(?:${escaped.join("|")})(?:\\?.*)?$`, "i");
|
|
1993
|
+
}
|
|
1994
|
+
function createDomainsRegex(domains = []) {
|
|
1995
|
+
const normalized = Array.from(new Set(
|
|
1996
|
+
domains.map((domain) => String(domain || "").toLowerCase().trim()).filter(Boolean)
|
|
1997
|
+
));
|
|
1998
|
+
if (!normalized.length) return null;
|
|
1999
|
+
const domainParts = normalized.map((domain) => `${escapeRegex(domain)}[^/:?#]*`);
|
|
2000
|
+
return new RegExp(`^https?:\\/\\/(?:${domainParts.join("|")})(?::\\d+)?(?:[/?#]|$)`, "i");
|
|
2001
|
+
}
|
|
2002
|
+
function escapeRegex(value) {
|
|
2003
|
+
return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2004
|
+
}
|
|
1997
2005
|
|
|
1998
2006
|
// src/mutation.js
|
|
1999
2007
|
import { v4 as uuidv42 } from "uuid";
|