feat: 打开渠道与脚本自动化分离

This commit is contained in:
DEV_DSW
2026-03-12 17:05:16 +08:00
parent f084e47c58
commit 236f4c7dc1
12 changed files with 201 additions and 132 deletions

View File

@@ -1,8 +1,8 @@
import { chromium } from 'playwright';
import log from 'electron-log';
import checkLoginStatusPkg from './common/checkLoginStatus.js';
import tabsPkg from './common/tabs.js';
const { checkLoginStatus } = checkLoginStatusPkg;
const { preparePage, safeDisconnectBrowser } = tabsPkg;
const parseDateInput = (dateStr) => {
if (!dateStr) return null;
@@ -61,7 +61,7 @@ const findHeaderDateIndex = async (container, mmdd) => {
return -1;
};
const toggleRoomByDateIndex = async (page, container, { roomType, dateIndex, operation }) => {
const toggleRoomByDateIndex = async (container, { roomType, dateIndex, operation }) => {
const roomAnchor = container.getByText(roomType, { exact: true }).first();
await roomAnchor.scrollIntoViewIfNeeded();
@@ -91,70 +91,17 @@ const toggleRoomByDateIndex = async (page, container, { roomType, dateIndex, ope
};
(async () => {
const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
let browser;
try {
const context = browser.contexts()[0];
const prepared = await preparePage(chromium);
browser = prepared.browser;
const page = prepared.page;
await context.addInitScript(() => {
Object.defineProperty(navigator, 'webdriver', { get: ()=> undefined });
});
const pages = await context.pages();
const tabIndex = Number(process.env.TAB_INDEX);
const page = pages.length ? pages[tabIndex] : await context.newPage();
await page.goto('https://hotel.fliggy.com/ebooking/hotelBaseInfoUv.htm#/ebk/homeV1');
const isLogin = await checkLoginStatus(page);
if(!isLogin) {
await page.getByRole('textbox', { name: '请输入账号' }).dblclick();
await page.getByRole('textbox', { name: '请输入账号' }).click();
await page.getByRole('textbox', { name: '请输入账号' }).fill('hoteltmwq123', { delay: 80 + Math.random() * 120 });
await page.waitForTimeout(1000 + Math.random() * 1000);
await page.getByRole('button', { name: '下一步' }).click();
const frame_1 = await page.frameLocator('#alibaba-login-box');
await page.locator('#alibaba-login-box').contentFrame().getByRole('textbox', { name: '请输入登录密码' }).dblclick();
await page.locator('#alibaba-login-box').contentFrame().getByRole('textbox', { name: '请输入登录密码' }).fill('Tmwq654321', { delay: 80 + Math.random() * 120 });
await page.waitForTimeout(1000 + Math.random() * 1000);
await page.locator('#alibaba-login-box').contentFrame().getByRole('button', { name: '登录' }).click();
// 等待滑块真正出现在 DOM 并可见
await page.waitForTimeout(4000 + Math.random() * 1000);
const frame_2 = await frame_1.frameLocator('#baxia-dialog-content');
const container = await frame_2.locator('#nc_1_nocaptcha');
const slider = await frame_2.locator('#nc_1_n1z');
const isVisible = await slider.isVisible();
if (isVisible) {
// 重新获取滑块按钮(可能嵌套在 iframe 里)
const containerBox = await container.boundingBox();
const sliderBox = await slider.boundingBox();
const startX = sliderBox.x + sliderBox.width / 2;
const startY = sliderBox.y + sliderBox.height / 2;
const distance = containerBox.width - sliderBox.width; // 适当拉长拖动距离
const steps = 20; // 分多步模拟人手拖动
await page.mouse.move(startX, startY);
// 等待随机时间再开始滑动(模拟人类反应)
await page.waitForTimeout(200 + Math.random() * 300);
await page.mouse.down();
await page.waitForTimeout(100 + Math.random() * 200);
// 按轨迹滑动
for (let i = 0; i < steps; i++) {
await page.mouse.move(
sliderBox.x + sliderBox.width / 2 + (distance * (i + 1) / steps),
sliderBox.y + sliderBox.height / 2 + (Math.random() * 5 - 2.5), // 模拟轻微Y轴抖动
{ steps: 5 }
);
}
await page.mouse.up();
}
const targetUrl = 'https://hotel.fliggy.com/ebooking/hotelBaseInfoUv.htm#/ebk/homeV1';
const currentUrl = page.url();
if (!currentUrl || !currentUrl.startsWith(targetUrl)) {
await page.goto(targetUrl);
}
await page.waitForTimeout(4000 + Math.random() * 300);
@@ -182,21 +129,13 @@ const toggleRoomByDateIndex = async (page, container, { roomType, dateIndex, ope
if (dateIndex < 0) {
throw new Error(`Date not found in header: ${mmdd}`);
}
await toggleRoomByDateIndex(page, container, { roomType, dateIndex, operation });
await toggleRoomByDateIndex(container, { roomType, dateIndex, operation });
await page.waitForTimeout(600 + Math.random() * 600);
}
} catch (error) {
log.error(error);
process.exitCode = 1;
}finally {
if (browser) {
try {
if (typeof browser.disconnect === 'function') {
await browser.disconnect();
} else {
await browser.close();
}
} catch {}
}
await safeDisconnectBrowser(browser);
}
})();