@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.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 = {
|
|
@@ -1824,7 +1824,6 @@ var Interception = {
|
|
|
1824
1824
|
* @param {import('playwright').Page} page - Playwright Page 对象
|
|
1825
1825
|
* @param {Object} [options] - 配置选项
|
|
1826
1826
|
* @param {string[]} [options.directDomains] - [已过时] 需要直连的域名列表,请改用 directConfig.domains
|
|
1827
|
-
* @param {string[]} [options.directExtensions] - 需要直连的扩展名(如 .js/.css)
|
|
1828
1827
|
* @param {Object} [options.directConfig] - 直连配置(参考 blockingConfig),支持 domains/directAllXxx 系列开关
|
|
1829
1828
|
* @param {Object} [options.blockingConfig] - 资源屏蔽配置
|
|
1830
1829
|
* @param {boolean} [options.fallbackToProxy] - 直连失败时是否回退到代理(默认 true)
|
|
@@ -1833,7 +1832,6 @@ var Interception = {
|
|
|
1833
1832
|
async setup(page, options = {}) {
|
|
1834
1833
|
const {
|
|
1835
1834
|
directDomains = [],
|
|
1836
|
-
directExtensions = [],
|
|
1837
1835
|
directConfig = {},
|
|
1838
1836
|
blockingConfig = {},
|
|
1839
1837
|
fallbackToProxy = true
|
|
@@ -1850,10 +1848,20 @@ var Interception = {
|
|
|
1850
1848
|
const hasDirectDomains = normalizedDirectDomains.length > 0;
|
|
1851
1849
|
const normalizedDirectExtensions = Array.from(
|
|
1852
1850
|
new Set(
|
|
1853
|
-
|
|
1851
|
+
configuredDirectExtensions.map((ext) => String(ext || "").toLowerCase().trim()).filter(Boolean).map((ext) => ext.startsWith(".") ? ext : `.${ext}`)
|
|
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,104 +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
1888
|
const isSilent = DirectConfig.silentExtensions.some((ext) => urlPath.endsWith(ext));
|
|
1878
|
-
const
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
url,
|
|
1906
|
-
method,
|
|
1907
|
-
headers: reqHeaders,
|
|
1908
|
-
body: postData,
|
|
1909
|
-
responseType: "buffer",
|
|
1910
|
-
// 强制获取 Buffer
|
|
1911
|
-
// 移除手动 TLS 指纹配置,使用 got-scraping 默认的高质量指纹
|
|
1912
|
-
// headerGeneratorOptions: ...
|
|
1913
|
-
// 使用共享的 Agent 单例(keepAlive: false,不会池化连接)
|
|
1914
|
-
agent: {
|
|
1915
|
-
http: SHARED_HTTP_AGENT,
|
|
1916
|
-
https: SHARED_HTTPS_AGENT
|
|
1917
|
-
},
|
|
1918
|
-
// 超时时间
|
|
1919
|
-
timeout: { request: DirectConfig.directTimeout * 1e3 }
|
|
1920
|
-
});
|
|
1921
|
-
const resHeaders = {};
|
|
1922
|
-
for (const [key, value] of Object.entries(response.headers)) {
|
|
1923
|
-
if (Array.isArray(value)) {
|
|
1924
|
-
resHeaders[key] = value.join(", ");
|
|
1925
|
-
} else if (value) {
|
|
1926
|
-
resHeaders[key] = String(value);
|
|
1927
|
-
}
|
|
1928
|
-
}
|
|
1929
|
-
delete resHeaders["content-encoding"];
|
|
1930
|
-
delete resHeaders["content-length"];
|
|
1931
|
-
delete resHeaders["transfer-encoding"];
|
|
1932
|
-
delete resHeaders["connection"];
|
|
1933
|
-
delete resHeaders["keep-alive"];
|
|
1934
|
-
isSilent ? logger9.debug(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`) : logger9.info(`\u76F4\u8FDE\u6210\u529F: ${urlPath}`);
|
|
1935
|
-
await safeFulfill(route, {
|
|
1936
|
-
status: response.statusCode,
|
|
1937
|
-
headers: resHeaders,
|
|
1938
|
-
body: response.body
|
|
1939
|
-
});
|
|
1940
|
-
handled = true;
|
|
1941
|
-
return;
|
|
1942
|
-
} catch (e) {
|
|
1943
|
-
const isTimeout = e.code === "ETIMEDOUT" || e.message.toLowerCase().includes("timeout");
|
|
1944
|
-
const action = fallbackToProxy ? "\u56DE\u9000\u4EE3\u7406" : "\u5DF2\u653E\u5F03";
|
|
1945
|
-
const reason = isTimeout ? `\u8D85\u65F6(${DirectConfig.directTimeout}s)` : `\u5F02\u5E38: ${e.message}`;
|
|
1946
|
-
logger9.warn(`\u76F4\u8FDE${reason}\uFF0C${action}: ${urlPath}`);
|
|
1947
|
-
if (fallbackToProxy) {
|
|
1948
|
-
await safeContinue(route);
|
|
1949
|
-
} else {
|
|
1950
|
-
await route.abort();
|
|
1951
|
-
}
|
|
1952
|
-
handled = true;
|
|
1953
|
-
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);
|
|
1954
1916
|
}
|
|
1955
1917
|
}
|
|
1956
|
-
|
|
1957
|
-
|
|
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
|
+
});
|
|
1958
1929
|
} catch (err) {
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
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);
|
|
1965
1939
|
}
|
|
1966
1940
|
}
|
|
1967
|
-
}
|
|
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
|
+
}
|
|
1968
1955
|
}
|
|
1969
1956
|
};
|
|
1970
1957
|
async function safeFulfill(route, options) {
|
|
@@ -1984,10 +1971,37 @@ async function safeContinue(route) {
|
|
|
1984
1971
|
}
|
|
1985
1972
|
}
|
|
1986
1973
|
}
|
|
1974
|
+
async function safeAbort(route) {
|
|
1975
|
+
try {
|
|
1976
|
+
await route.abort();
|
|
1977
|
+
} catch (error) {
|
|
1978
|
+
if (!isIgnorableError(error)) {
|
|
1979
|
+
}
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1987
1982
|
function isIgnorableError(error) {
|
|
1988
1983
|
const msg = error.message;
|
|
1989
1984
|
return msg.includes("already handled") || msg.includes("Target closed") || msg.includes("closed");
|
|
1990
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
|
+
}
|
|
1991
2005
|
|
|
1992
2006
|
// src/mutation.js
|
|
1993
2007
|
import { v4 as uuidv42 } from "uuid";
|