某直聘自动打招呼桌面助手

55 阅读11分钟

我做了一个 某直聘自动打招呼桌面助手,支持多账号、筛选岗位、实时日志

最近在投简历时发现一个痛点:每天要反复打开 某平台 直聘,搜索岗位、筛选城市/薪资/经验、点岗位、点立即沟通,动作高度重复。

于是我做了一个桌面版自动招呼助手:auto-resume

它基于:

  • Electron:桌面应用外壳
  • React + Vite + TypeScript:前端界面
  • Python FastAPI:本地后端服务
  • Patchright / Playwright:浏览器自动化
  • SQLite:本地任务和已招呼记录存储
  • WebSocket:实时日志推送

说明:某平台 直聘服务条款不允许自动化操作,本项目仅供学习交流。请合理控制频率,账号风险自担。


一、项目效果

这个工具主要解决几个问题:

  1. 多账号可以同时跑
    每个账号都有独立的 Chromium user_data_dir,cookie 和登录态互不影响。

  2. 可以自定义岗位筛选条件
    支持关键词、城市、薪资、经验、学历、公司规模、黑名单关键词。

  3. 可以配置多个搜索子任务
    比如先跑「前端开发」,再跑「React 开发」,每个子任务都有自己的招呼次数。

  4. 自动打招呼
    程序会打开岗位列表,读取岗位卡片,过滤不合适的岗位,然后点击「立即沟通」。

  5. 防重复招呼
    使用 SQLite 记录当天已经招呼过的岗位,同一个岗位当天不会重复处理。

  6. 实时日志
    前端通过 WebSocket 订阅任务状态,能看到程序当前在做什么。

  7. 支持暂停、继续、停止、编辑任务
    桌面端操作比较直观。


二、技术架构

整体架构如下:

auto-resume
├── Electron 桌面端
│   └── 加载 React 页面
│
├── React 前端
│   ├── 创建任务
│   ├── 编辑任务
│   ├── 控制开始 / 暂停 / 继续 / 停止
│   └── 展示实时日志和今日已招呼记录
│
├── FastAPI 后端
│   ├── REST API 管理任务
│   ├── WebSocket 推送状态
│   ├── TaskManager 管理多个任务
│   └── SQLite 存储任务和已招呼记录
│
└── Patchright / Playwright 自动化
    ├── 打开独立浏览器 profile
    ├── 等待用户登录
    ├── 构造 某平台 搜索 URL
    ├── 抓取岗位卡片
    ├── 过滤黑名单和已招呼岗位
    └── 点击立即沟通

三、项目目录结构

auto-resume/
├── package.json
├── electron/
│   ├── main.cjs
│   └── preload.cjs
├── frontend/
│   ├── package.json
│   └── src/
│       ├── App.tsx
│       ├── api/client.ts
│       ├── store/useTasks.ts
│       ├── constants/cities.ts
│       └── components/
│           ├── NewTaskModal.tsx
│           ├── TaskCard.tsx
│           ├── TaskDetail.tsx
│           └── StatusBadge.tsx
└── backend/
    ├── requirements.txt
    ├── run_server.py
    └── app/
        ├── main.py
        ├── api/tasks.py
        ├── schemas/task.py
        ├── core/
        │   ├── config.py
        │   └── logger.py
        └── services/
            ├── boss_automator.py
            ├── task_manager.py
            └── storage.py

几个核心文件:

文件作用
frontend/src/components/NewTaskModal.tsx新建 / 编辑任务表单
frontend/src/components/TaskCard.tsx任务卡片和控制按钮
frontend/src/components/TaskDetail.tsx日志和已招呼岗位详情
backend/app/api/tasks.py任务相关 REST API 和 WebSocket
backend/app/services/task_manager.py多任务调度和线程隔离
backend/app/services/boss_automator.py自动化核心逻辑
backend/app/services/storage.pySQLite 持久化

四、核心功能拆解

1. 多账号隔离

每个任务都会生成独立的浏览器 profile:

backend/data/profiles/<task_id>/

这样每个账号的 cookie、登录状态、浏览器缓存都是独立的。

也就是说:

  • 账号 A 登录后,不会影响账号 B
  • 每个任务可以对应一个 某平台 账号
  • 下次启动同一个任务时,可以复用之前的登录态

核心逻辑在 boss_automator.py 中:

self._ctx = await self._pw.chromium.launch_persistent_context(
    user_data_dir=str(_profile_dir(self.task_id)),
    channel="chromium",
    headless=False,
    no_viewport=True,
    locale="zh-CN",
    timezone_id="Asia/Shanghai",
)

这里用的是 launch_persistent_context,它和普通无痕上下文不同,会把用户数据持久化到本地目录。

2. 手动登录 + 自动复用登录态

第一次启动任务时,程序会打开浏览器,让用户手动扫码或输入账号密码登录。

登录成功后,会写入一个登录标记:

backend/data/profiles/<task_id>/.login_ok

后续判断这个任务是否登录过,就可以通过这个 marker 来判断。

这样做的好处是:

  • 不需要在程序里保存账号密码
  • 登录动作仍然由用户自己完成
  • cookie 由浏览器 profile 自己管理

3. 多子任务配置

创建任务时可以配置多个子任务。

例如:

子任务 1:关键词 React,城市深圳,目标 20 次
子任务 2:关键词 前端开发,城市广州,目标 20 次
子任务 3:关键词 Vue,城市远程,目标 10 次

后端数据结构:

class JobFilter(BaseModel):
    keyword: str
    city: Optional[str] = None
    salary: Optional[str] = None
    experience: Optional[str] = None
    degree: Optional[str] = None
    scale: Optional[str] = None
    exclude_keywords: List[str] = []


class SubTask(BaseModel):
    filter: JobFilter
    limit: int = 10

任务会按顺序执行:

  1. 先跑第一个子任务
  2. 达到该子任务次数后,进入下一个子任务
  3. 所有子任务跑完后,任务结束
  4. 如果达到每日总上限,也会提前结束

4. 自动构造 某平台 搜索地址

程序会根据筛选条件构造 某平台 搜索 URL。

比如:

params = {
    "query": f.keyword,
    "city": city_code,
}

如果用户选择了薪资、经验、学历、公司规模,也会继续拼接:

if f.salary:
    params["salary"] = f.salary
if f.experience:
    params["experience"] = f.experience
if f.degree:
    params["degree"] = f.degree
if f.scale:
    params["scale"] = f.scale

最终得到类似:

https://www.zhipin.com/web/geek/job?query=前端开发&city=101280600&salary=405

5. 岗位列表抓取

进入搜索页后,程序会等待岗位列表出现,然后从页面里抓取岗位卡片。

抓取的信息包括:

  • 岗位标题
  • 公司名称
  • 岗位标签
  • 详情链接
  • 是否已经沟通过

抓取后会进入过滤阶段。

6. 黑名单过滤

每个子任务可以配置黑名单关键词。

比如:

外包, 外派, 实习, 驻场

程序会把岗位标题、公司名、标签拼成一段文本,然后判断是否命中黑名单。

命中后直接跳过。

def _matches_blacklist(text: str, blacklist: List[str]) -> bool:
    text = (text or "").lower()
    return any(kw.lower() in text for kw in blacklist if kw.strip())

7. 已招呼幂等处理

为了避免重复打招呼,项目使用 SQLite 记录当天已招呼过的岗位。

表结构大致是:

CREATE TABLE IF NOT EXISTS greeted_jobs(
    task_id TEXT NOT NULL,
    job_key TEXT NOT NULL,
    day TEXT NOT NULL,
    greeted_at TEXT NOT NULL,
    title TEXT,
    company TEXT,
    sub_index INTEGER NOT NULL DEFAULT 0,
    PRIMARY KEY (task_id, job_key, day)
);

重点是这个主键:

PRIMARY KEY (task_id, job_key, day)

它保证同一个任务、同一个岗位、同一天只会记录一次。

即使页面刷新、翻页或重新启动任务,也不会重复招呼同一个岗位。

8. 点击立即沟通

过滤通过后,程序会:

  1. 点击左侧岗位卡片
  2. 等待右侧详情加载
  3. 找到「立即沟通」按钮
  4. 点击按钮
  5. 如果出现弹窗,填写或确认招呼语
  6. 关闭弹窗
  7. 记录已招呼岗位

招呼语可以自定义多条:

您好,我对贵司这个岗位很感兴趣,希望能进一步沟通。
您好,看了岗位描述比较匹配,方便的话可以聊一下。

程序每次会随机选择一条,让行为不要太机械。

9. 实时日志推送

后端通过 WebSocket 推送任务状态和日志。

接口在:

/api/tasks/ws/{task_id}

前端订阅后,可以实时收到:

  • 当前状态
  • 已招呼数量
  • 当前子任务
  • 最新处理岗位
  • 日志列表

这也是为什么桌面端可以看到程序实时运行过程。

10. Windows 下的多任务隔离

这个项目里有一个比较关键的点:每个自动化任务跑在独立线程里。

原因是 Windows 上 Playwright 启动浏览器需要兼容子进程事件循环。

任务管理器里做了处理:

if sys.platform == "win32":
    asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(coro)

这样每个任务都有自己的线程和事件循环。

好处:

  • 多任务可以并行
  • 浏览器操作不会阻塞 FastAPI 主循环
  • WebSocket 推送仍然回到主事件循环执行

五、安装和运行

1. 环境要求

需要准备:

  • Python 3.10+
  • Node.js 18+
  • Chrome / Chromium

2. 克隆项目

git clone https://github.com/wangrujun2016/auto-resume.git
cd auto-resume

3. 安装前端和 Electron 依赖

npm run install:all

4. 安装 Python 后端依赖

Windows:

cd backend
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
python -m patchright install chromium
cd ..

macOS / Linux:

cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python -m patchright install chromium
cd ..

5. 启动开发模式

Windows:

npm run dev

macOS:

npm run dev:mac

启动后会同时运行三个服务:

服务说明
FastAPI127.0.0.1:8765
Vite127.0.0.1:5173
Electron桌面应用窗口

六、使用步骤

第一步:新建账号任务

打开应用后,点击左侧的「新建账号任务」。

需要填写:

  • 任务 / 账号别名
  • 搜索关键词
  • 城市
  • 薪资
  • 经验
  • 学历
  • 公司规模
  • 黑名单关键词
  • 本子任务次数
  • 自定义招呼语
  • 间隔秒数
  • 每日总上限
  • 点开详情后的等待秒数

其中必填项主要是:

  • 任务名称
  • 搜索关键词

第二步:配置子任务

如果你只想跑一个关键词,保留一个子任务即可。

如果你想分批跑多个方向,可以继续添加子任务。

比如:

子任务 1:Java 后端,深圳,20 次
子任务 2:Spring Boot,广州,20 次
子任务 3:后端开发,杭州,20 次

程序会按顺序执行。

第三步:登录账号

点击任务卡片上的「登录」或「开始」。

首次运行会弹出浏览器窗口。

你需要手动完成 某平台 登录:

  • 扫码登录
  • 账号密码登录

登录成功后,程序会保存浏览器 profile。

下次再跑同一个任务,就不需要重复登录。

第四步:开始自动招呼

登录完成后,点击「开始」。

程序会自动:

  1. 打开 某平台 首页
  2. 检查登录状态
  3. 跳转搜索页
  4. 抓取岗位列表
  5. 跳过黑名单岗位
  6. 跳过今日已招呼岗位
  7. 点击岗位详情
  8. 点击「立即沟通」
  9. 发送招呼语
  10. 写入 SQLite 记录
  11. 等待设定间隔后处理下一个岗位

第五步:查看日志

点击任务卡片,可以进入任务详情。

这里可以看到:

  • 实时运行日志
  • 今日已招呼岗位
  • 当前任务状态
  • 已发送数量

如果某个岗位被跳过,日志里也会说明原因。

第六步:暂停 / 继续 / 停止

任务运行中可以随时操作:

  • 暂停:当前任务暂时不继续处理新岗位
  • 继续:恢复运行
  • 停止:结束当前自动化任务
  • 编辑:修改任务配置,下次启动生效
  • 删除:删除任务和对应浏览器 profile

七、打包桌面应用

Windows 打包

$env:CSC_IDENTITY_AUTO_DISCOVERY="false"
npm run dist:win

产物在:

release/

常见产物:

release/某平台自动招呼助手-Setup-0.1.0.exe
release/win-unpacked/

macOS 打包

npm run dist:mac

也可以只打当前架构:

npm run dist:mac:dmg

产物类似:

release/某平台自动招呼助手-0.1.0-x64.dmg
release/某平台自动招呼助手-0.1.0-arm64.dmg

八、本地数据存储位置

开发环境下,数据主要在:

backend/data/

包括:

backend/data/auto_resume.sqlite
backend/data/profiles/<task_id>/

打包后,不同系统的数据路径不同:

平台路径
Windows%APPDATA%\AutoResume\
macOS~/Library/Application Support/AutoResume/
Linux~/.local/share/AutoResume/

如果想让某个账号重新登录,删除对应的 profile 即可。


九、常见问题

1. 为什么点击不到「立即沟通」?

某平台 前端 DOM 可能会变。

如果页面结构变了,需要调整:

backend/app/services/boss_automator.py

里面的选择器逻辑。

2. 为什么登录超时?

默认等待登录时间是 10 分钟。

如果 10 分钟内没有完成登录,任务会报登录超时。

可以调整:

_wait_for_login(timeout_seconds=600)

3. 可以隐藏浏览器运行吗?

理论上可以把:

headless=False

改成:

headless=True

但不推荐。

因为首次登录需要人工操作,而且招聘网站对 headless 浏览器通常比较敏感。

4. 为什么要设置间隔?

不要高频点击。

项目里默认会有间隔和随机抖动,用来降低连续机械操作的特征。

建议合理设置频率,比如 30 秒以上。

5. 会不会重复打招呼?

正常不会。

项目会用 SQLite 记录当天已经招呼过的岗位,同一天同任务下不会重复处理同一个岗位。


十、项目亮点总结

这个项目虽然是一个小工具,但里面涉及到的东西还挺完整:

  • Electron 桌面应用
  • React 任务管理界面
  • FastAPI 本地服务
  • WebSocket 实时通信
  • SQLite 本地持久化
  • Playwright / Patchright 浏览器自动化
  • 多账号浏览器 profile 隔离
  • 多线程 + 多事件循环任务调度
  • 任务暂停、继续、停止
  • 自动化幂等处理
  • Windows / macOS 打包

如果你正在学习 Electron + Python 后端 + 浏览器自动化,这个项目也可以作为一个完整案例来参考。


十一、源码和下载

创作不易,跪求 star,麻烦点个小星星~

源码地址:

github.com/wangrujun20…

下载链接:

pan.baidu.com/s/1e5lkqYON…

提取码:

8bkt