linkedin-horse 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,222 @@
1
+ Metadata-Version: 2.4
2
+ Name: linkedin-horse
3
+ Version: 0.1.0
4
+ Summary: LinkedIn 搜索结果资料提取工具 — 自动化抓取、解析、导出
5
+ Author: linkedin-horse contributors
6
+ License-Expression: MIT
7
+ Keywords: linkedin,scraper,cli,typer,rich
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: Utilities
16
+ Requires-Python: >=3.9
17
+ Description-Content-Type: text/markdown
18
+ Requires-Dist: typer>=0.9.0
19
+ Requires-Dist: rich>=13.0.0
20
+ Requires-Dist: beautifulsoup4>=4.12.0
21
+ Requires-Dist: pandas>=2.0.0
22
+ Requires-Dist: openpyxl>=3.1.0
23
+ Requires-Dist: python-dotenv>=1.0.0
24
+ Requires-Dist: linkedin-cat
25
+ Requires-Dist: llmdog
26
+ Requires-Dist: larkfunc
27
+
28
+ # linkedin-horse
29
+
30
+ LinkedIn 搜索结果资料自动提取工具 — 基于 Selenium 自动化浏览器,从 LinkedIn 搜索页批量抓取个人资料数据,支持分页采集、自动去重、JSON 中间存储和 Excel 最终导出。
31
+
32
+ ## 功能特性
33
+
34
+ - **自动化采集**:基于 Selenium 驱动 Chrome 浏览器,模拟真实用户操作
35
+ - **智能解析**:多策略 HTML 解析,兼容 LinkedIn 新旧版页面结构
36
+ - **分页抓取**:支持指定起止页码,逐页自动翻页采集
37
+ - **自动去重**:基于 `profile_url` 自动过滤重复记录,支持增量采集
38
+ - **双格式存储**:每页数据实时保存为 JSON 文件,最终合并导出 Excel
39
+ - **重试机制**:每页最多 3 次重试,网络波动不丢数据
40
+ - **现代 CLI**:基于 Typer + Rich 构建,彩色输出、进度条、配置面板
41
+ - **Cookie 引导**:首次运行自动检测 Cookie 文件,提供详细的导出操作指引
42
+
43
+ ## 安装和环境配置
44
+
45
+ ### 安装
46
+
47
+ ```bash
48
+ pip install linkedin-horse
49
+ ```
50
+
51
+ ### 环境要求
52
+
53
+ - Python >= 3.9
54
+ - Chrome 浏览器(用于 Selenium 驱动)
55
+ - ChromeDriver(版本需与 Chrome 匹配)
56
+
57
+ ### Cookie 配置(首次使用必读)
58
+
59
+ linkedin-horse 需要你的 LinkedIn 登录态 Cookie 来访问搜索结果。首次运行时,程序会自动检测并提示你配置。
60
+
61
+ **操作步骤:**
62
+
63
+ 1. **安装 EditThisCookie 插件**
64
+ 打开 Chrome 浏览器,访问 [Chrome Web Store](https://chrome.google.com/webstore),搜索 "EditThisCookie" 并安装。
65
+
66
+ 2. **登录 LinkedIn**
67
+ 在 Chrome 中访问 https://www.linkedin.com 并登录你的账号,确保页面正常显示首页 Feed。
68
+
69
+ 3. **导出 Cookies**
70
+ 点击浏览器右上角的 EditThisCookie 插件图标(饼干形状),在弹出窗口中点击"导出"按钮。
71
+
72
+ 4. **保存文件**
73
+ 新建文本文件,粘贴剪贴板内容,保存为 `linkedin_cookies.json`,放置在程序运行目录下。
74
+
75
+ 5. **验证**
76
+ 确保文件是合法的 JSON 数组格式(以 `[` 开头,以 `]` 结尾)。
77
+
78
+ ## 使用示例
79
+
80
+ ### 基本用法
81
+
82
+ ```bash
83
+ # 从 LinkedIn 搜索页提取数据(第 1-5 页)
84
+ linkedin-horse extract \
85
+ --base-url "https://www.linkedin.com/search/results/people/?keywords=python%20developer&origin=GLOBAL_SEARCH_HEADER" \
86
+ --search-keyword "python_developer" \
87
+ --start-page 1 \
88
+ --end-page 5
89
+ ```
90
+
91
+ ### 完整参数示例
92
+
93
+ ```bash
94
+ linkedin-horse extract \
95
+ --base-url "https://www.linkedin.com/search/results/people/?keywords=data%20engineer" \
96
+ --search-keyword "data_engineer" \
97
+ --start-page 1 \
98
+ --end-page 20 \
99
+ --headless \
100
+ --cookies-json ./my_cookies.json \
101
+ --max-retries 5 \
102
+ --retry-delay 10
103
+ ```
104
+
105
+ ### 输出结构
106
+
107
+ 运行后会生成以下文件结构:
108
+
109
+ ```
110
+ ./
111
+ ├── data_engineer/ # 以 search_keyword 命名的数据目录
112
+ │ ├── data_engineer_1.json # 第 1 页数据
113
+ │ ├── data_engineer_2.json # 第 2 页数据
114
+ │ └── ...
115
+ └── data_engineer.xlsx # 最终合并的 Excel 文件
116
+ ```
117
+
118
+ ### 查看帮助
119
+
120
+ ```bash
121
+ linkedin-horse --help
122
+ linkedin-horse extract --help
123
+ ```
124
+
125
+ ## API 接口说明
126
+
127
+ linkedin-horse 采用模块化设计,核心模块可独立调用:
128
+
129
+ ### extractor 模块
130
+
131
+ ```python
132
+ from linkedin_horse.extractor import extract_profile_data_from_page
133
+
134
+ # 传入 HTML 源码,返回个人资料字典列表
135
+ profiles = extract_profile_data_from_page(html_source)
136
+ ```
137
+
138
+ ### export 模块
139
+
140
+ ```python
141
+ from linkedin_horse.export import save_page_json, merge_json_to_excel
142
+ from pathlib import Path
143
+
144
+ # 保存单页数据为 JSON
145
+ save_page_json(profiles, Path("my_search"), "my_search", page=1)
146
+
147
+ # 合并所有 JSON 为 Excel
148
+ merge_json_to_excel(Path("my_search"), Path("my_search.xlsx"))
149
+ ```
150
+
151
+ ### browser 模块
152
+
153
+ ```python
154
+ from linkedin_horse.browser import init_browser, fetch_page_with_retry, close_browser
155
+ from pathlib import Path
156
+
157
+ bot, driver = init_browser(Path("linkedin_cookies.json"), headless=True)
158
+ html = fetch_page_with_retry(driver, url, page_num=1)
159
+ close_browser(driver)
160
+ ```
161
+
162
+ ### cookies 模块
163
+
164
+ ```python
165
+ from linkedin_horse.cookies import check_cookies
166
+ from pathlib import Path
167
+
168
+ # 检查 Cookie 文件,不存在则输出指引并退出
169
+ check_cookies(Path("linkedin_cookies.json"))
170
+ ```
171
+
172
+ ## 依赖项清单
173
+
174
+ | 依赖 | 用途 |
175
+ |------|------|
176
+ | `typer` | CLI 框架 |
177
+ | `rich` | 终端美化输出 |
178
+ | `beautifulsoup4` | HTML 解析 |
179
+ | `pandas` | 数据处理与 Excel 导出 |
180
+ | `openpyxl` | Excel 文件引擎 |
181
+ | `python-dotenv` | 环境变量加载 |
182
+ | `linkedin-cat` | LinkedIn 浏览器自动化 |
183
+ | `llmdog` | LLM 调用封装 |
184
+ | `larkfunc` | 通用工具函数库 |
185
+
186
+ ## 技术架构
187
+
188
+ ```
189
+ linkedin_horse/
190
+ ├── cli.py # Typer CLI 入口,参数解析与流程编排
191
+ ├── output.py # Rich 统一输出模块(主题、彩色打印函数)
192
+ ├── cookies.py # Cookie 文件检查与用户操作指引
193
+ ├── extractor.py # HTML 解析与个人资料数据提取(核心逻辑)
194
+ ├── browser.py # 浏览器初始化与页面获取(含重试机制)
195
+ └── export.py # JSON 分页存储 + Excel 合并导出
196
+ ```
197
+
198
+ **数据流**:`搜索 URL → 逐页抓取 HTML → 解析提取 → JSON 分页保存 → Excel 合并导出`
199
+
200
+ 各模块职责单一、接口清晰,便于后续扩展(如增加新的解析策略、输出格式等)。
201
+
202
+ ## 贡献指南与许可证
203
+
204
+ ### 贡献
205
+
206
+ 1. Fork 本仓库
207
+ 2. 创建功能分支 (`git checkout -b feature/my-feature`)
208
+ 3. 提交更改 (`git commit -m 'Add my feature'`)
209
+ 4. 推送到分支 (`git push origin feature/my-feature`)
210
+ 5. 创建 Pull Request
211
+
212
+ ### 许可证
213
+
214
+ 本项目基于 MIT 许可证开源。
215
+
216
+ ### 免责声明
217
+
218
+ - 本工具仅供学习和研究用途,使用者需自行承担使用风险
219
+ - 使用本工具前请确保遵守 LinkedIn 的服务条款和使用政策
220
+ - 过度频繁的自动化访问可能导致账号被限制,请合理控制采集频率
221
+ - 开发者不对因使用本工具产生的任何后果承担责任
222
+ - 请尊重他人隐私,合法合规地使用采集到的数据
@@ -0,0 +1,195 @@
1
+ # linkedin-horse
2
+
3
+ LinkedIn 搜索结果资料自动提取工具 — 基于 Selenium 自动化浏览器,从 LinkedIn 搜索页批量抓取个人资料数据,支持分页采集、自动去重、JSON 中间存储和 Excel 最终导出。
4
+
5
+ ## 功能特性
6
+
7
+ - **自动化采集**:基于 Selenium 驱动 Chrome 浏览器,模拟真实用户操作
8
+ - **智能解析**:多策略 HTML 解析,兼容 LinkedIn 新旧版页面结构
9
+ - **分页抓取**:支持指定起止页码,逐页自动翻页采集
10
+ - **自动去重**:基于 `profile_url` 自动过滤重复记录,支持增量采集
11
+ - **双格式存储**:每页数据实时保存为 JSON 文件,最终合并导出 Excel
12
+ - **重试机制**:每页最多 3 次重试,网络波动不丢数据
13
+ - **现代 CLI**:基于 Typer + Rich 构建,彩色输出、进度条、配置面板
14
+ - **Cookie 引导**:首次运行自动检测 Cookie 文件,提供详细的导出操作指引
15
+
16
+ ## 安装和环境配置
17
+
18
+ ### 安装
19
+
20
+ ```bash
21
+ pip install linkedin-horse
22
+ ```
23
+
24
+ ### 环境要求
25
+
26
+ - Python >= 3.9
27
+ - Chrome 浏览器(用于 Selenium 驱动)
28
+ - ChromeDriver(版本需与 Chrome 匹配)
29
+
30
+ ### Cookie 配置(首次使用必读)
31
+
32
+ linkedin-horse 需要你的 LinkedIn 登录态 Cookie 来访问搜索结果。首次运行时,程序会自动检测并提示你配置。
33
+
34
+ **操作步骤:**
35
+
36
+ 1. **安装 EditThisCookie 插件**
37
+ 打开 Chrome 浏览器,访问 [Chrome Web Store](https://chrome.google.com/webstore),搜索 "EditThisCookie" 并安装。
38
+
39
+ 2. **登录 LinkedIn**
40
+ 在 Chrome 中访问 https://www.linkedin.com 并登录你的账号,确保页面正常显示首页 Feed。
41
+
42
+ 3. **导出 Cookies**
43
+ 点击浏览器右上角的 EditThisCookie 插件图标(饼干形状),在弹出窗口中点击"导出"按钮。
44
+
45
+ 4. **保存文件**
46
+ 新建文本文件,粘贴剪贴板内容,保存为 `linkedin_cookies.json`,放置在程序运行目录下。
47
+
48
+ 5. **验证**
49
+ 确保文件是合法的 JSON 数组格式(以 `[` 开头,以 `]` 结尾)。
50
+
51
+ ## 使用示例
52
+
53
+ ### 基本用法
54
+
55
+ ```bash
56
+ # 从 LinkedIn 搜索页提取数据(第 1-5 页)
57
+ linkedin-horse extract \
58
+ --base-url "https://www.linkedin.com/search/results/people/?keywords=python%20developer&origin=GLOBAL_SEARCH_HEADER" \
59
+ --search-keyword "python_developer" \
60
+ --start-page 1 \
61
+ --end-page 5
62
+ ```
63
+
64
+ ### 完整参数示例
65
+
66
+ ```bash
67
+ linkedin-horse extract \
68
+ --base-url "https://www.linkedin.com/search/results/people/?keywords=data%20engineer" \
69
+ --search-keyword "data_engineer" \
70
+ --start-page 1 \
71
+ --end-page 20 \
72
+ --headless \
73
+ --cookies-json ./my_cookies.json \
74
+ --max-retries 5 \
75
+ --retry-delay 10
76
+ ```
77
+
78
+ ### 输出结构
79
+
80
+ 运行后会生成以下文件结构:
81
+
82
+ ```
83
+ ./
84
+ ├── data_engineer/ # 以 search_keyword 命名的数据目录
85
+ │ ├── data_engineer_1.json # 第 1 页数据
86
+ │ ├── data_engineer_2.json # 第 2 页数据
87
+ │ └── ...
88
+ └── data_engineer.xlsx # 最终合并的 Excel 文件
89
+ ```
90
+
91
+ ### 查看帮助
92
+
93
+ ```bash
94
+ linkedin-horse --help
95
+ linkedin-horse extract --help
96
+ ```
97
+
98
+ ## API 接口说明
99
+
100
+ linkedin-horse 采用模块化设计,核心模块可独立调用:
101
+
102
+ ### extractor 模块
103
+
104
+ ```python
105
+ from linkedin_horse.extractor import extract_profile_data_from_page
106
+
107
+ # 传入 HTML 源码,返回个人资料字典列表
108
+ profiles = extract_profile_data_from_page(html_source)
109
+ ```
110
+
111
+ ### export 模块
112
+
113
+ ```python
114
+ from linkedin_horse.export import save_page_json, merge_json_to_excel
115
+ from pathlib import Path
116
+
117
+ # 保存单页数据为 JSON
118
+ save_page_json(profiles, Path("my_search"), "my_search", page=1)
119
+
120
+ # 合并所有 JSON 为 Excel
121
+ merge_json_to_excel(Path("my_search"), Path("my_search.xlsx"))
122
+ ```
123
+
124
+ ### browser 模块
125
+
126
+ ```python
127
+ from linkedin_horse.browser import init_browser, fetch_page_with_retry, close_browser
128
+ from pathlib import Path
129
+
130
+ bot, driver = init_browser(Path("linkedin_cookies.json"), headless=True)
131
+ html = fetch_page_with_retry(driver, url, page_num=1)
132
+ close_browser(driver)
133
+ ```
134
+
135
+ ### cookies 模块
136
+
137
+ ```python
138
+ from linkedin_horse.cookies import check_cookies
139
+ from pathlib import Path
140
+
141
+ # 检查 Cookie 文件,不存在则输出指引并退出
142
+ check_cookies(Path("linkedin_cookies.json"))
143
+ ```
144
+
145
+ ## 依赖项清单
146
+
147
+ | 依赖 | 用途 |
148
+ |------|------|
149
+ | `typer` | CLI 框架 |
150
+ | `rich` | 终端美化输出 |
151
+ | `beautifulsoup4` | HTML 解析 |
152
+ | `pandas` | 数据处理与 Excel 导出 |
153
+ | `openpyxl` | Excel 文件引擎 |
154
+ | `python-dotenv` | 环境变量加载 |
155
+ | `linkedin-cat` | LinkedIn 浏览器自动化 |
156
+ | `llmdog` | LLM 调用封装 |
157
+ | `larkfunc` | 通用工具函数库 |
158
+
159
+ ## 技术架构
160
+
161
+ ```
162
+ linkedin_horse/
163
+ ├── cli.py # Typer CLI 入口,参数解析与流程编排
164
+ ├── output.py # Rich 统一输出模块(主题、彩色打印函数)
165
+ ├── cookies.py # Cookie 文件检查与用户操作指引
166
+ ├── extractor.py # HTML 解析与个人资料数据提取(核心逻辑)
167
+ ├── browser.py # 浏览器初始化与页面获取(含重试机制)
168
+ └── export.py # JSON 分页存储 + Excel 合并导出
169
+ ```
170
+
171
+ **数据流**:`搜索 URL → 逐页抓取 HTML → 解析提取 → JSON 分页保存 → Excel 合并导出`
172
+
173
+ 各模块职责单一、接口清晰,便于后续扩展(如增加新的解析策略、输出格式等)。
174
+
175
+ ## 贡献指南与许可证
176
+
177
+ ### 贡献
178
+
179
+ 1. Fork 本仓库
180
+ 2. 创建功能分支 (`git checkout -b feature/my-feature`)
181
+ 3. 提交更改 (`git commit -m 'Add my feature'`)
182
+ 4. 推送到分支 (`git push origin feature/my-feature`)
183
+ 5. 创建 Pull Request
184
+
185
+ ### 许可证
186
+
187
+ 本项目基于 MIT 许可证开源。
188
+
189
+ ### 免责声明
190
+
191
+ - 本工具仅供学习和研究用途,使用者需自行承担使用风险
192
+ - 使用本工具前请确保遵守 LinkedIn 的服务条款和使用政策
193
+ - 过度频繁的自动化访问可能导致账号被限制,请合理控制采集频率
194
+ - 开发者不对因使用本工具产生的任何后果承担责任
195
+ - 请尊重他人隐私,合法合规地使用采集到的数据
@@ -0,0 +1,3 @@
1
+ """linkedin-horse: LinkedIn 搜索结果资料提取工具"""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,84 @@
1
+ """
2
+ linkedin_horse.browser
3
+ 浏览器初始化与页面获取(含重试机制)
4
+ """
5
+
6
+ import time
7
+ from pathlib import Path
8
+ from typing import Optional
9
+
10
+ import typer
11
+
12
+ from linkedin_cat.message import LinkedinMessage
13
+
14
+ from linkedin_horse.output import console, print_error, print_info
15
+
16
+
17
+ def init_browser(cookies_json: Path, headless: bool = False):
18
+ """
19
+ 初始化 LinkedIn 浏览器实例。
20
+
21
+ Args:
22
+ cookies_json: cookies JSON 文件路径
23
+ headless: 是否使用无头模式
24
+
25
+ Returns:
26
+ (bot, driver) 元组
27
+
28
+ Raises:
29
+ typer.Exit: 初始化失败时终止程序
30
+ """
31
+ try:
32
+ bot = LinkedinMessage(str(cookies_json), headless)
33
+ driver = bot.driver
34
+ print_info("浏览器已启动")
35
+ return bot, driver
36
+ except Exception as e:
37
+ print_error(f"初始化浏览器失败: {e}")
38
+ raise typer.Exit(code=1)
39
+
40
+
41
+ def close_browser(driver) -> None:
42
+ """安全关闭浏览器"""
43
+ try:
44
+ driver.quit()
45
+ print_info("浏览器已关闭")
46
+ except Exception:
47
+ pass
48
+
49
+
50
+ def fetch_page_with_retry(
51
+ driver,
52
+ url: str,
53
+ page_num: int,
54
+ max_retries: int = 3,
55
+ delay: int = 5,
56
+ ) -> Optional[str]:
57
+ """
58
+ 获取页面 HTML 源码,带重试机制。
59
+
60
+ Args:
61
+ driver: Selenium WebDriver 实例
62
+ url: 目标页面 URL
63
+ page_num: 当前页码(用于日志显示)
64
+ max_retries: 最大重试次数
65
+ delay: 重试间隔秒数
66
+
67
+ Returns:
68
+ 页面 HTML 源码,失败返回 None
69
+ """
70
+ for attempt in range(1, max_retries + 1):
71
+ try:
72
+ console.log(f"[dim]页面 {page_num} 尝试 {attempt}/{max_retries}[/dim]")
73
+ driver.get(url)
74
+ time.sleep(6) # 等待动态内容加载
75
+ return driver.page_source
76
+ except Exception as e:
77
+ print_error(f"页面 {page_num} 访问失败 (尝试 {attempt}/{max_retries}): {e}")
78
+ if attempt < max_retries:
79
+ console.log(f"[dim]{delay} 秒后重试...[/dim]")
80
+ time.sleep(delay)
81
+ else:
82
+ print_error(f"页面 {page_num} 已达最大重试次数,跳过")
83
+ return None
84
+ return None