内容
# NewsPy
使用 Python 实现的 NewsNow 新闻采集和 MCP 服务项目。
## 技术栈
- **包管理**: uv (Rust编写的高性能Python包管理器)
- **MCP服务**: fastmcp v3.2.4 (Model Context Protocol SDK)
- **爬虫**: httpx + BeautifulSoup4/lxml
- **数据库**: SurrealDB (支持嵌入式文件存储和远程服务器)
- **RSS支持**: feedparser-rs
- **Python版本**: 3.12+
## 项目结构
```
newspy/
├── newspy/
│ ├── sources/ # 数据源采集器
│ │ ├── __init__.py # 数据源注册表
│ │ ├── base.py # 基础爬虫类
│ │ ├── ithome.py # IT之家
│ │ ├── baidu.py # 百度热搜
│ │ ├── bilibili.py # B站热搜/热门视频
│ │ ├── github.py # GitHub Trending
│ │ ├── rss_source.py # RSS数据源
│ │ └── ...
│ ├── database/ # 数据库操作
│ │ ├── __init__.py
│ │ ├── cache.py # SurrealDB缓存管理
│ │ └── models.py # 数据模型
│ ├── settings.py # 集中配置文件
│ ├── cli.py # CLI入口点
│ ├── mcp_tool.py # MCP服务器
│ └── cron.py # 定时采集脚本
├── scripts/ # 辅助脚本
│ ├── mcp_client.py # MCP客户端测试
│ └── db_manage.py # 数据库管理
├── pyproject.toml # 项目配置 (支持命令行入口点)
├── uv.lock # 依赖锁定文件
└── CRON.md # 定时任务详细说明
```
## 快速开始
```bash
# 安装依赖
uv sync
# 查看所有可用命令
uv run newspy --help
uv run newspy-mcp --help
uv run newspy-cron --help
```
## 命令行工具
项目提供三个命令行入口点:
### 1. newspy - 测试和数据库管理工具
```bash
# 列出所有数据源
uv run newspy list
# 测试单个数据源
uv run newspy test ithome -v
# 测试所有数据源
uv run newspy test-all
# 随机获取资讯
uv run newspy random -n 10
# 数据库操作
uv run newspy db --list # 列出所有缓存
uv run newspy db -s ithome # 查询指定源缓存
uv run newspy db --clear # 清空数据库
```
### 2. newspy-mcp - MCP服务器
```bash
# 启动MCP服务器 (stdio模式)
uv run newspy-mcp
# MCP工具:
# - get_cached_news: 从数据库缓存读取最新资讯
# - get_latest_news: 获取指定数据源的最新资讯
# - list_all_sources: 列出所有可用数据源
```
### 3. newspy-cron - 定时采集
```bash
# 采集所有数据源
uv run newspy-cron
# 采集指定数据源
uv run newspy-cron -s ithome baidu github
# 设置crontab(每15分钟执行一次)
crontab -e
# 添加:*/15 * * * * cd /path/to/newspy && uv run newspy-cron >> /var/log/newspy-cron.log 2>&1
```
详细说明请查看 [CRON.md](CRON.md)。
## 配置系统
Newspy 使用 `settings.py` 进行集中配置(类似 Django 风格),所有配置项都支持环境变量覆盖。
### 环境变量配置
```bash
# 代理配置(支持 http/https/socks5)
export NEWSPY_PROXY="http://127.0.0.1:7890"
# 或使用系统代理
export HTTP_PROXY="http://127.0.0.1:7890"
export HTTPS_PROXY="http://127.0.0.1:7890"
# 请求超时(秒)
export NEWSPY_TIMEOUT=15
# 数据库连接路径
## 本地文件存储
export NEWSPY_DB_URL="file:///data/newspy"
## websocket服务
export NEWSPY_DB_URL="ws://localhost:8000"
# 禁用特定数据源(逗号分隔)
export NEWSPY_DISABLED="hackernews,github"
# 每个数据源最大新闻条数(0表示不限制)
export NEWSPY_MAX_NEWS=50
# 日志级别
export NEWSPY_LOG_LEVEL=INFO
```
### 主要配置项
| 配置项 | 环境变量 | 默认值 | 说明 |
|--------|----------|--------|------|
| `PROXY` | `NEWSPY_PROXY` | `None` | HTTP/SOCKS5代理 |
| `REQUEST_TIMEOUT` | `NEWSPY_TIMEOUT` | `10` | 请求超时(秒) |
| `DATABASE_URL` | `NEWSPY_DB_URL` | `file://~/.cache/newspy` | 数据库连接 |
| `CACHE_TTL` | `NEWSPY_CACHE_TTL` | `1800000` | 缓存过期时间(毫秒) |
| `CRON_CONCURRENCY` | `NEWSPY_CONCURRENCY` | `4` | 采集并发数 |
| `LOG_LEVEL` | `NEWSPY_LOG_LEVEL` | `INFO` | 日志级别 |
| `DISABLED_SOURCES` | `NEWSPY_DISABLED` | `[]` | 禁用的数据源 |
| `MAX_NEWS_PER_SOURCE` | `NEWSPY_MAX_NEWS` | `0` | 每源最大新闻数 |
## 数据源
项目支持 20+ 个数据源,包括:
### 科技类
- **ithome** - IT之家
- **kr36** - 36氪
- **github** - GitHub Trending
- **juejin** - 掘金
- **solidot** - Solidot
- **devto** - Dev.to
### 新闻类
- **baidu** - 百度热搜
- **toutiao** - 今日头条
- **ifeng** - 凤凰新闻
- **thepaper** - 澎湃新闻
- **cankaoxiaoxi** - 参考消息
- **sputniknewscn** - 俄罗斯卫星通讯社
### 财经类
- **wallstreetcn** - 华尔街见闻
- **gelonghui** - 格隆汇
- **xueqiu** - 雪球
- **jin10** - 金十数据
### 社区类
- **nowcoder** - 牛客网
### 视频类
- **bilibili** - B站热搜/热门视频
- **kuaishou** - 快手
- **douyin** - 抖音
### 其他
- **cls** - 财联社电报
- **ghxi** - GHXI
- **tencent** - 腾讯新闻
- **rss_source** - RSS数据源(支持自定义)
## 数据库
Newspy 使用 SurrealDB 作为数据库:
- **嵌入式模式**: 默认使用文件存储 (`file://~/.cache/newspy`)
- **服务器模式**: 支持连接远程 SurrealDB 服务器
- **数据格式**: JSON 文档存储,支持复杂查询
### 数据库管理
```bash
# 查看数据库状态
uv run newspy db --list
# 查询特定数据源
uv run newspy db -s ithome
# 清空数据库
uv run newspy db --clear
# 或手动删除数据库文件
rm -rf ~/.cache/newspy
```
## 添加新数据源
1. 在 `newspy/sources/` 目录创建新文件
2. 继承 `BaseCrawler` 类并实现 `crawl()` 方法
3. 在 `newspy/sources/__init__.py` 中注册数据源
示例:
```python
# newspy/sources/example.py
from typing import Any
from .base import BaseCrawler, NewsItem
class ExampleCrawler(BaseCrawler):
async def crawl(self) -> list[NewsItem]:
# 实现采集逻辑
items = []
# ... 采集代码 ...
return items
def create_crawler(source_id: str, config: dict[str, Any]) -> BaseCrawler:
return ExampleCrawler(source_id, config)
```
然后在 `__init__.py` 中注册:
```python
from .example import create_crawler as example_factory
def init_all_sources():
register_source("example", example_factory)
# ... 其他数据源
```
## 开发指南
### 安装开发依赖
```bash
uv sync --group dev
```
### 代码风格
```bash
# 使用 ruff 进行代码检查和格式化
uv run ruff check .
uv run ruff format .
```
### 类型检查
```bash
uv run mypy newsy
```
### 测试
```bash
uv run pytest
```
## 故障排查
### 常见问题
1. **采集失败**: 检查网络连接,某些数据源可能需要代理
2. **数据库错误**: 确保没有多个进程同时写入数据库
3. **依赖问题**: 运行 `uv sync` 重新安装依赖
4. **代理问题**: 设置 `Newspy_PROXY` 环境变量
### 日志调试
```bash
# 设置详细日志
export NEWSPY_LOG_LEVEL=DEBUG
# 查看cron日志
tail -f /var/log/newspy-cron.log
```
## 性能优化
- **并发数**: 根据服务器性能调整 `Newspy_CONCURRENCY`(建议4~16)
- **采集频率**: 根据数据源更新频率调整(热榜类5~15分钟,新闻类30~60分钟)
- **数据库**: 默认的 SurrealDB 嵌入式模式适合单进程,高并发场景建议使用 SurrealDB Server
## 许可证
本项目采用 MIT 许可证。