workface:Playwright 浏览器自动化求职
Node.js + Playwright 驱动的自动化求职工具,多平台简历投递。
项目背景
workface 是一个基于 Playwright 的浏览器自动化求职系统。求职者在找工作时,通常需要在多个招聘平台(BOSS 直聘、猎聘、拉勾、智联等)之间来回切换,手动搜索职位、筛选岗位、投递简历、记录投递状态。这个过程极其重复且耗时。workface 的目标就是自动化这一切。
项目采用"浏览器自动化 + 后端管理"的架构:Playwright 操控真实浏览器模拟用户操作,Spring Boot 后端处理数据存储和业务逻辑,Vue 3 前端提供可视化管理面板。
技术选型
| 组件 | 选择 | 理由 |
|---|---|---|
| 浏览器自动化 | Playwright(Node.js) | 比 Puppeteer 更现代,支持多浏览器、网络拦截 |
| 后端 | Spring Boot 3 + JPA | 任务管理、数据持久化 |
| 数据库 | PostgreSQL / MySQL | 关系型数据管理 |
| 前端 | Vue 3 + Vue Router | 移动端友好的管理面板 |
| 容器化 | Docker | 浏览器环境 + 后端统一部署 |
| 文件存储 | MinIO | 简历文件、截图存储 |
| AI 辅助 | Heuristic AI 适配器 | 智能匹配岗位和简历 |
架构设计
workface 采用"Browser Crawler Service + Java Backend + Vue Frontend"三层架构:
Vue 前端(管理界面)
│ REST API
▼
Spring Boot 后端(任务调度、数据管理、平台会话)
│ 指令通道
▼
Browser Crawler Service(Playwright 浏览器集群)
├── BOSS 直聘
├── 猎聘
├── 拉勾
└── 其他平台
核心模块:
- Platform Session 管理 — 维护各平台的登录态,通过持久化浏览器会话避免重复登录
- Job Search 引擎 — 多平台并行搜索,结果去重聚合
- Delivery 投递模块 — 自动投递简历,支持按条件筛选
- Interview 面试管理 — 面试邀请自动抓取与日历同步
- Profile 用户档案 — 多个简历版本管理
核心实现
Playwright 浏览器会话持久化
浏览器自动化求职最棘手的问题是如何保持登录态。workface 使用 Playwright 的持久化浏览器上下文功能:
// browser-crawler-service/server.js
const { chromium } = require('playwright');
async function startSession(platform, userId) {
const userDataDir = `./browser-profiles/${userId}/`;
const context = await chromium.launchPersistentContext(userDataDir, {
headless: false, // 首次登录需要交互
viewport: { width: 1280, height: 720 },
});
const page = await context.newPage();
if (platform === 'boss') {
await page.goto('https://www.zhipin.com/');
// 检查是否已登录
if (await page.locator('.login-btn').isVisible()) {
// 需要登录
await page.locator('.login-btn').click();
// 等待用户手动扫码或输入验证码...
await page.waitForURL('**/web/geek/**');
}
}
// 持久化上下文自动保存 cookies 和 localStorage
return { context, page };
}
多平台搜索适配器模式
workface 使用适配器模式封装不同平台的差异:
// 搜索引擎适配器
public interface CrawlerPort {
CrawlResult search(JobSearchCriteria criteria);
}
@Component
public class HttpCrawlerAdapter implements CrawlerPort {
public CrawlResult search(JobSearchCriteria criteria) {
// 通用的 HTTP 抓取逻辑,解析 HTML
}
}
@Component
public class BrowserCrawlerAdapter implements CrawlerPort {
private final WebClient webClient;
public CrawlResult search(JobSearchCriteria criteria) {
// 通过 Browser Crawler Service 执行复杂操作
}
}
// 路由适配器 - 根据平台选择策略
public class RoutingCrawlerAdapter implements CrawlerPort {
private final Map<String, CrawlerPort> adapters;
public CrawlResult search(JobSearchCriteria criteria) {
CrawlerPort adapter = adapters.get(criteria.getPlatform());
if (adapter == null) {
throw new UnsupportedOperationException("不支持的平台");
}
return adapter.search(criteria);
}
}
异步投递任务
@Service
public class DeliveryService {
@Async("taskExecutor")
public CompletableFuture<DeliveryResult> deliverResume(
Long taskId, String platform, String jobUrl) {
DeliveryResult result = new DeliveryResult(taskId);
try {
// 1. 通过 Browser Crawler 打开职位页面
// 2. 检查是否已投递
// 3. 点击"立即沟通"或"投递简历"
// 4. 记录投递结果
result.setStatus(DeliveryStatus.SUCCESS);
} catch (Exception e) {
result.setStatus(DeliveryStatus.FAILED);
result.setErrorMsg(e.getMessage());
}
return CompletableFuture.completedFuture(result);
}
}
踩坑记录
1. 反爬虫与验证码
招聘平台的反爬虫机制非常严格。早期使用纯 HTTP 请求抓取,很快被识别封 IP。解决方案:使用 Playwright 的完整浏览器环境(有头模式),模拟真实用户行为,包括随机延迟、鼠标移动、滚动等。
2. 登录态维护
各平台的登录态有效期不同,Cookie 刷新机制也不一样。解决方案:Playwright 的持久化浏览器上下文会自动保存所有会话数据(Cookies、LocalStorage、IndexedDB),下次启动时自动恢复,配合定时心跳请求刷新 Session。
3. 多平台 HTML 结构差异
每个招聘平台的 DOM 结构和 CSS 选择器都不同,且经常更新。解决方案:使用适配器模式隔离平台差异,每个平台有独立的解析逻辑;同时加入"失败检测"机制,当选择器匹配不到元素时自动截图告警。
4. 并发投递频率控制
短时间内大量投递会被平台判定为机器人。解决方案:投递任务加入队列,每个投递之间间隔 30-60 秒随机延迟,每天总量设置上限(如 100 份/天)。
总结
workface 是一个典型的"自动化解决重复劳动"的项目。求职过程中的搜职位、筛岗位、投简历这些步骤,本质上都是"规则明确、重复性高"的操作,非常适合用浏览器自动化来解决。
技术层面,Playwright 的持久化浏览器上下文是这个项目的关键——它让自动化脚本能够"记住"登录态,大大降低了每次操作都需要重新登录的复杂度。适配器模式让系统可以轻松扩展新的招聘平台。异步任务机制保证了投递操作的可靠性和频率控制。
不过也要诚实地说,浏览器自动化在反爬虫场景下存在灰色地带——各招聘平台的用户协议通常禁止自动化操作。这个项目在技术上有意义,但在实际使用中需要谨慎评估合规风险。