用 Playwright Firefox 跑过智联反爬的 6 个深坑

📅 2026/6/16 16:01:55
用 Playwright Firefox 跑过智联反爬的 6 个深坑
用 Playwright Firefox 跑过智联反爬的 6 个深坑发布指引:这是脱敏版引流博客,CSDN/掘金/知乎都能直接发。末尾记得挂你的联系方式。背景:最近在做一个多平台自动化工具,其中智联招聘这一路从 Chrome 切到 Firefox persistent context 踩了不少坑。这篇记录 6 个看起来应该能跑,实际跑不通的问题和最终解法,给后来人省点时间。技术栈:Playwright Firefox launchPersistentContext Node.js坑 1:登录态判定「假成功」现象脚本判定已登录,自动关窗,但实际用户还没扫码。原因智联有一堆 WAF / 追踪 cookie(Hm_*/sts_*/x-zp-client-id/sensorsdata*/ZP_OLD_FLAG等)在浏览器打开就被种下,代码只要检测到有 cookie就误判登录了。解法先抓未登录基线 cookie,然后轮询新 cookie,命中的必须不在基线里才算真登录。智联真正的登录态 cookie 只有 2 个:at(access token, 32 位随机串) rt(refresh token, 32 位随机串)。这俩不是 httpOnly(前端要读),长度固定,且未登录基线里没有 → 三重判据够稳。constLOGIN_COOKIES[at,rt];// 固化,别把 WAF cookie 算进去// 1. 拉登录页前先抓基线constbaselineCookiesawaitcontext.cookies();constbaselineNamesnewSet(baselineCookies.map(cc.name));// 2. 轮询,命中且不在基线才算constnewCookiesawaitcontext.cookies();constloginDetectedLOGIN_COOKIES.some(name{constfoundnewCookies.find(cc.namename);returnfound!baselineNames.has(name);// 关键:不在基线});坑 2:Chrome profile 切 Firefox,登录态丢失现象之前 Chrome 的持久 profile(data/zhilian-chrome-profile/)能复用登录态,切 Firefox 后失效。原因PlaywrightChrome 和 Firefox 的 profile 目录格式不通用,Chrome 用 Chromium 内核的 profile 结构,Firefox 用 Mozilla profile(不同的 cookie 存储格式 / 扩展系统)。解法给 Firefox 单独开一个 profile:data/zhilian-firefox-profile/,在 Playwright 窗口内重新登录一次(不能从系统 Firefox 拷)。constcontextawaitfirefox.launchPersistentContext(path.join(__dirname,../data/zhilian-firefox-profile),{headless:false,firefoxUserPrefs:{dom.webdriver.enabled:false,// 降指纹useAutomationExtension:false,},});坑 3:投递弹窗点不出来(Playwright 合成事件被吞)现象详情页点立即投递按钮,控制台不报错,但弹窗就是不出来。DOM 里弹窗组件还是初始的 0×0 占位。原因智联用Vue 事件委托,按钮 HTML 上没有 onclick 属性,弹窗组件是 Vue异步注入的。Playwrightlocator.click()合成的事件被 Vue 事件系统吞了。解法三连发才稳:// 1. 真鼠标移过去 点(marionette trusted event)constboxawaitbtn.boundingBox();awaitpage.mouse.move(box.xbox.width/2,box.ybox.height/2);awaitpage.mouse.click(box.xbox.width/2,box.ybox.height/2);// 2. JS 派发完整事件链 原生 clickawaitbtn.evaluate(el{[pointerdown,mousedown,pointerup,mouseup,click].forEach(t{el.dispatchEvent(newMouseEvent(t,{bubbles:true,cancelable:true}));});el.click();// 原生 click});// 3. 成功后弹窗才异步注入 DOM,轮询 10s 尺寸 50×50for(leti0;i50;i){constdlgpage.locator(.a-job-apply-workflow);constboxawaitdlg.boundingBox().catch(()null);if(boxbox.width50box.height50)break;awaitpage.waitForTimeout(200);}坑 4:投递结果判定假成功现象代码等 3 秒抓 HTML 正则匹配投递成功,但智联校验失败后弹窗会自动关掉,3 秒后页面已经回到详情页静态状态,HTML 里啥提示都没有 → 代码误判成功。解法拦截 xhr/fetch 响应,盯 url 含apply|deliver的 JSON,解析{code, message}。这是唯一可靠的判据。letserverResultnull;page.on(response,async(res){consturlres.url();if(/(apply|deliver)/i.test(url)res.request().method()POST){try{constjsonawaitres.json();serverResult{code:json.code,message:json.message};}catch{}}});// 点完确认按钮后等 5sawaitpage.waitForTimeout(5000);if(serverResultserverResult.code200){return{ok:true};}else{thrownewError(SERVER_REJECTED:${serverResult?.message||unknown});}坑 5:parseSalary被日薪/小时绕过现象解析薪资时,遇到150-200元/天这种日薪格式,被当月薪解析,数字爆掉。解法优先级判定:面议 → 0/0;带/天//日//小时//时→ 0/0(明确不识别);万 → ×10;K → 原值;元 → ÷1000。functionparseSalary(text){if(/面议/i.test(text))return{min:0,max:0};if(/\/天|\/日|\/小时|\/时/i.test(text))return{min:0,max:0};// 不识别日薪// 正则提数字...if(/万/.test(text)){min*10;max*10;}if(/元/.test(text)){min/1000;max/1000;}return{min,max};}坑 6:headless 模式看不到验证码/滑块现象脚本跑headless: true时,遇到滑块验证码卡死(无法手动过),改headless: false又弹一堆窗口干扰开发。解法开发期headless: false,验证码/滑块用户手动过;生产跑通后再切headless: true,配合登录态持久化(profile 复用)避开二次登录。实测智联的滑块没法用 CV 自动过(有行为检测),所以人过一次 profile 持久 后续免登才是正道。总结:6 条经验登录态判定必须抓基线→ 避开 WAF cookie 误判Chrome ≠ Firefox profile→ 换浏览器内核要重新登录Vue 异步弹窗用三连发→ mouse.move dispatchEvent 原生 click 轮询 DOM投递结果看服务端响应→ 不看 HTML(会假成功)薪资解析先判日薪/小时→ 优先级判定,元/万/K 在后滑块人过 profile 持久→ 开发期 headless:false,生产复用 profile 免登同类问题接单/咨询如果你的项目也遇到反爬 / 登录态复用 / Vue/React 异步 DOM / 多平台自动化问题,欢迎付费咨询或外包接洽:技术博客(CSDN/掘金/知乎):搜我 IDkkYXGGitHub:https://github.com/kkYXG/ai-blog-publisher闲鱼(国内小单):搜Playwright 自动化邮箱:1138504375qq.com微信:yxg940122(备注自动化)起价:国内 ¥500,测试自动化 / 合规数据采集 / 内部流程 RPA / B 端工作流,不接灰产(撞库/绕付费墙/批量注册/刷量)。发布前检查清单:末尾联系方式填完整(微信/邮箱/GitHub/闲鱼搜索词)代码块用javascript包起来(CSDN 高亮加分)标题含PlaywrightFirefox反爬三个关键词 ✅CSDN 选原创标签 添加 3 个标签(Playwright / 自动化 / 反爬)