Skip to main content

lp-auto

基于 DrissionPage 的 liepin 自动化工具包。

lp-auto 把「打开浏览器 → 登录 → 搜索筛选 → 翻页 → 导出简历」这一整套重复劳动,封装成了一个 既能命令行调用、也能当作 Python 库导入 的工具包。它最大的特点是:复用同一个 Chrome 浏览器,登录一次、长期有效,后续脚本直接“接管”而不必反复扫码/输入密码。


目录


它能做什么

能力 说明
浏览器复用 首次启动 Chrome,之后直接接管,登录态、标签页全保留
人工登录 打开登录页挂起,等你扫码/输密码,登录后回车继续
登录校验 自动访问首页,判断是否被重定向回 /login
搜索筛选 按 placeholder 定位输入框,填入关键词、职位、公司
翻页 循环点击「下一页」,直到最后一页
简历导出 点开卡片详情 → 读取文本 → 存成 .txt 文件 → 关闭

安装

直接使用 pip 安装:

pip install lp-auto

依赖会自动安装:typer、DrissionPage、requests。安装完成后,lp-auto 命令即可在终端使用。


30 秒快速开始

第一步:登录一次(只需做一次)

lp-auto login

程序会自动启动一个 Chrome 浏览器,停在 liepin 登录页。你在浏览器里完成登录,页面跳转到工作台后,回到终端按 回车。

关掉终端也没关系——浏览器会保留,登录态也在。

第二步:导出简历(以后每天都这样)

先确认浏览器已打开并登录,然后进入搜索结果页后运行:

lp-auto collect --save-dir ./resumes

它会把当前页所有简历卡片保存下来,存到 ./resumes/ 里。

第三步:一键搜索 + 逐页导出

lp-auto run --save-dir ./resumes --max-pages 20

它会自动:打开搜索页 → 读取搜索词 → 搜索 → 导出第 1 页 → 翻页 → 导出第 2 页…… 直到最后一页或达到 --max-pages。

就这么简单。


命令行用法

所有命令都带 --help,随时查看:

lp-auto --help
lp-auto login --help

login — 登录

lp-auto login
lp-auto login --no-verify        # 登录后不做自动校验

verify — 校验登录态

lp-auto verify

成功(未被重定向)退出码为 0,失败为 1,方便写脚本判断。

search — 搜索筛选

支持两种方式:命令行直接传参,或 JSON 配置。

方式一:直接传参数(最方便)

lp-auto search --keyword Python --job 后端开发 --company 字节跳动

三个参数都可选,省略即不筛选该字段:

lp-auto search --keyword Python          # 只按关键词
lp-auto search --job 后端开发            # 只按职位

方式二:JSON 配置

lp-auto search --config ./search_config.json

--config 指向一个 JSON 文件,格式如下(字段名固定,值为空则跳过):

{
  "keyword": "Python",
  "job": "后端开发",
  "company": ""
}

不传 --config 也不传参数时,默认读 ~/.lp_auto/search_config.json。

collect — 导出当前页简历

lp-auto collect                          # 全部导出
lp-auto collect --start 3                # 从第 3 张开始
lp-auto collect --limit 10               # 最多 10 张
lp-auto collect --step 2                 # 隔一张导出一张
lp-auto collect --delay 1.5              # 每张之间歇 1.5 秒
lp-auto collect --save-dir ./resumes     # 保存目录

paginate — 翻页

lp-auto paginate --max-pages 20 --delay 2

identify — 调试:识别页面输入框

页面改版导致输入框定位不到时,用它看看当前页面有哪些输入框、placeholder 是什么:

lp-auto identify

run — 一键任务

lp-auto run --save-dir ./resumes --max-pages 20 --config ./search_config.json
lp-auto run --save-dir ./resumes --keyword Python --job 后端开发   # 也可直接传参

等效于:进搜索页 → 搜索 → 逐页导出。

公共参数

以下参数对所有命令生效:

参数 说明 默认
--port Chrome 调试端口 46517
--chrome Chrome 可执行文件路径 系统默认路径
--user-data Chrome 用户数据目录 D:\selenium_profile
--save-dir 简历保存目录 ~/.lp_auto/resumes

Python 函数用法

最简示例

from lp_auto import AppConfig, BrowserManager, Collector

cfg = AppConfig(chrome_exe=r"D:\Chrome\chrome.exe")  # 可选,覆盖默认配置
page = BrowserManager(cfg).get_page()                 # 接管浏览器
count = Collector(cfg).collect_page(page, limit=10)       # 导出 10 份简历
print(f"共保存 {count} 份")

完整业务流程

from lp_auto import (
    AppConfig, BrowserManager, LoginFlow,
    SearchController, Pagination, Collector,
)

cfg = AppConfig(save_dir="./resumes")
manager = BrowserManager(cfg)

# 1. 登录(首次需要人工扫码)
page = manager.get_page(open_url="https://lpt.liepin.com/login")
LoginFlow().wait_manual_login(page)
LoginFlow().verify(page)

# 2. 打开搜索页并输入条件
page.new_tab("https://lpt.liepin.com/search")
search = SearchController(cfg)
search.search(page, {"keyword": "Python", "job": "后端开发"})

# 3. 逐页导出
pagination = Pagination()
collector = Collector(cfg)
total = 0
while True:
    total += collector.collect_page(page)
    if pagination.is_last_page(page):
        break
    pagination.go_next_page(page)

print(f"总共导出 {total} 份")

异常处理

所有异常继承自 lp_auto.exceptions.LpAutoError,可以统一捕获:

from lp_auto import BrowserManager, AppConfig
from lp_auto.exceptions import BrowserLaunchError, LoginExpiredError

try:
    page = BrowserManager(AppConfig()).get_page()
except BrowserLaunchError:
    print("Chrome 启动失败,检查路径配置")
except LoginExpiredError:
    print("登录态失效,请重新登录")

示例脚本

examples/ 目录下提供了可直接运行的示例,覆盖从登录到完整流水线的常见场景。所有示例都假设你已 pip install lp-auto,并(如需登录)先用 lp-auto login 完成一次登录。

quickstart.py — 最简导出

接管已登录的浏览器,导出当前页前 10 份简历。运行前请确保浏览器已停在你想导出的搜索结果页。

python examples/quickstart.py
"""最简示例:接管浏览器,导出当前页前 10 份简历。

运行前请确保已经用 `lp-auto login` 完成过登录,
并且浏览器当前停在你想要导出的搜索结果页。
"""
from lp_auto import AppConfig, BrowserManager, Collector


def main() -> None:
    cfg = AppConfig(save_dir="./resumes")  # 覆盖默认保存目录
    page = BrowserManager(cfg).get_page()  # 接管已登录的浏览器

    print(f"当前页: {page.url}")
    saved = Collector(cfg).collect_page(page, limit=10)
    print(f"完成,共保存 {saved} 份")


if __name__ == "__main__":
    main()

login_demo.py — 登录与校验

打开登录页 -> 等待人工登录 -> 校验登录态。

python examples/login_demo.py
"""登录示例:打开登录页 -> 等待人工登录 -> 校验登录态。

    python examples/login_demo.py
"""
from lp_auto import AppConfig, BrowserManager, LoginFlow


def main() -> None:
    cfg = AppConfig()
    manager = BrowserManager(cfg)
    flow = LoginFlow()

    page = flow.open_login(manager)   # 启动/接管浏览器并打开登录页
    flow.wait_manual_login(page)      # 提示人工登录,按回车继续
    ok = flow.verify(page)            # 访问首页校验是否被重定向

    if not ok:
        raise SystemExit("登录态校验失败,请重试")


if __name__ == "__main__":
    main()

run_pipeline.py — 完整流水线

搜索 -> 逐页导出简历,直到最后一页或达到最大页数。

python examples/run_pipeline.py
"""完整流水线示例:搜索 -> 逐页导出简历。

    python examples/run_pipeline.py
"""
from lp_auto import (
    AppConfig,
    BrowserManager,
    Collector,
    Pagination,
    SearchController,
)


def main() -> None:
    cfg = AppConfig(save_dir="./resumes")
    page = BrowserManager(cfg).get_page()

    # 1. 打开搜索页并输入筛选条件
    page.new_tab("https://lpt.liepin.com/search")

    search = SearchController(cfg)
    search.search(page, {"keyword": "Python", "job": "后端开发"})

    # 2. 逐页导出
    pagination = Pagination()
    collector = Collector(cfg)

    total = 0
    max_pages = 20
    for _ in range(max_pages):
        total += collector.collect_page(page)
        if pagination.is_last_page(page):
            print("已到最后一页,结束")
            break
        pagination.go_next_page(page)

    print(f"流水线完成,共导出 {total} 份简历")


if __name__ == "__main__":
    main()

search_config.json — 搜索词配置

供 lp-auto search --config 或 SearchController.load_config() 使用的搜索词文件,字段名固定、值为空则跳过该字段:

{
  "keyword": "Python",
  "job": "后端开发",
  "company": ""
}

把它放到 ~/.lp_auto/search_config.json 即可被默认读取,或用 --config 指定任意路径。


配置说明

三种配置方式,优先级从高到低:

1. 代码里直接传参

cfg = AppConfig(
    debug_port=47100,
    chrome_exe=r"D:\Chrome\chrome.exe",
    user_data=r"D:\chrome_profile\lp",
    save_dir="./resumes",
)

2. 环境变量(前缀 LP_AUTO_)

# Windows (PowerShell)
$env:LP_AUTO_CHROME_EXE = "D:\Chrome\chrome.exe"
$env:LP_AUTO_DEBUG_PORT = "47100"
$env:LP_AUTO_SAVE_DIR = "D:\resumes"
cfg = AppConfig.from_env()   # 自动读取上述环境变量

支持的环境变量:LP_AUTO_DEBUG_PORT、LP_AUTO_USER_DATA、LP_AUTO_CHROME_EXE、LP_AUTO_DATA_DIR、LP_AUTO_SAVE_DIR、LP_AUTO_MIN_CARD_WIDTH。

3. 命令行参数

lp-auto collect --chrome "D:\Chrome\chrome.exe" --save-dir ./resumes

配置文件位置

文件 路径
会话记录(自动生成) ~/.lp_auto/lp_session.json
搜索词(可用 --config 覆盖) ~/.lp_auto/search_config.json
简历默认保存目录 ~/.lp_auto/resumes/

项目结构

采用 src 布局,把“易变的选择器/URL”和“稳定的业务逻辑”分离开来:

lp_auto/
├── pyproject.toml              # 打包与依赖配置
├── README.md
├── LICENSE
├── examples/                   # 可运行的示例脚本
│   ├── quickstart.py
│   ├── login_demo.py
│   └── run_pipeline.py
├── tests/                      # 单元测试
│   └── test_config.py
└── src/
    └── lp_auto/
        ├── __init__.py         # 导出公共 API
        ├── __main__.py         # 支持 python -m lp_auto
        ├── cli.py              # Typer 命令入口(只做分发,无业务逻辑)
        ├── config.py           # 统一配置 AppConfig
        ├── constants.py        # URL、选择器、超时等常量
        ├── exceptions.py       # 异常体系
        └── core/
            ├── browser.py      # 浏览器复用管理器
            ├── login.py        # 登录与校验
            ├── search.py       # 搜索筛选
            ├── pagination.py   # 翻页
            ├── collector.py      # 简历导出
            └── tabs.py         # 标签页管理

分层原则(高内聚、低耦合):

  • core/ 每个模块只做一件事,彼此不相互 import,只共享 config 和 constants。
  • 业务逻辑都通过 page 对象参数传递,而不是在模块内部偷偷创建浏览器。
  • 选择器、URL 集中放在 constants.py;页面改版时只改这一处。
  • cli.py 只是一层薄薄的“翻译”,把命令行参数转成对 core 的调用。

如何扩展

场景 1:页面改版,选择器失效

打开 src/lp_auto/constants.py,修改对应的选择器列表即可。例如「下一页」按钮的 class 变了,改 NEXT_SELECTORS:

NEXT_SELECTORS = [
    "css:.ant-pagination-next",
    "css:.my-new-next-button",   # 新增一个候选
]

多个候选会按顺序尝试,第一个命中的生效。

场景 2:新增一个搜索字段

在 constants.py 的 FIELD_HINTS 里加一条即可:

FIELD_HINTS = {
    "keyword": ["搜职位/公司"],
    "job": ["搜索职位"],
    "company": ["搜索公司"],
    "city": ["搜索城市"],        # 新增字段
}

然后搜索词 JSON 里就能写 "city": "北京" 了。

场景 3:新增一条命令

在 cli.py 里用 @app.command() 加一个函数,内部调用 core 即可,例如:

@app.command()
def export_all(
    save_dir: Optional[str] = _SAVE_DIR,
    max_pages: int = typer.Option(50),
):
    """导出所有页简历。"""
    cfg = _build_config(save_dir=save_dir)
    page = _manager(cfg).get_page()
    # ... 调用 core 完成逻辑

场景 4:把流程接进更大的系统

不要用 CLI,直接 import lp_auto,像「Python 函数用法」里那样组装 BrowserManager / SearchController / Pagination / Collector,完全自由。


核心原理解释

这一节用大白话讲清楚「为什么这样设计」,方便你判断和二次开发。

1. 为什么要“复用浏览器”而不是每次都开新的?

常规自动化(比如 Selenium)每次运行都开一个“干净”的新浏览器,没有登录、没有历史,于是每次都得重新登录。liepin 这类网站登录很麻烦(要扫码或验证码)。

lp-auto 的做法是:用一个固定的 Chrome + 固定的调试端口启动一次,然后把「端口号」记在一个小文件里。以后再运行,先去这个端口“敲门”(发个 HTTP 请求探测),如果浏览器还活着,就直接接管它——相当于你回到之前那个已经登录好的浏览器继续操作。于是登录一次,长期有效。

2. 什么是“接管”?它和“打开”有什么区别?

  • 打开:subprocess 拉起 Chrome 进程,带 --remote-debugging-port=46517 参数,告诉 Chrome「给我留一个 46517 端口的遥控接口」。
  • 接管:DrissionPage 通过 set_local_port(46517) 连上这个已经存在的遥控接口,而不是新建浏览器。

两者的差别就像:

「打开」= 买一台新手机并开机;「接管」= 拿起你桌子上那台已经登录好的手机继续用。

3. 选择器为什么用“候选列表”而不是“写死一个”?

网页的前端框架(这里是 antd)会自动生成一些带随机后缀的 class,比如 ant-pagination-next 在不同版本可能叫法略有差异。所以每个“要找的东西”都配了一串候选选择器,按顺序尝试,第一个能找到且可见的就用。这就像打开一扇门时,兜里揣了好几把钥匙,一把一把试。

4. 为什么输入框用 placeholder 定位而不是 id?

页面上的 id(如 rc_select_1)是前端框架自动编号的,产品一改版数字就可能变。而 placeholder(灰色提示文字)是产品经理写死的文案,相对稳定得多。所以我们用「搜索职位」「搜索公司」这类文字去匹配输入框,更抗改版。

5. 为什么点击“下一页”前后要做那么多判断?

翻页是“异步”的:点完按钮,新页面内容要过一会儿才渲染出来。所以流程是:

  1. 记录翻页前的页码;
  2. 点击按钮;
  3. 轮询等待页码发生变化(最多等 10 秒);
  4. 若按钮是「禁用/灰色」状态,说明到最后一页了,停止。

这一点细微的「等待 + 判断」,是自动化脚本稳定性的关键。


常见问题

Q1:提示 Chrome 启动失败?

检查 --chrome 和 --user-data 两个路径是否正确。chrome_exe 默认是 C:\Program Files\Google\Chrome\Application\chrome.exe,user_data 默认是 D:\selenium_profile,请改成你机器上真实存在(或想让其创建的)路径。

Q2:运行时把浏览器也一起关了?

不要调用页面的 quit()。本包所有接口都不会主动关闭浏览器,接管只是“借用”,退出脚本后浏览器仍然保留。

Q3:登录态失效怎么办?

重新 lp-auto login 登录一次即可。也可以 lp-auto verify 先探测一下当前是否还生效。

Q4:导出的文件是空的?

说明点击卡片后弹的不是标准模态框,或元素定位失效。先用 lp-auto identify 或修改 constants.py 里的 MODAL_CONTENT_SELECTORS / CARD_SELECTOR。

Q5:怎么设置搜索词?

默认读 ~/.lp_auto/search_config.json,或 lp-auto search --config ./my.json。


许可证

MIT


免责声明

在使用本项目(下称「本工具」)之前,请务必仔细阅读并充分理解本声明的全部内容。一旦下载、安装、运行或以任何方式使用本工具,即视为你已同意并接受本声明的全部条款。

一、使用目的

本工具仅供学习、研究及技术交流使用,旨在演示浏览器自动化、页面数据提取等编程技术。本工具不提供、不鼓励、不协助任何针对 liepin 平台(liepin.com)或其他任何网站进行的批量抓取、数据采集、账号滥用或规避反爬机制等行为。

二、合规与授权

  1. 使用本工具不得违反《中华人民共和国网络安全法》《中华人民共和国数据安全法》《中华人民共和国个人信息保护法》以及目标网站所在地的其他适用法律法规。
  2. 你应当自行查阅并严格遵守 liepin 平台的服务条款、用户协议、隐私政策及 robots 协议等平台规定,并自行取得使用相关数据的合法授权与许可。
  3. 本工具不用于:批量抓取简历/职位数据、采集或存储他人个人信息、绕过验证码或登录保护、干扰平台正常服务,或其他任何可能损害第三方合法权益的用途。
  4. 若你计划从事任何数据采集活动,须确保已获得数据主体及平台的明确授权,并对所采集数据的合法性、正当性与必要性负责。

三、风险自负

  1. 账号风险:不正当使用可能导致你的 liepin 账号被限制、封禁,或在法律层面被追究责任。此类风险及后果完全由使用者自行承担。
  2. 法律风险:因使用本工具产生的任何民事、行政或刑事责任,均由使用者自行承担。
  3. 数据风险:本工具生成或导出的数据可能存在不准确、不完整、过期等情况,作者不对数据的真实性、准确性与可用性作出任何保证。

四、责任免除

本项目按「现状(AS IS)」提供,作者不作任何明示或暗示的保证,包括但不限于对适销性、特定用途适用性、不侵权及持续可用性的保证。在适用法律允许的最大范围内,因安装、使用或无法使用本工具而造成的任何直接、间接、偶然、附带、特殊或后果性损失(包括但不限于数据丢失、账号封禁、利润损失、业务中断、行政处罚、诉讼及赔偿责任),作者及贡献者均不承担任何责任,即使已被告知发生此类损失的可能性。

五、其他

使用者应独立判断本工具的适用性,并对其使用行为负全部责任。若本声明的任何条款被认定无效或不可执行,不影响其余条款的效力。本声明的解释权及适用以中华人民共和国法律为准。

Metadata

Release files for lp-auto 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for lp-auto 0.1.0
File Size Uploaded
lp_auto-0.1.0.tar.gz 34.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for lp-auto 0.1.0
File Interpreter ABI Platform
lp_auto-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 65.1 kB

Release files / lp_auto-0.1.0.tar.gz

Download URL lp_auto-0.1.0.tar.gz
Size 34.5 kB
Tags Source
SHA-256 checksum
How to use checksums
df3d4b05875d710c5967cda20807269130dcb1b0e45e32c2cc8818685bb28604
BLAKE2b-256 checksum
How to use checksums
8a06d2771ca19f8afe07cb73632e87974d6e4e1d038159f72fa1d6e905a78431
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.7

Release files / lp_auto-0.1.0-py3-none-any.whl

Download URL lp_auto-0.1.0-py3-none-any.whl
Size 30.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
261a7312da8be189e4c99802b0b5becc08f7aea759ec06e5e9a6f32b7e3ec57d
BLAKE2b-256 checksum
How to use checksums
1d6803ad9f0dd84b266d94e7f793c286194ac7998f905bc31e0928d7a8039eed
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/4.0.2 CPython/3.11.7

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page