feat: 投资资讯日报查询页 + 文档更新 + 拉取服务器最新内容

- 新增 charts/news_reports.php 报告查询导航页(列表+详情一体,fetch API 渲染)
- 新增 js/newsReports.js:AI 摘要/新闻联播/财经新闻/公告调研/数据总览固定模块,stats 归一化兼容多种格式
- index-2.php 研究报告卡片改为导航链接,移除 PHP 目录下拉框
- 更新 AGENTS.md/CLAUDE.md(路径、页面清单、数据模式等核实修正)
- 同步服务器拉取的文档:quant 使用手册、podcast-docs
- 生成 continuation.md 会话检查点
This commit is contained in:
2026-08-05 20:28:57 +08:00
parent 60fb1b95e1
commit 8ea9b48a9a
10 changed files with 1717 additions and 128 deletions
+390
View File
@@ -0,0 +1,390 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IntlNews 操作手册</title>
<style>
:root {
--bg: #1a1a2e;
--card: #16213e;
--accent: #0f3460;
--green: #00c853;
--yellow: #ffd600;
--red: #ff1744;
--text: #e0e0e0;
--muted: #8892b0;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, 'Segoe UI', system-ui, sans-serif; background: var(--bg); color: var(--text); line-height: 1.7; padding: 20px; }
.container { max-width: 960px; margin: 0 auto; }
h1 { font-size: 2em; margin: 1em 0 0.3em; color: #fff; border-bottom: 2px solid var(--accent); padding-bottom: 0.3em; }
h2 { font-size: 1.4em; margin: 1.5em 0 0.5em; color: #64ffda; }
h3 { font-size: 1.1em; margin: 1em 0 0.3em; color: #80cbc4; }
p, li { margin: 0.4em 0; }
code { background: #0d2137; padding: 2px 6px; border-radius: 3px; font-size: 0.9em; color: #a8d8ea; }
pre { background: #0d2137; padding: 12px 16px; border-radius: 6px; overflow-x: auto; border: 1px solid #1a3a5c; margin: 0.8em 0; }
table { width: 100%; border-collapse: collapse; margin: 1em 0; }
th, td { padding: 8px 12px; text-align: left; border-bottom: 1px solid #1a3a5c; }
th { background: var(--accent); color: #fff; font-weight: 600; }
tr:hover { background: #1a2a4a; }
.tag { display: inline-block; padding: 1px 8px; border-radius: 10px; font-size: 0.8em; font-weight: 600; }
.tag-ok { background: #1b5e20; color: #a5d6a7; }
.tag-warn { background: #e65100; color: #ffcc80; }
.tag-err { background: #b71c1c; color: #ef9a9a; }
.tag-new { background: #0d47a1; color: #90caf9; }
.info-box { background: #0d2137; border-left: 4px solid #64ffda; padding: 12px 16px; border-radius: 0 6px 6px 0; margin: 1em 0; }
.warn-box { background: #1e1a0d; border-left: 4px solid #ffd600; padding: 12px 16px; border-radius: 0 6px 6px 0; margin: 1em 0; }
.cmd { display: block; padding: 4px 0; font-family: 'SF Mono', 'Fira Code', monospace; font-size: 0.9em; }
.cmd::before { content: '$ '; color: #64ffda; }
.footer { margin-top: 3em; padding-top: 1em; border-top: 1px solid #1a3a5c; color: var(--muted); font-size: 0.85em; text-align: center; }
</style>
</head>
<body>
<div class="container">
<h1>📰 IntlNews — 国际财经新闻 Deep Research</h1>
<p style="color:var(--muted);">最后更新:2026-07-23 | 运行服务器:pi@192.168.1.160</p>
<div class="info-box">
<strong>项目定位:</strong>面向国际财经新闻的私有化 Deep Research 平台。抓取英文财经新闻 → 英译中 → 事件抽取 → 向量入库 → MCP Agent 深度研究。
</div>
<!-- ==================== 一、架构 ==================== -->
<h1>一、系统架构</h1>
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 400 250'%3E%3Crect width='400' height='250' fill='%231a1a2e'/%3E%3Ctext x='20' y='30' fill='%2364ffda' font-size='14'%3EPi 4 (8GB) — 全链路独立运行%3C/text%3E%3C/text%3E%3C/svg%3E" alt="Arch" style="display:none;">
<pre>
┌──────────────────────────────────────────────────────┐
│ Pi 4 (8GB) │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ M1 抓取 │──▶│ M2 正文 │──▶│ M3 三层去重 │ │
│ │ headful │ │ trafilat.│ │ URL/Content/SimH │ │
│ │ Playwright│ │ │ │ │ │
│ │ + HTTP 代 │ │ │ │ │ │
│ │ 理(海外) │ │ │ │ │ │
│ └──────────┘ └──────────┘ └────────┬─────────┘ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ M6 Qdrant│◀──│ M5 向量 │◀──│ M4 翻译+事件抽取 │ │
│ │ 入库 │ │ DashScope│ │ DeepSeek v4 │ │
│ └────┬─────┘ └──────────┘ └──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ M7 日报 │──▶│ doorcome │ │
│ │ 生成 │ │ 上传 │ │
│ └──────────┘ └──────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────┐ │
│ │ M8 MCP 服务(Cherry Studio / Claude Code │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
</pre>
<div class="info-box">
<strong>关键变更:</strong>海外服务器已于 2026-07-14 停用。全链路在 Pi 独立运行,通过 <code>Privoxy → SOCKS5 (ss-local)</code> 代理访问海外新闻网站。<br>
<strong>反爬策略:</strong>2026-07-23 更新 — 启用 Crawl4AI <code>magic</code> 全自动反检测 + Playwright <code>stealth</code> 模式。investing.com 改用 Google News RSS 代理。
</div>
<!-- ==================== 二、部署 ==================== -->
<h1>二、部署指南</h1>
<h2>2.1 环境要求</h2>
<ul>
<li>Python 3.11 + uv</li>
<li>Xvfbheadful Playwright 虚拟显示器)</li>
<li>Shadowsocks-libev + v2ray-pluginSOCKS5 代理)</li>
<li>PrivoxyHTTP → SOCKS5 转换)</li>
</ul>
<h2>2.2 初始化安装</h2>
<pre>
# 1. 克隆仓库
git clone ssh://gitea:2222/simon/intl_news /home/pi/intlnews
cd /home/pi/intlnews
# 2. Python 环境
uv sync
# 3. 环境变量
cp .env.example .env
# 填入: DEEPSEEK_API_KEY, DASHSCOPE_API_KEY, QDRANT_URL
# 4. Xvfb 虚拟显示器
sudo apt install xvfb
Xvfb :99 -screen 0 1280x1024x24 -ac +extension RANDR &amp;
# 5. Shadowsocks + Privoxy(海外代理)
sudo apt install shadowsocks-libev privoxy
# 配置 /etc/shadowsocks-libev/config.json
# 配置 /etc/privoxy/config: forward-socks5t / 127.0.0.1:1088 .
sudo systemctl enable --now shadowsocks-libev-local
sudo systemctl enable --now privoxy
</pre>
<h2>2.3 定时调度(crontab</h2>
<pre>
# crontab -e 添加:
0 6 * * * cd /home/pi/intlnews && bash scripts/domestic_full.sh >> logs/full.log 2>&1
0 12 * * * cd /home/pi/intlnews && bash scripts/domestic_full.sh >> logs/full.log 2>&1
0 18 * * * cd /home/pi/intlnews && bash scripts/domestic_full.sh >> logs/full.log 2>&1
0 22 * * * cd /home/pi/intlnews && bash scripts/domestic_full.sh >> logs/full.log 2>&1
@reboot Xvfb :99 -screen 0 1280x1024x24 -ac +extension RANDR &amp;
</pre>
<!-- ==================== 三、操作命令 ==================== -->
<h1>三、操作命令</h1>
<h2>3.1 全流程运行</h2>
<pre>
# 一键全流程(M1→M6→日报)
bash scripts/domestic_full.sh
</pre>
<h2>3.2 M1 抓取</h2>
<pre>
# 抓取全部 13 个源
bash scripts/domestic_crawl_8g.sh
# 单源调试
bash scripts/domestic_crawl_8g.sh investing
bash scripts/domestic_crawl_8g.sh investinglive
bash scripts/domestic_crawl_8g.sh reuters
</pre>
<h2>3.3 M2→M6 管道</h2>
<pre>
# 完整管道(需要先有 raw 数据)
bash scripts/pipeline.sh
# 或逐步执行:
PYTHONPATH=. .venv/bin/python3 -c "from scheduler.pipeline import run_pipeline; run_pipeline('$(date +%Y%m%d)')"
</pre>
<h2>3.4 日报</h2>
<pre>
# 生成当日日报
PYTHONPATH=. .venv/bin/python3 -c "from scheduler.reporter import generate_report; print(generate_report())"
# 查看日报列表
ls -lt data/reports/
</pre>
<h2>3.5 日志查看</h2>
<pre>
# 全量日志
tail -100 logs/full.log
# 筛选指定源
grep 'investing\|investinglive' logs/full.log | tail -20
</pre>
<!-- ==================== 四、新闻源状态 ==================== -->
<h1>四、新闻源状态</h1>
<table>
<tr><th></th><th>ID</th><th>策略</th><th>日产量</th><th>状态</th></tr>
<tr>
<td>Reuters</td><td><code>reuters</code></td><td>Google News RSS</td><td>~30 篇</td>
<td><span class="tag tag-warn">摘要</span> DataDome</td>
</tr>
<tr>
<td>CNBC</td><td><code>cnbc</code></td><td>CNBC RSS</td><td>~25 篇</td>
<td><span class="tag tag-ok">正常</span></td>
</tr>
<tr>
<td>MarketWatch</td><td><code>marketwatch</code></td><td>RSS + stealth</td><td>~25 篇</td>
<td><span class="tag tag-ok">正常</span></td>
</tr>
<tr>
<td>Financial Times</td><td><code>ft</code></td><td>FT RSS</td><td>~20 篇</td>
<td><span class="tag tag-warn">摘要</span> 付费墙</td>
</tr>
<tr>
<td>Yahoo Finance</td><td><code>yahoo_finance</code></td><td>Yahoo RSS</td><td>~30 篇</td>
<td><span class="tag tag-ok">正常</span></td>
</tr>
<tr>
<td>Investing.com</td><td><code>investing</code></td><td><strong>Google News RSS</strong> + stealth</td><td>25 篇</td>
<td><span class="tag tag-new">已修复</span> RSS 代理</td>
</tr>
<tr>
<td>Seeking Alpha</td><td><code>seekingalpha</code></td><td>RSS + stealth</td><td>~20 篇</td>
<td><span class="tag tag-ok">正常</span></td>
</tr>
<tr>
<td>Barron's</td><td><code>barrons</code></td><td>Dow Jones RSS + stealth</td><td>~20 篇</td>
<td><span class="tag tag-ok">正常</span></td>
</tr>
<tr>
<td>WSJ</td><td><code>wsj</code></td><td>Dow Jones RSS + stealth</td><td>~20 篇</td>
<td><span class="tag tag-ok">正常</span></td>
</tr>
<tr>
<td>Economist</td><td><code>economist</code></td><td>RSS + stealth</td><td>~15 篇</td>
<td><span class="tag tag-ok">正常</span></td>
</tr>
<tr>
<td style="background:#0d47a1;">InvestingLive</td><td><code>investinglive</code></td><td><strong>RSS(全文)</strong></td><td><strong>25 篇</strong></td>
<td><span class="tag tag-new">2026-07-23 新增</span></td>
</tr>
<tr>
<td>ZeroHedge</td><td><code>zerohedge</code></td><td>FeedBurner RSS</td><td>~15 篇</td>
<td><span class="tag tag-ok">正常</span></td>
</tr>
<tr style="color:var(--muted); text-decoration:line-through;">
<td>ForexLive</td><td><del><code>forexlive</code></del></td><td></td><td></td>
<td><span class="tag tag-err">已移除</span> 301→investinglive</td>
</tr>
</table>
<div class="warn-box">
<strong>⚠️ 注意:</strong>RSS 摘要源的全文依赖 headful Playwright 回退抓取,成功率取决于代理线路质量。investing.com 因 Cloudflare 反爬,全文抓取间歇性失败。
</div>
<!-- ==================== 五、数据存储 ==================== -->
<h1>五、数据存储</h1>
<pre>
/home/pi/intlnews/
├── data/
│ ├── raw/{source_id}/{yyyymmdd}/ M1 原始抓取(.html + .md + index.jsonl
│ ├── processed/{source_id}/ M2 正文提取结果
│ ├── dedup/ M3 去重指纹库(SQLite
│ ├── translations/{yyyymmdd}/ M4 翻译+事件抽取(JSONL
│ ├── embeddings/{yyyymmdd}/ M5 向量文件(JSONL
│ ├── reports/ M7 日报(HTML
│ └── vectorstore/ M6 Qdrant 本地数据
├── configs/
│ ├── sources.yaml 新闻源定义(13 个源)
│ ├── system.yaml 系统参数
│ └── profiles/8g_headful.yaml Pi 抓取配置
├── logs/full.log 运行日志
└── prompts/ LLM Prompt 模板
</pre>
<!-- ==================== 六、MCP 服务 ==================== -->
<h1>六、MCP 服务</h1>
<p>M8 模块提供 MCPModel Context Protocol)服务,供 Cherry Studio / Claude Code / Cursor 等客户端接入。</p>
<h2>6.1 启动</h2>
<pre>
cd /home/pi/intlnews
PYTHONPATH=. .venv/bin/python3 -m mcp_server.server
</pre>
<h2>6.2 可用工具</h2>
<table>
<tr><th>Tool</th><th>参数</th><th>功能</th></tr>
<tr><td><code>en_news_search</code></td><td>query, top_k</td><td>语义搜索知识库</td></tr>
<tr><td><code>en_news_filter</code></td><td>source_id, date, sentiment</td><td>按条件筛选事件</td></tr>
<tr><td><code>en_news_trending</code></td><td>days</td><td>获取近期热点</td></tr>
<tr><td><code>en_news_report</code></td><td></td><td>获取最新日报</td></tr>
<tr><td><code>en_news_daily_brief</code></td><td></td><td>一键生成简报</td></tr>
</table>
<!-- ==================== 七、配置参考 ==================== -->
<h1>七、配置参考</h1>
<h2>7.1 环境变量(.env</h2>
<table>
<tr><th>变量</th><th>用途</th></tr>
<tr><td><code>DEEPSEEK_API_KEY</code></td><td>DeepSeek LLM(翻译+事件抽取)</td></tr>
<tr><td><code>DASHSCOPE_API_KEY</code></td><td>DashScope Embedding(向量生成)</td></tr>
<tr><td><code>QDRANT_URL</code></td><td>Qdrant 服务地址</td></tr>
</table>
<h2>7.2 新闻源配置(sources.yaml</h2>
<p>每个源包含:id, name, homepage, rss_url, article_url_pattern, anti_bot_mode 等。</p>
<p>新增源时参考现有格式,启用/禁用通过 <code>enabled: true/false</code></p>
<h2>7.3 Profile 配置</h2>
<p>Pi 服务器使用 <code>8g_headful</code> profile(环境变量 <code>EN_NEWS_PROFILE</code>),通过 Privoxy HTTP 代理访问海外网站。</p>
<ul>
<li><code>proxy.enabled: true</code> — 启用 HTTP 代理</li>
<li><code>crawler.headful: true</code> — 有头浏览器 + Xvfb</li>
<li><code>crawler.magic: true</code> — Crawl4AI 全自动反检测</li>
<li><code>crawler.enable_stealth: true</code> — Playwright stealth</li>
</ul>
<!-- ==================== 八、排障 ==================== -->
<h1>八、常见排障</h1>
<table>
<tr><th style="width:200px;">现象</th><th>排查步骤</th></tr>
<tr>
<td>抓取 0 篇</td>
<td>
1. 检查 <code>logs/full.log</code> 看 RSS/Web 错误<br>
2. <code>bash scripts/domestic_crawl_8g.sh &lt;source_id&gt;</code> 单源测试<br>
3. 检查代理是否正常:<code>curl -I --proxy 127.0.0.1:3128 https://example.com</code>
</td>
</tr>
<tr>
<td>RSS 超时</td>
<td>
1. 确认 Shadowsocks 和 Privoxy 在运行<br>
2. <code>systemctl status shadowsocks-libev-local privoxy</code><br>
3. 环境变量 <code>HTTP_PROXY</code> 是否设置
</td>
</tr>
<tr>
<td>Cloudflare 拦截</td>
<td>
1. 已启用 <code>magic</code> + <code>stealth</code> 自动反检测<br>
2. 仍失败则需更换代理 IP(数据中心 IP 被标记)<br>
3. 改用 Google News RSS 代理(已为 investing/reuters 启用)
</td>
</tr>
<tr>
<td>日报无数据</td>
<td>
1. 检查 <code>data/translations/{date}/</code> 是否有 JSONL<br>
2. 检查 <code>data/embeddings/{date}/</code> 是否有向量
</td>
</tr>
<tr>
<td>MCP 连接失败</td>
<td>
1. 确认 MCP 服务进程在运行<br>
2. 检查端口监听:<code>ss -tlnp | grep 8080</code>
</td>
</tr>
</table>
<!-- ==================== 九、变更记录 ==================== -->
<h1>九、变更记录</h1>
<table>
<tr><th>日期</th><th>变更</th></tr>
<tr>
<td>2026-07-23</td>
<td>
<strong>反爬策略增强:</strong><br>
- crawler.py: magic/stealth/--disable-webrtc/remove_consent_popups<br>
- rss_crawler.py: httpx 代理支持<br>
- investing.com: Google News RSS 代理(绕过 Cloudflare<br>
- <strong>forexlive → investinglive 迁移</strong>(域名已 301 重定向)
</td>
</tr>
<tr>
<td>2026-07-14</td>
<td>
- 海外服务器停用,Pi 全链路独立运行<br>
- 8g_headful profile 新增(headful + HTTP 代理)<br>
- Shadowsocks + Privoxy 部署
</td>
</tr>
</table>
<div class="footer">
IntlNews — 国际财经新闻私有化 Deep Research 平台<br>
运行于 pi@192.168.1.160 | 调度 06:00 / 12:00 / 18:00 / 22:00
</div>
</div>
</body>
</html>
+254
View File
@@ -0,0 +1,254 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>A 股 Deep Research 用户手册 v1.1</title>
<style>
:root { --bg: #f8f9fa; --card: #fff; --text: #212529; --muted: #6c757d;
--accent: #2563eb; --border: #dee2e6; --code-bg: #f1f3f5; --radius: 8px; }
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; background: var(--bg); color: var(--text); line-height: 1.75; padding-bottom: 4rem; }
.container { max-width: 900px; margin: 0 auto; padding: 1.5rem; }
header { background: linear-gradient(135deg, #1e293b, #334155); color: #fff; padding: 3rem 0 2rem; text-align: center; }
header h1 { font-size: 2rem; }
header p { color: #94a3b8; margin-top: .5rem; }
nav { background: var(--card); border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 10; padding: .75rem 0; }
nav a { color: var(--accent); text-decoration: none; margin-right: 1rem; font-size: .9rem; }
h2 { font-size: 1.5rem; margin: 2.5rem 0 1rem; padding-bottom: .5rem; border-bottom: 2px solid var(--accent); }
h3 { font-size: 1.2rem; margin: 1.8rem 0 .8rem; color: #1e293b; }
h4 { font-size: 1rem; margin: 1.2rem 0 .5rem; }
p { margin: .6rem 0; }
a { color: var(--accent); }
code { background: var(--code-bg); padding: .15em .4em; border-radius: 4px; font-family: "SF Mono", "Fira Code", monospace; font-size: .88em; }
pre { background: #1e293b; color: #e2e8f0; padding: 1rem 1.2rem; border-radius: var(--radius); overflow-x: auto; font-size: .85em; line-height: 1.6; margin: .8rem 0; }
pre code { background: none; padding: 0; color: inherit; }
table { width: 100%; border-collapse: collapse; margin: 1rem 0; font-size: .93em; }
th, td { border: 1px solid var(--border); padding: .5rem .7rem; text-align: left; }
th { background: #f1f5f9; font-weight: 600; }
tr:nth-child(even) { background: #fafbfc; }
ul, ol { padding-left: 1.5rem; margin: .6rem 0; }
li { margin: .25rem 0; }
.card { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem 1.5rem; margin: 1rem 0; }
.badge-ok { background: #d1fae5; color: #065f46; display: inline-block; padding: .1em .5em; border-radius: 10px; font-size: .8em; font-weight: 600; }
.badge-warn { background: #fef3c7; color: #92400e; display: inline-block; padding: .1em .5em; border-radius: 10px; font-size: .8em; }
.badge-err { background: #fee2e2; color: #991b1b; display: inline-block; padding: .1em .5em; border-radius: 10px; font-size: .8em; }
footer { text-align: center; color: var(--muted); font-size: .85em; margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--border); }
@media (max-width: 640px) { .container { padding: .8rem; } header h1 { font-size: 1.5rem; } }
</style>
</head>
<body>
<header><div class="container"><h1>A 股 Deep Research 私有投研平台</h1><p>用户手册 v1.1 · 2026-06-17</p></div></header>
<nav><div class="container">
<a href="#概述">概述</a> <a href="#快速开始">快速开始</a> <a href="#cli">CLI 速查</a>
<a href="#全链路">全链路</a> <a href="#站点管理">站点管理</a> <a href="#检索">检索</a>
<a href="#定时任务">定时任务</a> <a href="#mcp">MCP</a> <a href="#投研">投研</a> <a href="#附录">附录</a>
</div></nav>
<main class="container">
<h2 id="概述">1. 项目概述</h2>
<p><strong>A 股 Deep Research</strong> 是私有化投研平台,自动完成财经新闻抓取 → 正文提取 → 事件抽取 → 向量化 → 语义检索,通过 MCP 协议接入 Cherry Studio / Claude Code,实现「自然语言提问 → 结构化研究报告」。</p>
<p><strong>技术栈</strong>: Python 3.11 · Crawl4AI · GNE · DeepSeek/Qwen · DashScope · Qdrant · APScheduler · MCP</p>
<p><strong>部署</strong>: 树莓派 5 (ARM64) <code>/home/pi/news/</code></p>
<h2 id="快速开始">2. 快速开始</h2>
<h3>2.1 安装</h3>
<pre><code>cd /home/pi/news
uv sync
cp .env.example .env
# 编辑 .env, 填入 DEEPSEEK_API_KEY 和 DASHSCOPE_API_KEY
uv run python -m playwright install chromium # 仅 M1 抓取需要</code></pre>
<h3>2.2 验证</h3>
<pre><code>uv run pytest -m "not integration" # 应显示 186 passed</code></pre>
<h2 id="cli">3. 统一 CLI 速查</h2>
<p>所有操作通过 <code>a-share</code> 命令完成。</p>
<table>
<tr><th>命令</th><th>功能</th><th>常用参数</th></tr>
<tr><td><code>a-share crawl</code></td><td>M1 抓取新闻</td><td><code>--source cls</code></td></tr>
<tr><td><code>a-share extract</code></td><td>M2 正文提取</td><td><code>--date 20260616</code></td></tr>
<tr><td><code>a-share dedup</code></td><td>M3 三层去重</td><td><code>--date 20260616 --reset</code></td></tr>
<tr><td><code>a-share events</code></td><td>M4 LLM 事件抽取</td><td><code>--provider qwen --limit 5</code></td></tr>
<tr><td><code>a-share embed</code></td><td>M5 向量化</td><td><code>--model text-embedding-v3</code></td></tr>
<tr><td><code>a-share ingest</code></td><td>M6 Qdrant 入库</td><td><code>--date 20260616 --recreate</code></td></tr>
<tr><td><code>a-share pipeline</code></td><td>全链路 (M1→M6)</td><td><code>--once --report</code></td></tr>
<tr><td><code>a-share discover</code></td><td>分析站点, 生成配置</td><td><code>--name 中文名 --add --extra URL</code></td></tr>
<tr><td><code>a-share add-entry</code></td><td>追加入口到已有源</td><td><code>source_id url1 url2 ...</code></td></tr>
<tr><td><code>a-share report</code></td><td>生成/上传日报</td><td><code>--date 20260616 --no-upload</code></td></tr>
<tr><td><code>a-share search</code></td><td>终端检索知识库</td><td><code>--source --stock --sentiment --top</code></td></tr>
<tr><td><code>a-share status</code></td><td>数据总览</td><td>无参数</td></tr>
</table>
<h2 id="全链路">4. 全链路一键运行</h2>
<pre><code>uv run a-share pipeline --once # 一次跑通 M1→M6
uv run a-share pipeline --once --report # 末尾自动生成日报并上传</code></pre>
<p>耗时约 4-5 分钟 (100 篇): crawler ~3min / extractor ~24s / dedup ~2s / llm ~45s / embedding ~10s / qdrant ~4s</p>
<p>只执行部分步骤: <code>uv run a-share pipeline --once --steps crawler,llm</code></p>
<p><strong>产物路径</strong>: <code>data/raw/</code> (M1) → <code>data/processed/</code> (M2) → <code>data/deduped/</code> (M3) → <code>data/events/</code> (M4) → <code>data/embeddings/</code> (M5) → <code>data/qdrant_storage/</code> (M6)</p>
<h2 id="站点管理">5. 新闻源管理</h2>
<h3>5.1 查看已有源</h3>
<p>配置文件: <code>configs/sources.yaml</code>。内置财联社 / 东方财富 / 新浪财经 / 证券时报 / 第一财经。</p>
<h3>5.2 新增站点 (一条命令)</h3>
<pre><code># 自动分析 + 写入 sources.yaml
uv run a-share discover https://example.com/news/ --name 中文名 --add
# 仅预览
uv run a-share discover https://example.com/news/</code></pre>
<p>自动完成: JS 抓取 → 链接提取 → 导航过滤 → 模式聚类 → 正则生成 → yaml 输出。写入时自动空行分隔、序号递增、<code># ---- N. 名称 ----</code> 注释头。</p>
<h3>5.3 同站多频道</h3>
<pre><code># 一次性分析多入口
uv run a-share discover https://example.com/news/global \
--extra https://example.com/news/china \
--extra https://example.com/news/tech \
--name 中文名 --add</code></pre>
<p>生成的 yaml 自动包含 <code>extra_homepages</code> 字段,抓取时依次访问所有入口,自动去重。</p>
<h3>5.4 为已有源追加入口</h3>
<pre><code>uv run a-share add-entry wallstreetcn https://xxx.com/news/新频道</code></pre>
<p>自动去重 — 已存在的 URL 跳过。</p>
<h3>5.5 验证</h3>
<pre><code>uv run a-share crawl --source wallstreetcn</code></pre>
<h2 id="cninfo">6. cninfo 公告抓取</h2>
<p>cninfo(巨潮资讯网)是独立的 A 股公告抓取管道,与新闻抓取分开调度(每天 08:00)。</p>
<pre><code>uv run a-share pipeline --cninfo-once # watchlist 全链路 (公告+调研+IRM)
uv run a-share cninfo --watchlist # 仅公告(关注公司)
uv run a-share cninfo --research # 仅调研
uv run a-share cninfo --irm # 仅互动问答
uv run a-share stock-report # 个股日报</code></pre>
<p>全链路 9 步: 公告→调研→IRM→提取→PDF→去重→LLM→向量→Qdrant。</p>
<h4>公告关注列表</h4>
<pre><code>uv run a-share watchlist add 300750 宁德时代 --note "动力电池龙头"
uv run a-share watchlist list
uv run a-share watchlist remove 000001
uv run a-share cninfo --watchlist # 只抓关注公司</code></pre>
<p>关注公司公告在日报中置顶并 ⭐ 高亮。配置: <code>configs/watchlist.yaml</code></p>
<p><strong>配置</strong>: <code>CNINFO_ENABLED</code> <code>CNINFO_DAYS_BACK</code> <code>CNINFO_MAX_PAGES</code> <code>CNINFO_API_BASE</code> <code>CNINFO_PDF_BASE</code></p>
<div class="card"><strong>⚠ .env 注意</strong>: 值后面不能跟 <code>#</code> 注释。python-dotenv 会把 <code>#</code> 后内容当成值。注释必须独占一行。</div>
<h2 id="检索">7. 知识库检索</h2>
<h3>6.1 终端直接检索</h3>
<pre><code>uv run a-share search "宁德时代固态电池" --top 5
uv run a-share search "政策" --source cls --sentiment positive
uv run a-share search "风险" --stock 001212 --min-importance 3</code></pre>
<h3>6.2 Python 检索 (带过滤)</h3>
<pre><code>from vectorstore import VectorStore, SearchFilter, make_qdrant_client
c = make_qdrant_client()
s = VectorStore(c)
hits = s.query(vector=probe["vector"], top_k=10,
filter=SearchFilter(source_id="cls", importance_min=3, sentiment="positive"))
for h in hits: print(h.short_summary())
s.close()</code></pre>
<p>支持 8 种过滤: source_id / stock_codes / company_names / industries / sentiment / importance_min / event_types / date_range。</p>
<h3>6.3 日报</h3>
<pre><code>uv run a-share report # 生成今日日报并上传
uv run a-share report --date 20260616 # 指定日期
uv run a-share report --no-upload # 仅生成不上传</code></pre>
<p>HTML 日报含: AI 摘要 (LLM 生成 400-500 字要点) + 数据总览 + 情绪分布 + 事件类型 + 高重要度事件列表。</p>
<h2 id="定时任务">8. 定时任务部署</h2>
<h3>7.1 安装 systemd 服务 (一次性)</h3>
<pre><code>sudo cp scripts/a-share-research.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable a-share-research</code></pre>
<h3>7.2 日常操作</h3>
<table>
<tr><td>启动</td><td><code>sudo systemctl start a-share-research</code></td></tr>
<tr><td>停止</td><td><code>sudo systemctl stop a-share-research</code></td></tr>
<tr><td>状态</td><td><code>sudo systemctl status a-share-research</code></td></tr>
<tr><td>实时日志</td><td><code>journalctl -u a-share-research -f</code></td></tr>
</table>
<p>默认执行时间: 每天 07:00 / 12:00 / 18:00 / 22:00。7:00 的日报自动覆盖过去 24 小时新闻。</p>
<h4>修改定时配置</h4>
<pre><code># 1. 编辑 .env 中的 SCHEDULE_TIMES
nano /home/pi/news/.env
# 格式: HH:MM,HH:MM,... (24 小时制, 逗号分隔)
# 例: SCHEDULE_TIMES=08:00,14:00,20:00
# 2. 重启服务
sudo systemctl restart a-share-research
# 3. 验证
grep "已注册定时任务" /home/pi/news/logs/scheduler.log | tail -4</code></pre>
<h2 id="mcp">8. MCP 服务与 AI Agent</h2>
<h3>8.1 连接 Cherry Studio</h3>
<p>设置 → MCP 服务器 → 添加:</p>
<pre><code>{"mcpServers":{"a-share-research":{"command":"uv","args":["run","python","-m","scripts.run_mcp_server"],"cwd":"/home/pi/news"}}}</code></pre>
<h3>8.2 5 个 MCP 工具</h3>
<table>
<tr><th>工具</th><th>功能</th><th>示例</th></tr>
<tr><td><code>search_news</code></td><td>通用语义检索</td><td><code>search_news("宁德时代固态电池")</code></td></tr>
<tr><td><code>search_company_news</code></td><td>按公司检索</td><td><code>search_company_news("价格", company="茅台")</code></td></tr>
<tr><td><code>search_industry_news</code></td><td>按行业检索</td><td><code>search_industry_news("政策", industry="半导体")</code></td></tr>
<tr><td><code>search_stock_events</code></td><td>按股票代码检索</td><td><code>search_stock_events("事件", stock_code="300750")</code></td></tr>
<tr><td><code>search_sentiment_trend</code></td><td>情绪检索+统计</td><td><code>search_sentiment_trend("AI算力", sentiment="all")</code></td></tr>
</table>
<h2 id="投研">9. 投研分析模板</h2>
<p>在 Cherry Studio 中粘贴 <code>docs/agent_prompt.md</code> 作为 System Prompt:</p>
<div class="card"><strong>公司分析</strong>: 分析宁德时代 (300750) 近 30 天的利好利空变化</div>
<div class="card"><strong>行业分析</strong>: 分析动力电池行业最近的政策动向和竞争格局</div>
<div class="card"><strong>风险排查</strong>: 梳理中旗新材 (001212) 近期面临的主要风险</div>
<div class="card"><strong>事件追踪</strong>: 过去一周 A 股有哪些重大监管处罚事件?</div>
<div class="card"><strong>情绪趋势</strong>: 近一个月 AI 算力概念的情绪变化趋势如何?</div>
<h2 id="附录">10. 附录</h2>
<h3>A. Qdrant 部署模式</h3>
<table>
<tr><th></th><th>本地文件模式 (默认)</th><th>Docker Server 模式</th></tr>
<tr><td>类比</td><td>SQLite</td><td>PostgreSQL</td></tr>
<tr><td>进程</td><td>无独立进程</td><td>容器 a_share_qdrant</td></tr>
<tr><td>ARM64</td><td><span class="badge-ok"></span></td><td><span class="badge-err"></span> jemalloc 16K 页崩溃</td></tr>
<tr><td>适用</td><td>树莓派 / 单机</td><td>x86 生产 / 远程</td></tr>
</table>
<h3>B. 环境变量</h3>
<table>
<tr><td><code>LLM_PROVIDER</code></td><td><code>deepseek</code></td><td>M4 LLM</td></tr>
<tr><td><code>DEEPSEEK_API_KEY</code></td><td></td><td>DeepSeek Key</td></tr>
<tr><td><code>DASHSCOPE_API_KEY</code></td><td></td><td>百炼 Key (M5/M8)</td></tr>
<tr><td><code>EMBEDDING_PROVIDER</code></td><td><code>dashscope</code></td><td>M5 嵌入</td></tr>
<tr><td><code>SCHEDULE_TIMES</code></td><td><code>07:00,12:00,18:00,22:00</code></td><td>M7 定时</td></tr>
</table>
<h3>C. 日志文件</h3>
<p><code>logs/crawler.log</code> · <code>logs/extractor.log</code> · <code>logs/dedup.log</code> · <code>logs/llm.log</code> · <code>logs/embedding.log</code> · <code>logs/qdrant.log</code> · <code>logs/scheduler.log</code> · <code>logs/mcp_server.log</code> (自动轮转 10MB×5)</p>
<h3>D. 常见问题</h3>
<div class="card"><h4>Q: 某源抓取 0 篇?</h4><p>A: 编辑 <code>configs/sources.yaml</code>,检查 <code>article_url_pattern</code> 正则。或重新 <code>discover</code> 分析。</p></div>
<div class="card"><h4>Q: LLM 报错?</h4><p>A: 检查 <code>.env</code><code>DEEPSEEK_API_KEY</code>。可切换 <code>--provider qwen</code> 测试。</p></div>
<div class="card"><h4>Q: Qdrant 搜索无结果?</h4><p>A: <code>uv run a-share status</code> 检查数据量。若 Qdrant 为 0,执行 <code>uv run a-share ingest --date &lt;date&gt; --recreate</code></p></div>
<div class="card"><h4>Q: 从零重建知识库?</h4><pre><code>rm -rf data/raw data/processed data/dedup data/deduped data/events data/embeddings data/qdrant_storage
uv run a-share pipeline --once</code></pre></div>
</main>
<footer><div class="container"><p>A 股 Deep Research 私有投研平台 · 用户手册 v1.1 · 2026-06-17</p></div></footer>
</body>
</html>