@skrillex1224/playwright-toolkit 2.1.135 → 2.1.137
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 +104 -90
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +106 -92
- package/dist/index.js.map +3 -3
- package/index.d.ts +0 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1851,7 +1851,6 @@ var Interception = {
|
|
|
1851
1851
|
* @param {import('playwright').Page} page - Playwright Page 对象
|
|
1852
1852
|
* @param {Object} [options] - 配置选项
|
|
1853
1853
|
* @param {string[]} [options.directDomains] - [已过时] 需要直连的域名列表,请改用 directConfig.domains
|
|
1854
|
-
* @param {string[]} [options.directExtensions] - 需要直连的扩展名(如 .js/.css)
|
|
1855
1854
|
* @param {Object} [options.directConfig] - 直连配置(参考 blockingConfig),支持 domains/directAllXxx 系列开关
|
|
1856
1855
|
* @param {Object} [options.blockingConfig] - 资源屏蔽配置
|
|
1857
1856
|
* @param {boolean} [options.fallbackToProxy] - 直连失败时是否回退到代理(默认 true)
|
|
@@ -1860,7 +1859,6 @@ var Interception = {
|
|
|
1860
1859
|
async setup(page, options = {}) {
|
|
1861
1860
|
const {
|
|
1862
1861
|
directDomains = [],
|
|
1863
|
-
directExtensions = [],
|
|
1864
1862
|
directConfig = {},
|
|
1865
1863
|
blockingConfig = {},
|
|
1866
1864
|
fallbackToProxy = true
|
|
@@ -1877,10 +1875,20 @@ var Interception = {
|
|
|
1877
1875
|
const hasDirectDomains = normalizedDirectDomains.length > 0;
|
|
1878
1876
|
const normalizedDirectExtensions = Array.from(
|
|
1879
1877
|
new Set(
|
|
1880
|
-
|
|
1878
|
+
configuredDirectExtensions.map((ext) => String(ext || "").toLowerCase().trim()).filter(Boolean).map((ext) => ext.startsWith(".") ? ext : `.${ext}`)
|
|
1881
1879
|
)
|
|
1882
1880
|
);
|
|
1883
1881
|
const hasDirectExtensions = normalizedDirectExtensions.length > 0;
|
|
1882
|
+
const blockedExtensionsSet = new Set(blockedExtensions);
|
|
1883
|
+
const directOnlyExtensions = normalizedDirectExtensions.filter((ext) => !blockedExtensionsSet.has(ext));
|
|
1884
|
+
const directRouteMatchers = [
|
|
1885
|
+
createDomainsRegex(normalizedDirectDomains),
|
|
1886
|
+
createExtensionsRegex(directOnlyExtensions)
|
|
1887
|
+
].filter(Boolean);
|
|
1888
|
+
const blockRouteMatchers = [createExtensionsRegex(blockedExtensions)].filter(Boolean);
|
|
1889
|
+
const hasDirectRules = directRouteMatchers.length > 0;
|
|
1890
|
+
const hasBlockRules = blockRouteMatchers.length > 0;
|
|
1891
|
+
const hasInterceptionRules = hasDirectRules || hasBlockRules;
|
|
1884
1892
|
const enabledCategories = [];
|
|
1885
1893
|
if (mergedBlockingConfig.blockArchive) enabledCategories.push("\u538B\u7F29\u5305");
|
|
1886
1894
|
if (mergedBlockingConfig.blockExecutable) enabledCategories.push("\u53EF\u6267\u884C\u6587\u4EF6");
|
|
@@ -1894,104 +1902,83 @@ var Interception = {
|
|
|
1894
1902
|
if (hasDirectDomains) directRules.push(`\u76F4\u8FDE\u57DF\u540D: [${normalizedDirectDomains.length} \u4E2A]`);
|
|
1895
1903
|
if (hasDirectExtensions) directRules.push(`\u76F4\u8FDE\u6269\u5C55\u540D: [${normalizedDirectExtensions.join(", ")}]`);
|
|
1896
1904
|
logger9.start("setup", directRules.length > 0 ? `${directRules.join(" | ")} | \u5C4F\u853D: [${enabledCategories.join(", ")}]` : `\u4EC5\u8D44\u6E90\u5C4F\u853D\u6A21\u5F0F | \u5C4F\u853D: [${enabledCategories.join(", ")}]`);
|
|
1897
|
-
|
|
1898
|
-
|
|
1905
|
+
if (!hasInterceptionRules) {
|
|
1906
|
+
logger9.info("\u65E0\u547D\u4E2D\u89C4\u5219\uFF0C\u8DF3\u8FC7 page.route \u6CE8\u518C");
|
|
1907
|
+
return;
|
|
1908
|
+
}
|
|
1909
|
+
const directRouteHandler = async (route) => {
|
|
1899
1910
|
try {
|
|
1900
1911
|
const request = route.request();
|
|
1901
1912
|
const url = request.url();
|
|
1902
1913
|
const urlLower = url.toLowerCase();
|
|
1903
1914
|
const urlPath = urlLower.split("?")[0];
|
|
1904
1915
|
const isSilent = DirectConfig.silentExtensions.some((ext) => urlPath.endsWith(ext));
|
|
1905
|
-
const
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
url,
|
|
1933
|
-
method,
|
|
1934
|
-
headers: reqHeaders,
|
|
1935
|
-
body: postData,
|
|
1936
|
-
responseType: "buffer",
|
|
1937
|
-
// 强制获取 Buffer
|
|
1938
|
-
// 移除手动 TLS 指纹配置,使用 got-scraping 默认的高质量指纹
|
|
1939
|
-
// headerGeneratorOptions: ...
|
|
1940
|
-
// 使用共享的 Agent 单例(keepAlive: false,不会池化连接)
|
|
1941
|
-
agent: {
|
|
1942
|
-
http: SHARED_HTTP_AGENT,
|
|
1943
|
-
https: SHARED_HTTPS_AGENT
|
|
1944
|
-
},
|
|
1945
|
-
// 超时时间
|
|
1946
|
-
timeout: { request: DirectConfig.directTimeout * 1e3 }
|
|
1947
|
-
});
|
|
1948
|
-
const resHeaders = {};
|
|
1949
|
-
for (const [key, value] of Object.entries(response.headers)) {
|
|
1950
|
-
if (Array.isArray(value)) {
|
|
1951
|
-
resHeaders[key] = value.join(", ");
|
|
1952
|
-
} else if (value) {
|
|
1953
|
-
resHeaders[key] = String(value);
|
|
1954
|
-
}
|
|
1955
|
-
}
|
|
1956
|
-
delete resHeaders["content-encoding"];
|
|
1957
|
-
delete resHeaders["content-length"];
|
|
1958
|
-
delete resHeaders["transfer-encoding"];
|
|
1959
|
-
delete resHeaders["connection"];
|
|
1960
|
-
delete resHeaders["keep-alive"];
|
|
1961
|
-
isSilent ? logger9.debug(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`) : logger9.info(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`);
|
|
1962
|
-
await safeFulfill(route, {
|
|
1963
|
-
status: response.statusCode,
|
|
1964
|
-
headers: resHeaders,
|
|
1965
|
-
body: response.body
|
|
1966
|
-
});
|
|
1967
|
-
handled = true;
|
|
1968
|
-
return;
|
|
1969
|
-
} catch (e) {
|
|
1970
|
-
const isTimeout = e.code === "ETIMEDOUT" || e.message.toLowerCase().includes("timeout");
|
|
1971
|
-
const action = fallbackToProxy ? "\u56DE\u9000\u4EE3\u7406" : "\u5DF2\u653E\u5F03";
|
|
1972
|
-
const reason = isTimeout ? `\u8D85\u65F6(${DirectConfig.directTimeout}s)` : `\u5F02\u5E38: ${e.message}`;
|
|
1973
|
-
logger9.warn(`\u76F4\u8FDE${reason}\uFF0C${action}: ${urlPath}`);
|
|
1974
|
-
if (fallbackToProxy) {
|
|
1975
|
-
await safeContinue(route);
|
|
1976
|
-
} else {
|
|
1977
|
-
await route.abort();
|
|
1978
|
-
}
|
|
1979
|
-
handled = true;
|
|
1980
|
-
return;
|
|
1916
|
+
const reqHeaders = await request.allHeaders();
|
|
1917
|
+
delete reqHeaders["host"];
|
|
1918
|
+
const method = request.method();
|
|
1919
|
+
const postData = method !== "GET" && method !== "HEAD" ? request.postDataBuffer() : void 0;
|
|
1920
|
+
const response = await (0, import_got_scraping.gotScraping)({
|
|
1921
|
+
...SHARED_GOT_OPTIONS,
|
|
1922
|
+
// 应用通用配置
|
|
1923
|
+
url,
|
|
1924
|
+
method,
|
|
1925
|
+
headers: reqHeaders,
|
|
1926
|
+
body: postData,
|
|
1927
|
+
responseType: "buffer",
|
|
1928
|
+
// 强制获取 Buffer
|
|
1929
|
+
// 使用共享的 Agent 单例(keepAlive: false,不会池化连接)
|
|
1930
|
+
agent: {
|
|
1931
|
+
http: SHARED_HTTP_AGENT,
|
|
1932
|
+
https: SHARED_HTTPS_AGENT
|
|
1933
|
+
},
|
|
1934
|
+
// 超时时间
|
|
1935
|
+
timeout: { request: DirectConfig.directTimeout * 1e3 }
|
|
1936
|
+
});
|
|
1937
|
+
const resHeaders = {};
|
|
1938
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
1939
|
+
if (Array.isArray(value)) {
|
|
1940
|
+
resHeaders[key] = value.join(", ");
|
|
1941
|
+
} else if (value) {
|
|
1942
|
+
resHeaders[key] = String(value);
|
|
1981
1943
|
}
|
|
1982
1944
|
}
|
|
1983
|
-
|
|
1984
|
-
|
|
1945
|
+
delete resHeaders["content-encoding"];
|
|
1946
|
+
delete resHeaders["content-length"];
|
|
1947
|
+
delete resHeaders["transfer-encoding"];
|
|
1948
|
+
delete resHeaders["connection"];
|
|
1949
|
+
delete resHeaders["keep-alive"];
|
|
1950
|
+
isSilent ? logger9.debug(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`) : logger9.info(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`);
|
|
1951
|
+
await safeFulfill(route, {
|
|
1952
|
+
status: response.statusCode,
|
|
1953
|
+
headers: resHeaders,
|
|
1954
|
+
body: response.body
|
|
1955
|
+
});
|
|
1985
1956
|
} catch (err) {
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1957
|
+
const message = String(err?.message || "");
|
|
1958
|
+
const isTimeout = err?.code === "ETIMEDOUT" || message.toLowerCase().includes("timeout");
|
|
1959
|
+
const action = fallbackToProxy ? "\u56DE\u9000\u4EE3\u7406" : "\u5DF2\u653E\u5F03";
|
|
1960
|
+
const reason = isTimeout ? `\u8D85\u65F6(${DirectConfig.directTimeout}s)` : `\u5F02\u5E38: ${message}`;
|
|
1961
|
+
logger9.warn(`\u76F4\u8FDE${reason}\uFF0C${action}`);
|
|
1962
|
+
if (fallbackToProxy) {
|
|
1963
|
+
await safeContinue(route);
|
|
1964
|
+
} else {
|
|
1965
|
+
await safeAbort(route);
|
|
1992
1966
|
}
|
|
1993
1967
|
}
|
|
1994
|
-
}
|
|
1968
|
+
};
|
|
1969
|
+
const blockRouteHandler = async (route) => {
|
|
1970
|
+
await safeAbort(route);
|
|
1971
|
+
};
|
|
1972
|
+
if (hasDirectRules) {
|
|
1973
|
+
for (const matcher of directRouteMatchers) {
|
|
1974
|
+
await page.route(matcher, directRouteHandler);
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
if (hasBlockRules) {
|
|
1978
|
+
for (const matcher of blockRouteMatchers) {
|
|
1979
|
+
await page.route(matcher, blockRouteHandler);
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1995
1982
|
}
|
|
1996
1983
|
};
|
|
1997
1984
|
async function safeFulfill(route, options) {
|
|
@@ -2011,10 +1998,37 @@ async function safeContinue(route) {
|
|
|
2011
1998
|
}
|
|
2012
1999
|
}
|
|
2013
2000
|
}
|
|
2001
|
+
async function safeAbort(route) {
|
|
2002
|
+
try {
|
|
2003
|
+
await route.abort();
|
|
2004
|
+
} catch (error) {
|
|
2005
|
+
if (!isIgnorableError(error)) {
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2014
2009
|
function isIgnorableError(error) {
|
|
2015
2010
|
const msg = error.message;
|
|
2016
2011
|
return msg.includes("already handled") || msg.includes("Target closed") || msg.includes("closed");
|
|
2017
2012
|
}
|
|
2013
|
+
function createExtensionsRegex(extensions = []) {
|
|
2014
|
+
const normalized = Array.from(new Set(
|
|
2015
|
+
extensions.map((ext) => String(ext || "").toLowerCase().trim()).filter(Boolean).map((ext) => ext.startsWith(".") ? ext : `.${ext}`)
|
|
2016
|
+
));
|
|
2017
|
+
if (!normalized.length) return null;
|
|
2018
|
+
const escaped = normalized.map((ext) => escapeRegex(ext));
|
|
2019
|
+
return new RegExp(`(?:${escaped.join("|")})(?:\\?.*)?$`, "i");
|
|
2020
|
+
}
|
|
2021
|
+
function createDomainsRegex(domains = []) {
|
|
2022
|
+
const normalized = Array.from(new Set(
|
|
2023
|
+
domains.map((domain) => String(domain || "").toLowerCase().trim()).filter(Boolean)
|
|
2024
|
+
));
|
|
2025
|
+
if (!normalized.length) return null;
|
|
2026
|
+
const domainParts = normalized.map((domain) => `${escapeRegex(domain)}[^/:?#]*`);
|
|
2027
|
+
return new RegExp(`^https?:\\/\\/(?:${domainParts.join("|")})(?::\\d+)?(?:[/?#]|$)`, "i");
|
|
2028
|
+
}
|
|
2029
|
+
function escapeRegex(value) {
|
|
2030
|
+
return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2031
|
+
}
|
|
2018
2032
|
|
|
2019
2033
|
// src/mutation.js
|
|
2020
2034
|
var import_uuid2 = require("uuid");
|