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.
- linkedin_horse-0.1.0/PKG-INFO +222 -0
- linkedin_horse-0.1.0/README.md +195 -0
- linkedin_horse-0.1.0/linkedin_horse/__init__.py +3 -0
- linkedin_horse-0.1.0/linkedin_horse/browser.py +84 -0
- linkedin_horse-0.1.0/linkedin_horse/cli.py +249 -0
- linkedin_horse-0.1.0/linkedin_horse/cookies.py +74 -0
- linkedin_horse-0.1.0/linkedin_horse/export.py +135 -0
- linkedin_horse-0.1.0/linkedin_horse/extractor.py +145 -0
- linkedin_horse-0.1.0/linkedin_horse/output.py +46 -0
- linkedin_horse-0.1.0/linkedin_horse.egg-info/PKG-INFO +222 -0
- linkedin_horse-0.1.0/linkedin_horse.egg-info/SOURCES.txt +15 -0
- linkedin_horse-0.1.0/linkedin_horse.egg-info/dependency_links.txt +1 -0
- linkedin_horse-0.1.0/linkedin_horse.egg-info/entry_points.txt +2 -0
- linkedin_horse-0.1.0/linkedin_horse.egg-info/requires.txt +9 -0
- linkedin_horse-0.1.0/linkedin_horse.egg-info/top_level.txt +1 -0
- linkedin_horse-0.1.0/pyproject.toml +43 -0
- linkedin_horse-0.1.0/setup.cfg +4 -0
|
@@ -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,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
|