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. 为什么点击“下一页”前后要做那么多判断?
翻页是“异步”的:点完按钮,新页面内容要过一会儿才渲染出来。所以流程是:
- 记录翻页前的页码;
- 点击按钮;
- 轮询等待页码发生变化(最多等 10 秒);
- 若按钮是「禁用/灰色」状态,说明到最后一页了,停止。
这一点细微的「等待 + 判断」,是自动化脚本稳定性的关键。
常见问题
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。
许可证
免责声明
在使用本项目(下称「本工具」)之前,请务必仔细阅读并充分理解本声明的全部内容。一旦下载、安装、运行或以任何方式使用本工具,即视为你已同意并接受本声明的全部条款。
一、使用目的
本工具仅供学习、研究及技术交流使用,旨在演示浏览器自动化、页面数据提取等编程技术。本工具不提供、不鼓励、不协助任何针对 liepin 平台(liepin.com)或其他任何网站进行的批量抓取、数据采集、账号滥用或规避反爬机制等行为。
二、合规与授权
- 使用本工具不得违反《中华人民共和国网络安全法》《中华人民共和国数据安全法》《中华人民共和国个人信息保护法》以及目标网站所在地的其他适用法律法规。
- 你应当自行查阅并严格遵守 liepin 平台的服务条款、用户协议、隐私政策及 robots 协议等平台规定,并自行取得使用相关数据的合法授权与许可。
- 本工具不用于:批量抓取简历/职位数据、采集或存储他人个人信息、绕过验证码或登录保护、干扰平台正常服务,或其他任何可能损害第三方合法权益的用途。
- 若你计划从事任何数据采集活动,须确保已获得数据主体及平台的明确授权,并对所采集数据的合法性、正当性与必要性负责。
三、风险自负
- 账号风险:不正当使用可能导致你的 liepin 账号被限制、封禁,或在法律层面被追究责任。此类风险及后果完全由使用者自行承担。
- 法律风险:因使用本工具产生的任何民事、行政或刑事责任,均由使用者自行承担。
- 数据风险:本工具生成或导出的数据可能存在不准确、不完整、过期等情况,作者不对数据的真实性、准确性与可用性作出任何保证。
四、责任免除
本项目按「现状(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)
| File | Size | Uploaded | |
|---|---|---|---|
| lp_auto-0.1.0.tar.gz | 34.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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
|