first init
This commit is contained in:
parent
6a4f0a9de3
commit
8abea7a7c6
@ -23,8 +23,13 @@ export async function getBrowserAndContexts({ headless, slowMo }) {
|
||||
const browser = await chromium.connectOverCDP(wsEndpoint);
|
||||
const contexts = browser.contexts();
|
||||
const baseContext = contexts[0] || await browser.newContext();
|
||||
// 关闭所有已有页签,保持干净
|
||||
for (const p of baseContext.pages()) { try { await p.close(); } catch {} }
|
||||
// AdsPower 需要至少保留一个标签页,关闭多余的
|
||||
const existingPages = baseContext.pages();
|
||||
if (existingPages.length > 1) {
|
||||
for (let i = 1; i < existingPages.length; i++) {
|
||||
try { await existingPages[i].close(); } catch {}
|
||||
}
|
||||
}
|
||||
// 在同一个指纹环境下创建两个页签(同上下文不同页)
|
||||
return {
|
||||
browser,
|
||||
|
||||
111
emailModule.js
111
emailModule.js
@ -141,27 +141,61 @@ export async function setupTempMail(page) {
|
||||
return { inboxReady: true, page };
|
||||
}
|
||||
|
||||
// 全局基线时间,在 setupTempMail 后初始化,每次注册成功后更新
|
||||
let globalBaselineTime = null;
|
||||
|
||||
/**
|
||||
* 获取收件箱最新一条邮件的时间作为基线
|
||||
*/
|
||||
export async function updateBaseline(page) {
|
||||
try {
|
||||
// 等待收件箱加载
|
||||
await page.waitForSelector('.inbox', { timeout: 10000 }).catch(() => {});
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// 查找所有含有时间的邮件行
|
||||
const timeSpans = page.locator('.inbox span[data-date]');
|
||||
const count = await timeSpans.count();
|
||||
if (count === 0) {
|
||||
globalBaselineTime = null;
|
||||
console.log('[基线] 收件箱无邮件,基线为 null');
|
||||
return;
|
||||
}
|
||||
// 第一个就是最新的
|
||||
const dateStr = await timeSpans.first().getAttribute('data-date');
|
||||
globalBaselineTime = dateStr;
|
||||
console.log('[基线] 更新为最新邮件时间:', globalBaselineTime);
|
||||
} catch (e) {
|
||||
console.log('[基线] 获取失败:', e.message);
|
||||
globalBaselineTime = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 等待并获取验证码
|
||||
* @param {Page} page - Playwright 页面对象
|
||||
* @returns {Promise<string>} 验证码
|
||||
*/
|
||||
export async function waitForVerificationCode(page, sentAfterMs) {
|
||||
export async function waitForVerificationCode(page, sentAfterMs, targetEmail) {
|
||||
console.log('⏳ 等待接收验证码邮件...');
|
||||
console.log('[LOG] 不会刷新页面,只等待新邮件出现...');
|
||||
console.log('[LOG] 基线时间:', globalBaselineTime || '未设置');
|
||||
|
||||
const maxWaitTime = 120000; // 最多等待 120 秒
|
||||
const checkInterval = 1000; // 每 1 秒检查一次
|
||||
const maxWaitTime = 120000;
|
||||
const checkInterval = 1000;
|
||||
let elapsed = 0;
|
||||
|
||||
async function extractCodeFromOpenedMail() {
|
||||
async function extractCodeFromOpenedMail(expectEmail) {
|
||||
// 1) 优先从特定内容区域读取
|
||||
const contentLoc = page.locator('.mail-content, .email-body, #mail-body, [class*="mail-content"], .pm-text, .view, .message-body').first();
|
||||
if (await contentLoc.count() > 0) {
|
||||
const text = await contentLoc.textContent();
|
||||
if (expectEmail && text && !text.includes(expectEmail)) {
|
||||
console.log('[LOG] 内容不匹配目标邮箱,继续查找');
|
||||
} else {
|
||||
const code = /\b(\d{6})\b/.exec(text || '');
|
||||
if (code) return code[1];
|
||||
}
|
||||
}
|
||||
// 2) 遍历所有 iframe 提取文本
|
||||
const frames = page.frames();
|
||||
console.log(`[LOG] 当前 frame 数量: ${frames.length}`);
|
||||
@ -170,12 +204,14 @@ export async function waitForVerificationCode(page, sentAfterMs) {
|
||||
const body = await f.$('body');
|
||||
if (!body) continue;
|
||||
const text = await f.evaluate(() => document.body.innerText || '');
|
||||
if (expectEmail && text && !text.includes(expectEmail)) continue;
|
||||
const m = /\b(\d{6})\b/.exec(text);
|
||||
if (m) return m[1];
|
||||
} catch {}
|
||||
}
|
||||
// 3) 退化为整页文本
|
||||
const all = await page.textContent('body');
|
||||
if (expectEmail && all && !all.includes(expectEmail)) return null;
|
||||
const m = /\b(\d{6})\b/.exec(all || '');
|
||||
return m ? m[1] : null;
|
||||
}
|
||||
@ -186,54 +222,45 @@ export async function waitForVerificationCode(page, sentAfterMs) {
|
||||
|
||||
console.log(`[LOG] 检查邮件... (已等待 ${elapsed / 1000} 秒)`);
|
||||
|
||||
// 邮件列表行(兼容多种结构)
|
||||
const emailRows = page.locator('.inbox-dataList .mail-item, .inbox-dataList > div, div.row.no-gutters');
|
||||
const emailCount = await emailRows.count();
|
||||
console.log(`[LOG] 当前邮件数量: ${emailCount}`);
|
||||
|
||||
if (emailCount > 0) {
|
||||
console.log('📬 发现邮件,尝试读取...');
|
||||
|
||||
// 遍历所有邮件,优先读取发送之后的邮件(按顺序尝试)
|
||||
for (let i = 0; i < emailCount; i++) {
|
||||
const emailRow = emailRows.nth(i);
|
||||
|
||||
// 过滤发送时间之前的旧邮件(根据 data-date)
|
||||
try {
|
||||
const timeSpan = emailRow.locator('span[data-date]').first();
|
||||
if (await timeSpan.count() > 0) {
|
||||
// 每个邮件包含 <span data-date>,找到所有带时间戳的行
|
||||
const timeSpans = page.locator('.inbox span[data-date]');
|
||||
const count = await timeSpans.count();
|
||||
console.log(`[LOG] 当前邮件数量: ${count}`);
|
||||
|
||||
if (count === 0) continue;
|
||||
|
||||
// 遍历所有邮件,找第一个满足条件的:发件人 cfbounces && 时间 > 基线
|
||||
for (let i = 0; i < count; i++) {
|
||||
const timeSpan = timeSpans.nth(i);
|
||||
const dateStr = await timeSpan.getAttribute('data-date');
|
||||
if (dateStr) {
|
||||
const parsed = Date.parse(dateStr.replace(' ', 'T')) || new Date(dateStr).getTime();
|
||||
if (sentAfterMs && parsed && parsed < sentAfterMs) {
|
||||
console.log(`[LOG] 跳过旧邮件 ${dateStr}`);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
|
||||
try {
|
||||
// 点击打开邮件(有些需要双击/再次点击切换到详情)
|
||||
await emailRow.click({ timeout: 5000 });
|
||||
await page.waitForTimeout(500);
|
||||
try { await emailRow.dblclick({ timeout: 1000 }); } catch {}
|
||||
// 向上找到包含 from 的父元素获取发件人
|
||||
const row = timeSpan.locator('xpath=ancestor::div[contains(@class, "row")]').first();
|
||||
const fromSpan = row.locator('.from span').last();
|
||||
const sender = await fromSpan.textContent().catch(() => '');
|
||||
|
||||
// 等待内容区域或 iframe 加载
|
||||
await page.waitForTimeout(1500);
|
||||
const isCfbounces = /cfbounces/i.test(sender || '');
|
||||
const isNewer = globalBaselineTime ? (dateStr > globalBaselineTime) : true;
|
||||
|
||||
const code = await extractCodeFromOpenedMail();
|
||||
console.log(`[LOG] Row ${i+1}: sender=${sender} date=${dateStr} baseline=${globalBaselineTime} newer=${isNewer}`);
|
||||
|
||||
if (isCfbounces && isNewer) {
|
||||
console.log('✅ 发现新验证邮件,点击读取...');
|
||||
await row.scrollIntoViewIfNeeded().catch(() => {});
|
||||
await row.click({ timeout: 5000 });
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
const code = await extractCodeFromOpenedMail(targetEmail);
|
||||
if (code) {
|
||||
console.log('✅ 获取到验证码:', code);
|
||||
return code;
|
||||
}
|
||||
console.log(`[LOG] 邮件 ${i + 1} 中未找到验证码`);
|
||||
} catch (error) {
|
||||
console.log(`[LOG] 读取邮件 ${i + 1} 失败:`, error.message);
|
||||
console.log('[LOG] 该邮件未提取到验证码,继续...');
|
||||
}
|
||||
}
|
||||
|
||||
console.log('⚠️ 所有邮件中未找到验证码,继续等待...');
|
||||
} catch (e) {
|
||||
console.log('[LOG] 检查邮件出错:', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
10
index.js
10
index.js
@ -1,6 +1,6 @@
|
||||
import { chromium } from 'playwright';
|
||||
import { config } from './config.js';
|
||||
import { setupTempMail, waitForVerificationCode } from './emailModule.js';
|
||||
import { setupTempMail, waitForVerificationCode, updateBaseline } from './emailModule.js';
|
||||
import { registerOnVerdent, completeRegistration } from './registerModule.js';
|
||||
import { getBrowserAndContexts } from './browser.js';
|
||||
import { generateUsername } from './util.js';
|
||||
@ -40,13 +40,16 @@ async function main() {
|
||||
const email = `${localPart}@${config.tempmail.domain}`;
|
||||
console.log('📧 将用于注册的邮箱:', email);
|
||||
|
||||
// 获取初始基线时间
|
||||
await updateBaseline(emailPage);
|
||||
|
||||
// ========== 第二步:在 Verdent 上开始注册 ==========
|
||||
console.log('\n🌐 === 步骤 2: 开始 Verdent.ai 注册 ===');
|
||||
const { sentAtMs } = await registerOnVerdent(registerPage, email);
|
||||
|
||||
// ========== 第三步:等待验证码邮件(只取发送后的邮件) ==========
|
||||
console.log('\n📬 === 步骤 3: 等待验证码邮件 ===');
|
||||
const verificationCode = await waitForVerificationCode(emailPage, sentAtMs);
|
||||
const verificationCode = await waitForVerificationCode(emailPage, sentAtMs, email);
|
||||
|
||||
if (!verificationCode) {
|
||||
throw new Error('未能获取验证码');
|
||||
@ -68,6 +71,9 @@ async function main() {
|
||||
console.log('🔑 密码:', config.verdent.password);
|
||||
console.log('============================================\n');
|
||||
|
||||
// 更新基线为当前最新邮件时间
|
||||
await updateBaseline(emailPage);
|
||||
|
||||
// 持久化保存(注册时间与过期时间=7天)
|
||||
const createdAt = new Date();
|
||||
const expiresAt = new Date(createdAt.getTime() + 7 * 24 * 60 * 60 * 1000);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user