{"owner":"jhao104","repo":"proxy_pool","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["CLAUDE.md"],"files":{"CLAUDE.md":"# CLAUDE.md\n\n本文件为 Claude Code (claude.ai/code) 在本仓库中工作时提供指导。\n\n## 技术栈\nPython (3.8–3.11)、Flask (API)、Redis/SSDB (存储)、APScheduler (调度)。依赖版本固定记录在 `requirements.txt` 中。\n\n## 常用命令\n- 安装依赖：`pip install -r requirements.txt`\n- 运行代理爬取/验证调度器：`python proxyPool.py schedule`\n- 运行 API 服务器：`python proxyPool.py server`\n- 查看启用的代理源：`python proxyPool.py fetcher`\n- 运行单元测试：`pytest tests/unit/`\n- 运行 API 测试：`pytest tests/api/`\n- 运行集成测试（需真实 Redis）：`pytest tests/integration/ -m integration`\n- 运行全部测试：`pytest`\n- 查看覆盖率：`pytest --cov=. --cov-report=term-missing`\n\n## 测试\n\n### 目录结构\n```\ntests/\n├── conftest.py              # 共享 fixtures（app、client、fake_redis、proxy_obj、reset_singleton）\n├── unit/                    # 纯逻辑，零外部依赖\n│   ├── test_proxy.py        # Proxy 类：构造、序列化、setter、add_source\n│   ├── test_db_client.py    # DbClient.parseDbConn URI 解析\n│   ├── test_config.py       # ConfigHandler 环境变量覆盖\n│   ├── test_validator.py    # formatValidator 正则匹配\n│   ├── test_base_fetcher.py # BaseFetcher 基类解析方法\n│   └── test_fetcher_sources.py # 各代理源 fetcher yield 逻辑\n├── api/                     # Flask 测试客户端，mock ProxyHandler\n│   └── test_proxy_api.py    # /get /pop /all /count /delete 全路由\n└── integration/             # 需要真实 Redis，标记 @pytest.mark.integration\n    ├── test_redis_client.py # RedisClient 完整 CRUD\n    └── test_ssdb_client.py  # SsdbClient 完整 CRUD\n```\n\n### 测试分层\n- **unit/**：不依赖外部服务，用 `unittest.mock` 或 `fakeredis` 模拟，CI 必跑\n- **api/**：使用 Flask `app.test_client()`，mock 掉 `ProxyHandler`，不依赖数据库\n- **integration/**：需要真实 Redis，通过 `@pytest.mark.integration` 标记，按需执行\n\n### 测试依赖\n`pytest`、`pytest-cov`、`fakeredis`（纯 Python Redis 模拟，无需真实服务）\n\n### 关键约定\n- 测试函数命名：`test_` 前缀 + 下划线命名（`test_get_with_https`）\n- 每个测试前自动重置 `Singleton._inst`，避免单例泄漏\n- 集成测试与单元测试共存：单元测试用 fakeredis 跑，集成测试标记后按需执行\n\n## 高层架构\n免费代理池项目，爬取公开代理源、验证代理可用性、持久化存储到 Redis/SSDB，并通过 Flask RESTful API 提供代理服务。\n\n### 核心组件\n- **爬取器** (`fetcher/`)：插件架构。`baseFetcher.py` 定义 `BaseFetcher` 基类（提供 `parseProxiesFromText`/`yieldUniqueProxies` 共享方法，约定 `name`/`url`/`enabled` 属性和 `fetch()` 方法）。每个代理源在 `sources/` 目录下独立文件，继承 `BaseFetcher`。调度器自动扫描目录加载 `enabled=True` 的源。`setting.py` 的 `PROXY_FETCHER_EXCLUDE` 黑名单可临时禁用指定源。\n- **数据库层** (`db/`)：抽象 `dbClient` 接口，包含 Redis (`redisClient.py`) 和 SSDB (`ssdbClient.py`) 两种实现。通过 `setting.py` 中的 `DB_CONN` 配置连接（格式：`redis://:pwd@ip:port/db` 或 `ssdb://:pwd@ip:port`）。\n- **调度器** (`helper/scheduler.py`)：基于 APScheduler 的定时任务，驱动爬取器运行并触发验证。时区通过 `setting.py` 中的 `TIMEZONE` 配置。\n- **验证器** (`helper/validator.py`)：使用 `HTTP_URL` (http://httpbin.org) 和 `HTTPS_URL` (https://www.qq.com) 测试代理，超时时间由 `VERIFY_TIMEOUT` 指定（默认 10 秒）。超过 `MAX_FAIL_COUNT` 的代理会被移除。当代理池数量低于 `POOL_SIZE_MIN`（默认 20）时触发重新爬取。\n- **API** (`api/proxyApi.py`)：Flask 接口，包含以下端点：\n  - `/get`：随机获取一个代理（`?type=https` 可筛选 HTTPS 代理）\n  - `/pop`：获取并删除一个代理\n  - `/all`：列出所有代理\n  - `/count`：代理数量统计\n  - `/delete`：通过 `?proxy=host:port` 删除指定代理\n  - 服务运行在 `HOST:PORT`（默认 `0.0.0.0:5010`），配置来自 `setting.py`。\n- **命令行入口** (`proxyPool.py`)：基于 click 的命令行工具，包含 `schedule` 和 `server` 两个子命令。\n\n### 扩展代理源\n1. 在 `fetcher/sources/` 目录下新建 `.py` 文件，继承 `BaseFetcher`，声明 `name`/`url`/`enabled` 属性，实现 `fetch()` 方法 yield 出 `host:port` 字符串。\n2. 调度器下一轮采集自动发现并启用，无需修改配置。可用 `python proxyPool.py fetcher` 查看启用列表。\n\n## 关键配置\n所有运行时配置均在 `setting.py` 中：\n- `HOST`/`PORT`：API 绑定的地址和端口\n- `DB_CONN`：数据库连接字符串\n- `PROXY_FETCHER_EXCLUDE`：爬取器黑名单（自动扫描 `enabled=True` 的源，排除黑名单中的）\n- `HTTP_URL`/`HTTPS_URL`：验证目标 URL\n- `VERIFY_TIMEOUT`：验证超时时间（默认 10 秒）\n- `MAX_FAIL_COUNT`：代理被移除前允许的最大失败次数\n- `POOL_SIZE_MIN`：触发重新爬取的最小代理池数量阈值\n- `PROXY_REGION`：是否启用代理地区属性（默认 `True`）\n- `TIMEZONE`：调度器时区（默认 `Asia/Shanghai`）\n\n## 代码风格与命名规范\n- **文件头**：每个 `.py` 文件必须包含以下标准头部：\n  ```python\n  # -*- coding: utf-8 -*-\n  \"\"\"\n  -------------------------------------------------\n     File Name：     fileName.py\n     Description :   文件功能描述\n     Author :        JHao\n     date：          yyyy/mm/dd\n  -------------------------------------------------\n     Change Activity:\n                     yyyy/mm/dd: 修改内容简述 (修改时添加此行)\n  -------------------------------------------------\n  \"\"\"\n  __author__ = 'JHao'\n  ```\n- **缩进**：4 个空格（Python 标准）\n- **文件命名**：驼峰命名，如 `proxyFetcher.py`、`dbClient.py`、`redisClient.py`、`webRequest.py`\n- **类命名**：帕斯卡命名，如 `ProxyFetcher`、`RedisClient`、`SsdbClient`、`ProxyValidator`\n- **方法命名**：混合风格——数据库/爬取器方法使用驼峰命名（`getAll`、`getCount`、`changeTable`、`parseProxiesFromText`），属性和辅助方法使用下划线命名（`user_agent`、`fail_count`、`check_count`）\n- **爬取器文件**：小写命名（如 `zdaye.py`、`kuaidaili.py`），类名 PascalCase（如 `ZdayeFetcher`、`KuaidailiFetcher`）\n- **常量**（在 `setting.py` 中）：大写下划线命名（`DB_CONN`、`PROXY_FETCHER_EXCLUDE`、`HTTP_URL`、`MAX_FAIL_COUNT`）\n- **变量**：下划线命名（`proxy_obj`、`proxy_str`、`https`）\n- **注释/文档字符串**：源文件头部和行内注释通常使用中文（普通话）\n- **单例模式**：使用自定义 `Singleton` 元类（`util/singleton.py`）结合 `six.withMetaclass` 实现\n\n## 注意事项\n- 运行测试前需先安装测试依赖：`pip install pytest pytest-cov fakeredis`\n- 单元测试和 API 测试不依赖外部服务，可直接运行；集成测试需启动 Redis\n"}}