Skip to main content

LinkedIn recruiter message automation toolkit

Project description

recruiter-msg

LinkedIn 招聘者消息自动化工具包 —— 基于 Selenium 的 LinkedIn Recruiter 消息批量发送、候选人筛选与去重管理工具。


功能特性

  • 批量消息发送:从 Excel 读取候选人列表,自动导航至 LinkedIn Recruiter 页面并发送定制消息
  • 智能去重:基于 DiskCache + JSON 断点的双重去重机制,避免重复发送
  • 候选人筛选:支持基于关键词和 LLM 的姓名/职位评估,自动过滤非技术岗位
  • URN 缓存:自动缓存公开 URL 与 Recruiter URN 的映射关系,加速后续访问
  • 简历提取:从 LinkedIn 页面自动提取候选人资料文本并保存
  • LLM 集成:支持 OpenAI 兼容 API(DeepSeek、Ollama 等)进行智能评估
  • 模板变量:消息正文支持 {name}{title}{email}{linkedin_url} 动态替换
  • CLI 命令行:提供完整的 Typer CLI 工具,开箱即用

安装

从 PyPI 安装

pip install recruiter-msg

快速开始

第一步:初始化配置

recruiter-msg init

此命令会在当前目录生成 .env 文件,请编辑填入你的 LLM API 配置:

# LLM 配置
LLM_API_KEY=your-api-key-here
LLM_BASE_URL=http://api.openai.com/v1
LLM_MODEL=deepseek-v3.1-terminus-chat
LLM_TIMEOUT=120
LLM_MAX_RETRIES=3

如果不使用 LLM 评估功能,可跳过此步骤。

第二步:准备 Cookie 文件

本工具需要 LinkedIn Recruiter 的登录 Cookie 来访问招聘者页面:

  1. 用浏览器登录 LinkedIn Recruiter
  2. 安装 Cookie 导出浏览器插件(推荐 EditThisCookieCookie-Editor
  3. 导出 Cookie 为 JSON 格式
  4. 保存为 cookie.json 到当前目录(或通过 --cookie-file 指定路径)

第三步:准备候选人 Excel 文件

创建一个 Excel 文件(.xlsx),包含以下列:

列名 说明
url LinkedIn 个人资料 URL(公开链接或 Recruiter 链接)
tag 标签,用于过滤(如 "agent"
recommend_title 推荐职位标题,同时用作消息主题
email_content 消息正文内容,支持模板变量替换

模板变量:在 email_content 中可使用以下变量,发送时自动替换:

  • {name} — 候选人姓名(从 LinkedIn 页面解析)
  • {title} — 候选人当前职位
  • {email} — 候选人邮箱(需配置邮箱数据源)
  • {linkedin_url} — 候选人 LinkedIn URL

示例 Excel 数据

url tag recommend_title email_content
https://linkedin.com/in/zhangsan agent 高级Java工程师 你好 {name},我们对你的背景很感兴趣...
https://linkedin.com/in/lisi agent AI算法工程师 Hi {name},有一个 {title} 的机会想和你聊聊...

第四步:运行自动化

# 基本运行(discover 模式,使用 URN 缓存)
recruiter-msg run --excel ./candidates.xlsx --tag agent --mode discover

# 公开链接模式(首次运行,自动发现 URN 并缓存)
recruiter-msg run --excel ./candidates.xlsx --tag agent --mode public-url

# Recruiter 链接模式(Excel 中直接提供 talent/profile 链接)
recruiter-msg run --excel ./candidates.xlsx --tag agent --mode recruiter-url

# 启用 LLM 评估(智能筛选候选人)
recruiter-msg run --excel ./candidates.xlsx --llm --mode discover

# 指定切片范围(只处理第 5-10 位候选人)
recruiter-msg run --excel ./candidates.xlsx --start 4 --end 10

# 自定义延时(避免触发频率限制)
recruiter-msg run --excel ./candidates.xlsx --delay-min 2.0 --delay-max 5.0

# 无头模式(不显示浏览器窗口)
recruiter-msg run --excel ./candidates.xlsx --headless

# 详细日志输出
recruiter-msg run --excel ./candidates.xlsx -v

处理模式说明

模式 适用场景 说明
discover 已有 URN 缓存 Excel 提供公开链接,先查 URN 缓存,有则直接跳转招聘者页面,无缓存则失败
public-url 首次运行 Excel 提供公开链接,从公开页面导航并自动发现招聘者链接,缓存 URN
recruiter-url 仅有招聘者链接 Excel 提供招聘者链接,直接访问并回填 URN 缓存

其他命令

# 列出 Excel 中的候选人
recruiter-msg list-candidates --excel ./candidates.xlsx --tag agent --limit 20

# 检查某个标识符是否已发送
recruiter-msg check-duplicate "https://linkedin.com/in/zhangsan"

# 初始化 .env 配置文件(使用 --force 覆盖已有文件)
recruiter-msg init --force

项目架构

目录结构

recruiter-msg/
├── pyproject.toml              # 项目构建配置与依赖声明
├── README.md                   # 项目文档
├── LICENSE                     # MIT 许可证
├── src/recruiter_msg/
│   ├── __init__.py             # 包入口,导出所有公共 API
│   ├── models.py               # 数据模型定义
│   ├── interfaces.py           # 抽象接口(策略模式)
│   ├── exceptions.py           # 自定义异常
│   ├── checker.py              # 去重检查器实现
│   ├── datasource.py           # 候选人数据源实现
│   ├── parser.py               # LinkedIn 页面解析器
│   ├── navigator.py            # LinkedIn 页面导航器
│   ├── sender.py               # LinkedIn 消息发送器
│   ├── evaluator.py            # 评估器实现
│   ├── strategy.py             # 消息策略实现
│   ├── orchestrator.py         # 核心编排器与工厂函数
│   ├── resume.py               # 简历文本提取
│   ├── llm.py                  # LLM 客户端
│   └── cli.py                  # CLI 命令行入口
└── tests/                      # 测试目录

核心设计模式

本项目采用 策略模式(Strategy Pattern) 设计,所有核心功能通过抽象接口定义,具体实现可替换:

┌─────────────────────────────────────────────────────────────┐
│                    CLI (cli.py / Typer)                      │
│                  recruiter-msg run / list / ...              │
└──────────────────────────┬──────────────────────────────────┘
                           │
                           ▼
┌─────────────────────────────────────────────────────────────┐
│              Orchestrator (orchestrator.py)                  │
│           LinkedInAutomationOrchestrator                     │
│                                                              │
│  process_candidate() / process_candidate_urn()              │
│  process_candidate_direct_urn()                              │
│                                                              │
│  编排完整流程:导航 → 解析 → 评估 → 去重 → 生成消息 → 发送    │
└──┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬─────────┘
   │      │      │      │      │      │      │      │
   ▼      ▼      ▼      ▼      ▼      ▼      ▼      ▼
┌─────┐┌─────┐┌─────┐┌─────┐┌─────┐┌─────┐┌─────┐┌─────┐
│Nav  ││Parse││Name ││Title││Dedup││Msg  ││Send ││Data │
│     ││     ││Eval ││Eval ││Chk  ││Strat││     ││Src  │
└──┬──┘└──┬──┘└──┬──┘└──┬──┘└──┬──┘└──┬──┘└──┬──┘└──┬──┘
   │       │       │       │       │       │       │       │
   ▼       ▼       ▼       ▼       ▼       ▼       ▼       ▼
 接口层 (interfaces.py) — 9 个抽象基类

接口与实现对照表

抽象接口 实现类 职责
ProfileParser LinkedInProfileParser 解析 LinkedIn 个人资料页面
MessageStrategy ExcelMessageStrategy 基于模板生成消息内容
DuplicateChecker DiskCacheDuplicateChecker 基于 DiskCache 的去重
JsonCheckpointDuplicateChecker 基于 JSON 文件的断点去重
CompositeDuplicateChecker 组合多个去重检查器
Navigator LinkedInNavigator LinkedIn 页面导航与交互
MessageSender LinkedInMessageSender 消息输入与发送
NameEvaluator LLMNameEvaluator 基于 LLM 的姓名分类评估
TitleEvaluator KeywordTitleEvaluator 基于关键词的职位筛选
LLMTitleEvaluator 基于 LLM 的技术岗位识别
CandidateDataSource ExcelCandidateDataSource 从 Excel 加载候选人数据
EmailDataSource (需用户自行实现) 邮箱数据获取

数据模型

Config                    全局配置(状态关键词、主题关键词、招聘者标识)
Candidate                 候选人完整数据(URL、ID、URN、消息标题/正文、标签)
CandidateProfile          从页面解析的候选人资料(姓名、职位、LinkedIn URL)
MessageContent            消息内容(标题 + 正文)
MessageThread             消息线程(发件人、主题、状态、日期、预览)

处理流程

discover 模式为例,单个候选人的完整处理流程:

1. 查询 URN 缓存(公开 URL → Recruiter URN)
2. 导航至 Recruiter 个人资料页
3. 解析候选人资料(姓名、职位)
4. 评估姓名(可选,LLM 判断国籍过滤)
5. 评估职位(关键词过滤或 LLM 判断技术岗)
6. 保存简历文本(可选)
7. 检查消息历史(避免重复发送)
8. 检查缓存去重
9. 检查消息按钮可用性
10. 打开消息对话框
11. 生成消息内容(模板变量替换)
12. 发送消息
13. 标记为已发送(写入去重缓存 + 断点文件)

编程接口使用

除了 CLI 命令行,也可以在 Python 代码中直接调用:

from recruiter_msg import (
    Config,
    LinkedInAutomationOrchestrator,
    create_default_orchestrator,
    LLMClient,
)

# 1. 创建配置
config = Config(
    status_keywords=["Accepted", "Deleted"],
    subject_keywords=["Agent"],
    recruiter="chandler",
)

# 2. 创建编排器和数据源(需要先初始化 Selenium driver)
orchestrator, data_source = create_default_orchestrator(
    driver=driver,
    config=config,
    excel_path="./candidates.xlsx",
    tag_filter="agent",
    use_llm=True,               # 启用 LLM 评估
    urn_cache_dir="./cache_dir", # URN 缓存目录
    resume_dir="./resume",       # 简历保存目录
)

# 3. 加载候选人
candidates = data_source.fetch_candidates(tag_filter="agent")

# 4. 逐个处理
for candidate in candidates:
    result = orchestrator.process_candidate_urn(candidate)
    print(f"{'成功' if result else '失败'}: {candidate.linkedin_url}")

自定义实现

所有核心组件均可替换,只需实现对应的抽象接口:

from recruiter_msg import DuplicateChecker, MessageStrategy, Candidate, CandidateProfile, MessageContent

# 自定义去重检查器
class RedisDuplicateChecker(DuplicateChecker):
    def is_duplicate(self, identifier: str, content_key: str) -> bool:
        # 使用 Redis 实现
        ...

    def mark_as_sent(self, identifier: str, content_key: str) -> None:
        ...

# 自定义消息策略
class AIMessageStrategy(MessageStrategy):
    def generate_content(self, candidate: Candidate, profile: CandidateProfile) -> MessageContent:
        # 使用 LLM 动态生成消息
        ...

# 注入到编排器
orchestrator = LinkedInAutomationOrchestrator(
    driver=driver,
    duplicate_checker=RedisDuplicateChecker(),
    message_strategy=AIMessageStrategy(),
    ...
)

LLM 客户端配置

LLMClient 支持任何 OpenAI 兼容的 API 服务:

from recruiter_msg import LLMClient

# 方式一:通过 .env 文件配置
# LLM_API_KEY=sk-xxx
# LLM_BASE_URL=https://api.deepseek.com/v1
# LLM_MODEL=deepseek-chat

# 方式二:直接传参
client = LLMClient(
    api_key="sk-xxx",
    base_url="https://api.deepseek.com/v1",
    model="deepseek-chat",
    timeout=120,
    max_retries=3,
)

# 方式三:使用本地 Ollama
client = LLMClient(
    api_key="ollama",
    base_url="http://localhost:11434/v1",
    model="qwen2.5:7b",
)

# 调用
response = client.chat("你是助手", "你好")
result = client.chat_json("你是分类专家", "判断以下职位是否为技术岗:Java工程师")

常见问题

Q: Cookie 过期怎么办?

重新导出 LinkedIn Cookie 并替换 cookie.json 文件即可。LinkedIn Cookie 通常有效期为数天至数周。

Q: 如何避免被 LinkedIn 限制?

  • 使用 --delay-min--delay-max 设置合理的操作间隔(建议 2-5 秒)
  • 使用 --start--end 分批处理候选人
  • 避免短时间内大量操作

Q: URN 缓存有什么用?

LinkedIn Recruiter 页面使用 URN(如 ACoAABxxx)标识候选人,而 Excel 中通常只有公开链接。URN 缓存将公开 URL 映射到 Recruiter URN,避免每次都需要从公开页面重新发现 Recruiter 链接,大幅提升处理速度。


免责声明

本工具仅供学习和研究目的使用。

  1. 服务条款:本工具的自动化操作可能违反 LinkedIn 的服务条款(Terms of Service)和用户协议。使用本工具即表示你知悉并自行承担因违反服务条款而导致的一切后果,包括但不限于账号被限制、封禁或法律追诉。

  2. 合规使用:使用者应确保其使用方式符合所在地区的法律法规,包括但不限于数据隐私法(如 GDPR、CCPA 等)、反垃圾信息法以及劳动就业相关法规。

  3. 无担保:本工具按"原样"(AS IS)提供,不作任何明示或暗示的担保,包括但不限于适销性、特定用途适用性和非侵权性。作者不对使用本工具所产生的任何直接、间接、附带、特殊或后果性损害承担责任。

  4. 风险自担:使用者应当充分理解本工具的功能和潜在风险,自行评估并承担所有使用风险。作者不对因使用本工具而导致的任何损失、数据泄露、账号问题或其他不良后果承担任何责任。

  5. 非商业用途:本工具不鼓励也不支持任何形式的商业滥用、大规模自动化骚扰或垃圾信息发送行为。

  6. 修改与终止:作者保留随时修改、更新或终止本工具的权利,无需事先通知。

使用本工具即表示你已阅读、理解并同意以上免责声明的所有条款。如果你不同意,请勿使用本工具。

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

recruiter_msg-0.1.0.tar.gz (21.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

recruiter_msg-0.1.0-py3-none-any.whl (28.1 kB view details)

Uploaded Python 3

File details

Details for the file recruiter_msg-0.1.0.tar.gz.

File metadata

  • Download URL: recruiter_msg-0.1.0.tar.gz
  • Upload date:
  • Size: 21.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for recruiter_msg-0.1.0.tar.gz
Algorithm Hash digest
SHA256 956b4e19b1cb4e7b3be156324d0a8ce6ce24d4bbb9be5c2365dcbdbf35a5d5dd
MD5 1d324297a2e56a84f92ccb314bfa9752
BLAKE2b-256 295c8d140cd649ef26534e68d07888544b24349c905a7c528574fba45ba4342b

See more details on using hashes here.

File details

Details for the file recruiter_msg-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: recruiter_msg-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 28.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for recruiter_msg-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b54e383a83f5f15fef154a1e9bcc5f91103f09722f1d5d3908acca5c2d3928e5
MD5 38f3dcf7d9c0945339b31e5849eb8fd4
BLAKE2b-256 6017e04af4dc51d4e1d40090ab465ee3cc4d823b828a187858c960d961615594

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page