|
|
# 暗网采集服务部署笔记
> CentOS + Tor + Privoxy + Flask(python3 直接启动)
## 环境信息
| 项目 | 值 ||------|-----|| 云平台 | 华为云 || 部署主机 | `ocai-node-05` || 公网 IP | `124.243.188.109` | | 内网 IP | `192.168.0.131`(同 VPC 内访问) || 代码目录 | `/opt/crawl/darkweb_api` || 入口文件 | `darkweb_api_3.py` |
| 服务 | 端口 | 说明 ||------|------|------|| Tor (SOCKS5) | `9050` | 暗网隧道;动态采集直连此端口 || Privoxy (HTTP) | `19095` | 静态采集走此代理 || Flask API | `8000` | 采集接口 `/crawl` |
**端口对应关系(三处必须一致):**
| 组件 | 配置文件 | 关键项 | 值 ||------|----------|--------|-----|| Tor | `/etc/tor/torrc` | `SOCKSPort` | `127.0.0.1:9050` || Privoxy | `/etc/privoxy/config` | `listen-address` | `127.0.0.1:19095` || Privoxy | `/etc/privoxy/config` | `forward-socks5t` | `/ 127.0.0.1:9050 .` || API 代码 | `darkweb_api_3.py` | 静态代理 / 动态代理 | `19095` / `9050` |
## API 接口说明
**作用**:接收一个目标 URL(明网或 `.onion` 暗网),由服务器经 Tor 代理抓取页面内容,以 JSON 返回 HTML 源码。调用方无需在本机配置 Tor / 代理。
| 项目 | 说明 ||------|------|| 地址 | `POST http://<IP>:8000/crawl` || Content-Type | `application/json` || 采集模式 | **静态**(默认):`requests` + Privoxy;**动态**:Playwright + Tor,适合搜索页 / JS 渲染页 |
**输入(JSON Body):**
| 参数 | 必填 | 默认值 | 说明 ||------|------|--------|------|| `url` | 是 | — | 要采集的目标地址 || `is_dynamic` | 否 | `false` | `true` 启用动态采集(Playwright) || `headers` | 否 | `{}` | 自定义请求头 || `cookies` | 否 | `{}` | 自定义 Cookie || `referer` | 否 | — | Referer 头 || `static_timeout_s` | 否 | `60` | 静态采集超时(秒) || `dynamic_timeout_ms` | 否 | `90000` | 动态页面加载超时(毫秒) || `wait_selector` | 否 | — | 动态模式下等待的 CSS 选择器 || `wait_selector_timeout_ms` | 否 | `30000` | 选择器等待超时(毫秒) |
**输出(JSON):**
成功(HTTP 200):
```json{ "code": 200, "msg": "success", "mode": "静态", "data": { "status_code": 200, "url": "http://xxx.onion/", "content": "<html>...页面源码...</html>" }}```
失败:
| HTTP 状态码 | `code` | `msg` 示例 ||-------------|--------|------------|| 400 | 400 | `请发送 JSON 格式` / `url 不能为空` || 502 | 502 | `代理连接失败,请检查服务状态` || 504 | 504 | `静态请求超时` / `动态请求超时` || 500 | 500 | `系统异常: ...` |
**Python 调用示例:**
```pythonimport requests
resp = requests.post( "http://124.243.188.109:8000/crawl", json={"url": "http://xxx.onion/", "is_dynamic": True}, timeout=300,)data = resp.json()html = data["data"]["content"] # msg == "success" 时取用```
---
# 快速上手(最常用)
## 关键配置(首次部署必做)
> Privoxy 默认监听 `8118`,必须改成 `19095` 并转发到 Tor `9050`;改完后还要处理文件权限。
### 1. 配置 Tor(`/etc/tor/torrc`)
```bashsudo vim /etc/tor/torrc```
确认存在以下行(没有就加上,有重复端口配置以这条为准):
```SOCKSPort 127.0.0.1:9050```
```bashsudo systemctl restart torsudo netstat -tlnp | grep 9050 # 应看到 tor 监听 9050```
### 2. 配置 Privoxy(`/etc/privoxy/config`)
```bashsudo vim /etc/privoxy/config```
**① 注释掉默认监听端口**(搜索 `listen-address`,把 `8118` 那行注释掉):
```# listen-address 127.0.0.1:8118
# listen-address [::1]:8118
```
**② 新增监听端口**(HTTP 代理,供 API 静态采集使用):
```listen-address 127.0.0.1:19095```
**③ 新增转发规则**(把 HTTP 代理流量转给 Tor SOCKS5,末尾 `.` 不能漏):
```forward-socks5t / 127.0.0.1:9050 .```
**④ 修复权限**(`sudo vim` 改完后面属主会变成 root,Privoxy 会启动失败):
```bashsudo chown -R privoxy:privoxy /etc/privoxy/```
**⑤ 若 SELinux 拦截 19095 端口**(启动失败或端口未监听时):
```bashsudo setenforce 0```
```bashsudo systemctl restart privoxysudo netstat -tlnp | grep 19095 # 应看到 privoxy 监听 19095```
### 3. 确认 API 代码端口一致
`darkweb_api_3.py` 中应与上面配置对应(一般默认已正确,改过 Privoxy 端口时需同步修改):
```pythonSTATIC_PROXY_PORT = "19095" # 对应 Privoxy listen-addressDYNAMIC_PROXY_SERVER = "socks5://127.0.0.1:9050" # 对应 Tor SOCKSPort```
---
## 启动服务
```bash# 1. 启动基础代理(一般已装好,重启即可)
sudo systemctl start torsudo systemctl start privoxy
# 2. 启动 API
cd /opt/crawl/darkweb_apinohup python3 darkweb_api_3.py > ./logs/api_stdout.log 2>&1 &```
## 验证命令
```bash# 服务与端口
sudo systemctl status tor privoxyps -ef | grep darkweb_api_3sudo netstat -tlnp | grep -E '9050|19095|8000'
# Tor 直连
curl --socks5-hostname 127.0.0.1:9050 --max-time 60 http://httpbin.org/ip
# Privoxy 转发
curl -x http://127.0.0.1:19095 --max-time 60 http://httpbin.org/ip
# 暗网连通
curl -x http://127.0.0.1:19095 -L --max-time 120 \ "http://darkzqtmbdeauwq5mzcmgeeuhet42fhfjj4p5wbak3ofx2yqgecoeqyd.onion/"
# API 静态采集
curl -X POST -H "Content-Type: application/json" \ -d '{"url": "http://darkzqtmbdeauwq5mzcmgeeuhet42fhfjj4p5wbak3ofx2yqgecoeqyd.onion/"}' \ http://127.0.0.1:8000/crawl
# API 动态采集
curl -X POST -H "Content-Type: application/json" \ -d '{"url": "http://darkzqtmbdeauwq5mzcmgeeuhet42fhfjj4p5wbak3ofx2yqgecoeqyd.onion/search?q=a", "is_dynamic": true}' \ http://127.0.0.1:8000/crawl```
## 一键体检
```bashecho "=== Tor ===" && curl -s --socks5-hostname 127.0.0.1:9050 --max-time 30 http://httpbin.org/ip && \echo -e "\n=== Privoxy ===" && curl -s -x http://127.0.0.1:19095 --max-time 30 http://httpbin.org/ip && \echo -e "\n=== API ===" && curl -s -X POST -H "Content-Type: application/json" \ -d '{"url":"http://httpbin.org/ip"}' http://127.0.0.1:8000/crawl | head -c 200```
## 启停与排障
```bash# 采集超时?先重启 Tor(最常见修复方式)
sudo systemctl restart torsudo systemctl restart privoxy
# 查看 Tor 是否正常建电路
journalctl -u tor -n 20 --no-pager | grep -iE 'bootstrap|circuit'
# API 进程管理
ps -ef | grep darkweb_api_3kill <PID>cd /opt/crawl/darkweb_api && nohup python3 darkweb_api_3.py > ./logs/api_stdout.log 2>&1 &```
## 外部调用
```bash# 其他机器通过公网 IP 调 API(推荐)
curl -X POST -H "Content-Type: application/json" \ -d '{"url": "http://<onion-url>/"}' \ http://124.243.188.109:8000/crawl
# 同 VPC 内网
curl -X POST -H "Content-Type: application/json" \ -d '{"url": "http://<onion-url>/"}' \ http://192.168.0.131:8000/crawl```
---
# 详细部署说明
## 一、核心架构
```客户端 (Python / Curl / 其他服务器) ↓ HTTP 请求Flask API (:8000) ──静态采集──→ Privoxy (:19095) │ ↓ SOCKS5 └──动态采集 (Playwright) ──────────→ Tor (:9050) ↓ 加密隧道 暗网 (.onion)```
- **Tor**:建立暗网加密隧道,提供 SOCKS5 接口(`9050`)。- **Privoxy**:将 HTTP 代理请求翻译为 SOCKS5 后转发给 Tor。- **Flask API**:对外提供 `/crawl` 接口;静态走 Privoxy,动态由 Playwright 直连 Tor。当前以 `python3` 直接启动。
---
## 二、安装与配置 Tor
Tor 不在 CentOS 默认源中,需先添加 EPEL:
```bashsudo yum install epel-release -ysudo yum install tor -y```
编辑 `/etc/tor/torrc`,确认 SOCKS 监听端口:
```SOCKSPort 127.0.0.1:9050```
```bashsudo systemctl start torsudo systemctl enable torsudo systemctl restart torsudo netstat -tlnp | grep 9050 # 确认 9050 已监听```
---
## 三、安装与配置 Privoxy
```bashsudo yum install privoxy -y```
编辑 `/etc/privoxy/config`,**三项必改**:
| 步骤 | 操作 | 说明 ||------|------|------|| ① | 注释默认 `listen-address ... 8118` | 避免仍监听旧端口 || ② | 新增 `listen-address 127.0.0.1:19095` | HTTP 代理监听端口 || ③ | 新增 `forward-socks5t / 127.0.0.1:9050 .` | 转发到 Tor,末尾 `.` 不能漏 |
完整示例:
```# listen-address 127.0.0.1:8118
# listen-address [::1]:8118
listen-address 127.0.0.1:19095forward-socks5t / 127.0.0.1:9050 .```
改完权限并启动:
```bashsudo chown -R privoxy:privoxy /etc/privoxy/sudo systemctl start privoxysudo systemctl enable privoxysudo systemctl restart privoxysudo systemctl status privoxysudo netstat -tlnp | grep 19095```
---
## 四、常见问题
### 权限错误(Permission Denied)
`sudo vim` 改配置后文件属主变为 `root`,Privoxy 以 `privoxy` 用户运行时会读不到配置:
```bashsudo chown -R privoxy:privoxy /etc/privoxy/ls -l /etc/privoxy/config # 确认属主为 privoxy```
### SELinux 拦截自定义端口
CentOS 默认只允许 Privoxy 监听 `8118`,改用 `19095` 可能被拦截:
```bashsudo setenforce 0 # 临时关闭,验证后可按需配置 SELinux 策略```
### Tor 进程在跑但采集超时
日志出现 `0 circuits open` 或 Privoxy 请求 `127.0.0.1:19095` 超时:
```bashsudo systemctl restart torjournalctl -u tor -f # 观察是否出现 Bootstrapped 100%```
若重启后仍卡在 Bootstrap 5%,检查系统时间(`timedatectl`)和华为云安全组出站规则;仍不通再考虑配置 Tor Bridge。
---
## 五、API 服务部署
### 接口作用
`/crawl` 是暗网采集服务的唯一入口。客户端传入目标 URL,服务端代为完成:
1. **静态模式**(默认):通过 Privoxy → Tor 发 HTTP 请求,返回页面 HTML。2. **动态模式**(`is_dynamic: true`):启动无头浏览器经 Tor 访问,支持 JS 渲染、自动滚动,返回渲染后的 HTML。
适用于:暗网页面采集、搜索结果显示、需登录 Cookie / 自定义请求头的场景。部分站点在代码内置了采集策略,会自动切换动态模式。
### 请求格式
```POST /crawlHost: 124.243.188.109:8000Content-Type: application/json```
```json{ "url": "http://darkzqtmbdeauwq5mzcmgeeuhet42fhfjj4p5wbak3ofx2yqgecoeqyd.onion/search?q=a", "is_dynamic": true, "headers": {"User-Agent": "Mozilla/5.0 ..."}, "cookies": {"session": "xxx"}, "referer": "http://xxx.onion/", "static_timeout_s": 120, "dynamic_timeout_ms": 90000, "wait_selector": "body", "wait_selector_timeout_ms": 30000}```
### 响应格式
**成功:**
```json{ "code": 200, "msg": "success", "mode": "动态", "data": { "status_code": 200, "url": "http://xxx.onion/search?q=a", "content": "<!DOCTYPE html>..." }}```
| 字段 | 说明 ||------|------|| `code` | 业务状态码,200 表示成功 || `msg` | `success` 或错误描述 || `mode` | 实际使用的采集模式:`静态` / `动态` || `data.status_code` | 目标站点 HTTP 状态码 || `data.url` | 请求的原始 URL || `data.content` | 页面 HTML 源码(主要取用字段) |
**失败:**
```json{"code": 504, "msg": "静态请求超时"}```
### 代码目录
```bashcd /opt/crawl/darkweb_apils darkweb_api_3.py```
代码内代理配置(一般无需修改):
- 静态代理:`127.0.0.1:19095`(Privoxy)- 动态代理:`socks5://127.0.0.1:9050`(Tor)
### 启动方式
前台运行(调试用):
```bashcd /opt/crawl/darkweb_apipython3 darkweb_api_3.py```
后台运行(生产常用):
```bashcd /opt/crawl/darkweb_apinohup python3 darkweb_api_3.py > ./logs/api_stdout.log 2>&1 &```
### 调用示例
**curl:**
```bash# 静态采集
curl -X POST -H "Content-Type: application/json" \ -d '{"url": "http://<onion-url>/"}' \ http://127.0.0.1:8000/crawl
# 动态采集
curl -X POST -H "Content-Type: application/json" \ -d '{"url": "http://<onion-url>/", "is_dynamic": true}' \ http://127.0.0.1:8000/crawl```
**Python:**
```pythonimport requests
api_url = "http://124.243.188.109:8000/crawl"payload = { "url": "http://<onion-url>/", "is_dynamic": True,}
resp = requests.post(api_url, json=payload, timeout=300)result = resp.json()
if result.get("msg") == "success": html = result["data"]["content"]else: print("失败:", result.get("msg"))```
**其他服务器(公网):**
```bashcurl -X POST -H "Content-Type: application/json" \ -d '{"url": "http://<onion-url>/"}' \ http://124.243.188.109:8000/crawl```
---
## 六、运维速查
```bash# 服务状态
sudo systemctl status tor privoxyps -ef | grep darkweb_api_3
# 端口占用
sudo netstat -tlnp | grep -E '9050|19095|8000'
# 日志
tail -f /opt/crawl/darkweb_api/logs/api_stdout.logtail -f /opt/crawl/darkweb_api/logs/*.logsudo journalctl -u tor -fsudo journalctl -u privoxy -f```
|