[ISSUE-0067] dogfood v0.10.87 — 4 项小修¶
v0.10.87 dogfood(advocatehealth.com 医生页)截图反馈: 1. 邮箱抓到
your@email.com(占位符污染) 2. 网页 2 个号码(847-382-6579 + 224-848-4453)只显示 1 个 3. 想开 multi-stage flag 但只能 DevTools console,体验差 4. v0.10.87 probe 把 403 当 ok 路径,但 403 一般是反爬墙
Bug 1:your@email.com 占位符污染¶
病灶¶
BUILTIN_EMAIL_BLACKLIST(scraper.ts:2-8)只覆盖 example@example.com / yourname@domain.com 等,your@email.com 不在内。它是国外订阅表单 / footer 模板的极常见 placeholder。
修¶
扩充 BLACKLIST + NOISE 两层:
BLACKLIST 精确新增 14 个(your@email.com / you@example.com / me@example.com / info@example.com / contact@example.com / noreply@example.com / johndoe@example.com 等)
NOISE 模糊新增 9 个:@example.com / @example.org / @example.net / @yoursite.com / @yourdomain.com / @your-domain.com / @mysite.com / @mywebsite.com
Bug 2:网页 regex 提取的 phone 从未写入 DB(长期 bug)¶
病灶 ⚠️¶
scraper-executor.ts:processWebsiteScrape tab 路径写库时:
// v0.10.87 及之前
await updateByQuery('MapTaskData', { id: { in: [id] } }, {
emails: uniqueEmails,
facebook, linkedin, instagram, twitter, youtube,
whatsapp: finalWhatsapp,
scrape_status: 2,
// ❌ phone 字段完全缺失!
});
extractedPhones(scraper-executor.ts:185)确实抽到了,但只塞进 page-log 做日志展示,从未写到 MapTaskData。
UI 看到的 phone 字段值一直是 Google Maps 商家本身的电话(地图采集阶段填的)— 不是网站抓的。截图里看到 +1 847-382-6579 是 Google Maps 给的;第二个 224-848-4453 网页 regex 抽到了但被丢了。
这是个 极长期 bug(自有 extractedPhones 那天起就漏写 DB)。
修¶
加 helper mergePhonesWithMapsLabel(mapsPhone, websitePhones):
export function mergePhonesWithMapsLabel(
mapsPhone: string,
websitePhones: string[]
): string {
const normalize = (p: string) => p.replace(/\D/g, ''); // 纯数字 key 去重
const mapsList = (mapsPhone || '').split(/[,;|]/).map(s => s.trim()).filter(Boolean);
const seen = new Map<string, { value: string; source: 'maps' | 'web' }>();
for (const p of mapsList) {
const k = normalize(p);
if (k.length >= 7 && !seen.has(k)) seen.set(k, { value: p, source: 'maps' });
}
for (const p of websitePhones || []) {
const k = normalize(p);
if (k.length >= 7 && !seen.has(k)) seen.set(k, { value: p, source: 'web' });
}
const all = Array.from(seen.values()).slice(0, 5);
if (all.length === 0) return '';
// 单号码 + 地图来源 → 不加标记(兼容旧数据)
if (all.length === 1 && all[0].source === 'maps') return all[0].value;
// 多号码 / 仅网站 → 地图来源加 (地图) 标记
return all.map(({ value, source }) =>
source === 'maps' ? `${value} (地图)` : value
).join(', ');
}
写库前先 select 现有 phone(Google Maps 给的),合并去重,回写:
const existing = await selectByQuery('MapTaskData', { where: { id: { in: [id] } }, limit: 1 });
const existingPhone = existing?.[0]?.phone || '';
const mergedPhone = mergePhonesWithMapsLabel(existingPhone, extractedPhones);
await updateByQuery('MapTaskData', { id: { in: [id] } }, {
...,
phone: mergedPhone, // ← v0.10.88 写回
...
});
两处都改了:tab 路径(line 211)+ pipeline success 路径(applyPipelineOutcome)。
UX 选择(用户决策)¶
B 方案 + 地图来源加 (地图) 标记。
- 单号码场景(90%+):不加标记,UI 与 v0.10.87 完全一致
- 多号码场景:地图来源 +1 847-382-6579 (地图),网站抓的 224-848-4453,逗号分隔
Bug 3:缺 settings UI toggle¶
病灶¶
v0.10.87 默认关 enableMultiStageScrape,启用方式只有 chrome DevTools 改 storage。用户截图被 Chrome "allow pasting" 拦住 + 真跑发现 WXT lazy 写入(settings 没保存过时 chrome.storage.local 里没有 local:settingParams),导致 s = undefined,code 直接 TypeError。
修¶
settings-view.tsx 在 "🔗 内页跟随" 段之前加新段 "⚡ 多阶段抓取(实验性 · 默认关)" + 一个 RHFSwitch:
<RHFSwitch
name="enableMultiStageScrape"
label="启用多阶段抓取(HEAD → GET → 正则 → tab 兜底)"
helperText="开启后,先用 fetch 轻量探测..."
/>
加 Yup schema:enableMultiStageScrape: Yup.boolean()
Bug 4:probe 403/451 未归 antibot¶
病灶¶
website-probe.ts pickStatusReason 只把 404/410 归 dead、429/5xx 归 retry-later,403/451 走默认分支返回 ok — 然后 fetch GET 拿 body,浪费一次请求。
SPEC-004 决策树原意:403/503 + cf-ray 是 antibot。但 403 没 cf-ray 怎么办? Spec 没明确。
修¶
按"宁可错杀不放过"原则,403/451 全归 antibot(让 tab fallback 用真实 UA/cookie 试):
截图里 auroradvancedurgentcare.com 那条 403 在 v0.10.88 会被识别为 antibot → 直接 tab fallback,不浪费 GET。
元教训¶
- dogfood ≠ 完美:v0.10.87 写完自信"骨架可用",第一次截图就翻出 2 个真实 bug + 1 个长期 bug + 1 个体验问题。没装到真浏览器看的话,永远查不出 phone 字段从未写库。
- WXT lazy storage 陷阱:
storage.defineItemgetValue 在 storage 没该 key 时返回 defaultValue 但不写。chrome devtools 改 storage 不安全,应优先做 UI。 - 长期 bug 的发现需要新功能驱动:phone 字段从未写库这个事,没人会主动查 — 必须等用户截图对比,才能发现"咦,我抓到的电话去哪了"。
- 占位符黑名单永远漏:placeholders 五花八门,要持续补。
相关¶
- SPEC-004-网站采集多阶段优化-云端协同 — Phase 1
- 多阶段抓取pipeline — 架构
- [[0023-mailto-url-encoded-pollutes-email|0023-mailto链接URL编码污染邮箱]] — 同类 email 噪音治理