@skrillex1224/playwright-toolkit 2.1.8 → 2.1.10
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 +74 -47
- package/dist/index.cjs.map +2 -2
- package/dist/index.js +74 -47
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1281,6 +1281,14 @@ var DEFAULT_BLOCKING_CONFIG = {
|
|
|
1281
1281
|
/** 额外自定义扩展名列表 */
|
|
1282
1282
|
customExtensions: []
|
|
1283
1283
|
};
|
|
1284
|
+
var SHARED_GOT_OPTIONS = {
|
|
1285
|
+
http2: false,
|
|
1286
|
+
// 禁用 HTTP2 避免在拦截场景下的握手兼容性问题
|
|
1287
|
+
retry: { limit: 0 },
|
|
1288
|
+
// 让 Playwright 或外层逻辑处理重试
|
|
1289
|
+
throwHttpErrors: false
|
|
1290
|
+
// 404/500 等错误不抛出异常,直接透传给浏览器
|
|
1291
|
+
};
|
|
1284
1292
|
var Interception = {
|
|
1285
1293
|
/**
|
|
1286
1294
|
* 根据配置生成需要屏蔽的扩展名列表
|
|
@@ -1324,16 +1332,6 @@ var Interception = {
|
|
|
1324
1332
|
/**
|
|
1325
1333
|
* 设置网络拦截规则(资源屏蔽 + CDN 直连)
|
|
1326
1334
|
*
|
|
1327
|
-
* 工作流程:
|
|
1328
|
-
* 1. 检查请求是否在屏蔽列表中 → 如果是,直接 abort
|
|
1329
|
-
* 2. 检查是否匹配直连域名 → 如果是,使用 Node.js fetch 直连
|
|
1330
|
-
* 3. 其他请求正常走代理
|
|
1331
|
-
*
|
|
1332
|
-
* 适用场景:
|
|
1333
|
-
* - 代理 IP 无法访问某些 CDN 域名
|
|
1334
|
-
* - 需要加速静态资源加载
|
|
1335
|
-
* - 屏蔽不必要的资源请求
|
|
1336
|
-
*
|
|
1337
1335
|
* @param {import('playwright').Page} page - Playwright Page 对象
|
|
1338
1336
|
* @param {Object} [options] - 配置选项
|
|
1339
1337
|
* @param {string[]} [options.directDomains] - 需要直连的域名列表
|
|
@@ -1346,10 +1344,10 @@ var Interception = {
|
|
|
1346
1344
|
directDomains = [],
|
|
1347
1345
|
blockingConfig = {},
|
|
1348
1346
|
fallbackToProxy = true
|
|
1349
|
-
// 默认回退到代理,保证可用性
|
|
1350
1347
|
} = options;
|
|
1351
1348
|
const mergedBlockingConfig = { ...DEFAULT_BLOCKING_CONFIG, ...blockingConfig };
|
|
1352
1349
|
const blockedExtensions = this.getBlockedExtensions(mergedBlockingConfig);
|
|
1350
|
+
const hasDirectDomains = directDomains.length > 0;
|
|
1353
1351
|
const enabledCategories = [];
|
|
1354
1352
|
if (mergedBlockingConfig.blockArchive) enabledCategories.push("\u538B\u7F29\u5305");
|
|
1355
1353
|
if (mergedBlockingConfig.blockExecutable) enabledCategories.push("\u53EF\u6267\u884C\u6587\u4EF6");
|
|
@@ -1359,21 +1357,19 @@ var Interception = {
|
|
|
1359
1357
|
if (mergedBlockingConfig.blockFont) enabledCategories.push("\u5B57\u4F53");
|
|
1360
1358
|
if (mergedBlockingConfig.blockCss) enabledCategories.push("CSS");
|
|
1361
1359
|
if (mergedBlockingConfig.blockOther) enabledCategories.push("\u5176\u4ED6");
|
|
1362
|
-
|
|
1363
|
-
logger9.start("setup", hasDirectDomains ? `\u76F4\u8FDE\u57DF\u540D: [${directDomains.join(", ")}]` : "\u4EC5\u8D44\u6E90\u5C4F\u853D\u6A21\u5F0F");
|
|
1360
|
+
logger9.start("setup", hasDirectDomains ? `\u76F4\u8FDE\u57DF\u540D: [${directDomains.length} \u4E2A] | \u5C4F\u853D: [${enabledCategories.join(", ")}]` : `\u4EC5\u8D44\u6E90\u5C4F\u853D\u6A21\u5F0F | \u5C4F\u853D: [${enabledCategories.join(", ")}]`);
|
|
1364
1361
|
await page.route("**/*", async (route) => {
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
if (matchesDomain) {
|
|
1362
|
+
try {
|
|
1363
|
+
const request = route.request();
|
|
1364
|
+
const url = request.url();
|
|
1365
|
+
const urlLower = url.toLowerCase();
|
|
1366
|
+
const urlPath = urlLower.split("?")[0];
|
|
1367
|
+
const shouldBlock = blockedExtensions.some((ext) => urlPath.endsWith(ext));
|
|
1368
|
+
if (shouldBlock) {
|
|
1369
|
+
await route.abort();
|
|
1370
|
+
return;
|
|
1371
|
+
}
|
|
1372
|
+
if (hasDirectDomains && directDomains.some((domain) => url.includes(domain))) {
|
|
1377
1373
|
try {
|
|
1378
1374
|
const reqHeaders = await request.allHeaders();
|
|
1379
1375
|
delete reqHeaders["host"];
|
|
@@ -1381,30 +1377,29 @@ var Interception = {
|
|
|
1381
1377
|
const method = request.method();
|
|
1382
1378
|
const postData = method !== "GET" && method !== "HEAD" ? request.postDataBuffer() : void 0;
|
|
1383
1379
|
const response = await (0, import_got_scraping.gotScraping)({
|
|
1380
|
+
...SHARED_GOT_OPTIONS,
|
|
1381
|
+
// 应用通用配置
|
|
1384
1382
|
url,
|
|
1385
1383
|
method,
|
|
1386
1384
|
headers: reqHeaders,
|
|
1387
1385
|
body: postData,
|
|
1388
1386
|
responseType: "buffer",
|
|
1389
|
-
//
|
|
1390
|
-
//
|
|
1391
|
-
http2: false,
|
|
1392
|
-
// 模拟浏览器指纹 (Header 部分)
|
|
1387
|
+
// 强制获取 Buffer
|
|
1388
|
+
// 模拟浏览器 TLS 指纹
|
|
1393
1389
|
headerGeneratorOptions: Stealth.getTlsFingerprintOptions(userAgent),
|
|
1394
|
-
|
|
1395
|
-
//
|
|
1396
|
-
//
|
|
1390
|
+
// 【核心修复 1】: keepAlive 设置为 false
|
|
1391
|
+
// 每一个拦截请求都是独立的,使用 keepAlive 会导致 Agent 池耗尽,
|
|
1392
|
+
// 从而导致后续请求一直 Pending。
|
|
1397
1393
|
agent: {
|
|
1398
|
-
http: new import_http.Agent({ keepAlive:
|
|
1399
|
-
https: new import_https2.Agent({ keepAlive:
|
|
1394
|
+
http: new import_http.Agent({ keepAlive: false }),
|
|
1395
|
+
https: new import_https2.Agent({ keepAlive: false, rejectUnauthorized: false })
|
|
1400
1396
|
},
|
|
1401
|
-
//
|
|
1397
|
+
// 设置较短的超时时间,给回退代理留出机会
|
|
1402
1398
|
timeout: {
|
|
1403
|
-
request:
|
|
1404
|
-
//
|
|
1399
|
+
request: 12 * 1e3
|
|
1400
|
+
// 12秒超时
|
|
1405
1401
|
}
|
|
1406
1402
|
});
|
|
1407
|
-
const body = response.body;
|
|
1408
1403
|
const resHeaders = {};
|
|
1409
1404
|
for (const [key, value] of Object.entries(response.headers)) {
|
|
1410
1405
|
if (Array.isArray(value)) {
|
|
@@ -1415,29 +1410,61 @@ var Interception = {
|
|
|
1415
1410
|
}
|
|
1416
1411
|
delete resHeaders["content-encoding"];
|
|
1417
1412
|
delete resHeaders["content-length"];
|
|
1418
|
-
|
|
1419
|
-
|
|
1413
|
+
delete resHeaders["transfer-encoding"];
|
|
1414
|
+
delete resHeaders["connection"];
|
|
1415
|
+
delete resHeaders["keep-alive"];
|
|
1416
|
+
logger9.info(`\u76F4\u8FDE\u6210\u529F: ${url}`);
|
|
1417
|
+
await safeFulfill(route, {
|
|
1420
1418
|
status: response.statusCode,
|
|
1421
1419
|
headers: resHeaders,
|
|
1422
|
-
body
|
|
1420
|
+
body: response.body
|
|
1423
1421
|
});
|
|
1424
1422
|
return;
|
|
1425
1423
|
} catch (e) {
|
|
1426
1424
|
if (fallbackToProxy) {
|
|
1427
|
-
logger9.warn(`\u76F4\u8FDE\
|
|
1428
|
-
|
|
1425
|
+
logger9.warn(`\u76F4\u8FDE\u5F02\u5E38\uFF0C\u56DE\u9000\u4EE3\u7406: ${url} | Err: ${e.message}`);
|
|
1426
|
+
await safeContinue(route);
|
|
1427
|
+
return;
|
|
1429
1428
|
} else {
|
|
1430
|
-
logger9.warn(`\u76F4\u8FDE\u5931\u8D25: ${url
|
|
1431
|
-
|
|
1429
|
+
logger9.warn(`\u76F4\u8FDE\u5931\u8D25: ${url} | Err: ${e.message}`);
|
|
1430
|
+
await route.abort();
|
|
1431
|
+
return;
|
|
1432
1432
|
}
|
|
1433
1433
|
}
|
|
1434
1434
|
}
|
|
1435
|
+
await safeContinue(route);
|
|
1436
|
+
} catch (err) {
|
|
1437
|
+
try {
|
|
1438
|
+
if (!route.request().failure()) {
|
|
1439
|
+
await route.continue();
|
|
1440
|
+
}
|
|
1441
|
+
} catch (_) {
|
|
1442
|
+
}
|
|
1435
1443
|
}
|
|
1436
|
-
return route.continue();
|
|
1437
1444
|
});
|
|
1438
|
-
logger9.success("setup", `\u5C4F\u853D\u5206\u7C7B: [${enabledCategories.join(", ")}]`);
|
|
1439
1445
|
}
|
|
1440
1446
|
};
|
|
1447
|
+
async function safeFulfill(route, options) {
|
|
1448
|
+
try {
|
|
1449
|
+
await route.fulfill(options);
|
|
1450
|
+
} catch (error) {
|
|
1451
|
+
if (!isIgnorableError(error)) {
|
|
1452
|
+
console.error(`[Interception] Fulfill Error: ${error.message}`);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
async function safeContinue(route) {
|
|
1457
|
+
try {
|
|
1458
|
+
await route.continue();
|
|
1459
|
+
} catch (error) {
|
|
1460
|
+
if (!isIgnorableError(error)) {
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
function isIgnorableError(error) {
|
|
1465
|
+
const msg = error.message;
|
|
1466
|
+
return msg.includes("already handled") || msg.includes("Target closed") || msg.includes("closed");
|
|
1467
|
+
}
|
|
1441
1468
|
|
|
1442
1469
|
// index.js
|
|
1443
1470
|
var usePlaywrightToolKit = () => {
|