Skill: 13923870749/newsscraper (version 1.0.0)

--- name: news-hot-scraper description: This skill should be used when users need to scrape hot news topics from Chinese platforms (微博、知乎、B站、抖音、今日头条、腾讯新闻、澎湃新闻), generate summaries, and cite sources. It supports both API-based and direct scraping methods, and offers both extractive and abstractive summarization techniques. --- # News Hot Scraper ## Overview 自动爬取国内热点新闻信息,支持多种平台(微博、知乎、B站、抖音、今日头条、腾讯新闻、澎湃新闻),能够生成新闻摘要并注明出处。提供 API 和直接爬取两种数据获取方式,以及提取式和生成式两种摘要生成方案。 ## 核心功能 ### 1. 新闻数据获取 根据用户输入的主题或关键词,从支持的平台获取热点新闻数据。支持两种方式: - **API 方式**: 使用免费的热榜聚合 API(如 uapis.cn)快速获取多平台热点数据 - **直接爬取**: 使用 requests + BeautifulSoup 等技术直接从新闻网站爬取数据 ### 2. 新闻摘要生成 对获取的新闻内容进行智能摘要,支持两种技术方案: - **提取式摘要**: 基于关键词和句子重要性提取关键句,快速简洁 - **生成式摘要**: 使用 HuggingFace 的中文摘要模型(如 `google/mt5-small-chinese`),生成更自然的摘要 ### 3. 出处标注 为每条新闻清晰标注: - 标题 - 来源平台 - 发布时间 - 原文链接 - 摘要内容 ## 使用场景 当用户需要: - "帮我搜集关于[主题]的国内热点新闻" - "爬取微博热搜、知乎热榜的今日热点" - "获取科技领域的最新新闻并生成摘要" - "监控特定主题的新闻动态" - "整理多个平台的热点话题" ## 工作流程 ### 步骤 1: 确定数据源和获取方式 根据用户需求和实际情况选择: - **快速获取**: 优先使用 API 方式(如全网热榜聚合 API) - **详细内容**: 使用直接爬取方式获取更多内容 参考 `references/platforms.md` 了解各平台的爬取策略和注意事项。 ### 步骤 2: 执行数据获取 使用 `scripts/news_scraper.py` 脚本进行数据爬取: ```bash # 使用 API 方式获取多平台热点 python scripts/news_scraper.py --mode api --platforms weibo,zhihu --limit 20 # 直接爬取特定平台 python scripts/news_scraper.py --mode scrape --platform weibo --limit 10 # 根据主题爬取新闻 python scripts/news_scraper.py --mode scrape --keyword "人工智能" --platforms weibo,zhihu --limit 15 ``` ### 步骤 3: 生成新闻摘要 使用 `scripts/news_summarizer.py` 脚本生成摘要: ```bash # 提取式摘要(快速) python scripts/news_summarizer.py --method extractive --input news_data.json --output summary.json # 生成式摘要(质量更好) python scripts/news_summarizer.py --method abstractive --input news_data.json --output summary.json ``` 参考 `references/summarization_methods.md` 了解不同摘要方法的原理和适用场景。 ### 步骤 4: 整理和输出 将结果整理成结构化的格式(JSON/Markdown),包含: - 新闻标题 - 来源平台 - 发布时间 - 摘要内容 - 原文链接 - 热度/排名(如适用) ## 技术栈 ### 爬虫技术 - **requests**: HTTP 请求 - **BeautifulSoup4**: HTML 解析 - **newspaper3k**: 新闻内容提取(可选) - **API 接口**: 全网热榜聚合 API(uapis.cn 等) ### 摘要生成 - **提取式**: jieba(分词)、textrank(句子重要性排序) - **生成式**: transformers + HuggingFace 模型(`google/mt5-small-chinese`) ### 数据处理 - **JSON**: 数据存储和交换 - **Markdown**: 报告输出 ## 注意事项 ### 合规性 - 遵守网站的 robots.txt 规则 - 控制请求频率,避免对目标网站造成压力 - 尊重数据的使用条款和版权 ### 反爬虫处理 - 使用合理的请求头(User-Agent) - 添加适当的延时(建议 1-3 秒) - 考虑使用代理 IP(如需要大量爬取) ### 数据质量 - 验证新闻来源的可靠性 - 过滤重复或低质量内容 - 记录数据获取的时间戳 ## 资源 ### scripts/ - **news_scraper.py**: 新闻数据爬取脚本,支持 API 和直接爬取两种方式 - **news_summarizer.py**: 新闻摘要生成脚本,支持提取式和生成式两种方法 ### references/ - **platforms.md**: 各平台(微博、知乎、B站等)的爬取策略、API 文档和注意事项 - **summarization_methods.md**: 摘要生成方法的详细介绍,包括技术原理和实现代码示例 ### assets/ - (暂无,可根据需要添加模板或示例数据) ## 常见问题 ### Q: 优先使用 API 还是直接爬取? A: 对于快速获取多平台热点,优先使用 API(如全网热榜聚合 API),它们通常已经处理了反爬虫问题。如果需要更详细的内容或特定平台的数据,再使用直接爬取。 ### Q: 提取式摘要和生成式摘要哪个更好? A: 提取式摘要速度快,但可能不够连贯;生成式摘要质量更高,但需要更长时间。根据使用场景选择: - 实时监控/快速浏览: 提取式 - 深度分析/报告生成: 生成式 ### Q: 如何处理反爬虫限制? A: 参考 `references/platforms.md` 中的反爬虫处理建议,包括: - 使用合理的请求头和延时 - 考虑使用代理 IP - 遵守 robots.txt 规则 - 优先使用官方 API(如果可用) ## 扩展建议 未来可以考虑添加: - 定时任务功能,定期自动爬取热点 - 数据可视化(词云、趋势图) - 多语言支持 - 情感分析 - 主题聚类分析 ## 依赖安装 ### 基础依赖(必须安装) ```bash pip install requests beautifulsoup4 ``` ### 提取式摘要依赖(推荐) ```bash pip install jieba ``` ### 生成式摘要依赖(可选) ```bash pip install transformers torch ``` 注意: ClawHub 不会自动安装依赖,用户需要根据上述说明手动安装所需的 Python 包。

path: README.md
content: # 新闻热点爬取 Skill (News Hot Scraper)

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python Version](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
[![Skill Status](https://img.shields.io/badge/status-beta-orange.svg)]()

自动爬取国内热点新闻信息,支持多种平台,能够生成新闻摘要并注明出处。

## ✨ 功能特性

### 1. 多平台支持
- 微博热搜
- 知乎热榜
- B站热门
- 抖音热点
- 今日头条
- 腾讯新闻
- 澎湃新闻

### 2. 两种数据获取方式
- **API 方式**: 使用免费的热榜聚合 API,快速获取多平台热点
- **直接爬取**: 使用 requests + BeautifulSoup 直接从新闻网站爬取

### 3. 两种摘要生成方案
- **提取式摘要**: 基于关键词提取关键句,快速简洁
- **生成式摘要**: 使用 HuggingFace 的中文摘要模型,生成更自然的摘要

### 4. 完整的出处标注
- 标题
- 来源平台
- 发布时间
- 原文链接
- 摘要内容

## 📦 安装

### 方式 1: 使用 pip 安装

```bash
# 基础安装(仅支持提取式摘要)
pip install news-hot-scraper

# 安装生成式摘要依赖
pip install news-hot-scraper[abstractive]
```

### 方式 2: 从源码安装

```bash
# 克隆仓库
git clone https://clawhub.com/workbuddy/news-hot-scraper.git
cd news-hot-scraper

# 安装基础依赖
pip install -r requirements.txt

# 安装生成式摘要依赖(可选)
pip install transformers torch
```

## 🚀 快速开始

### 1. 使用 API 方式获取多平台热点

```bash
# 获取微博和知乎的热点
python scripts/news_scraper.py --mode api --platforms weibo,zhihu --limit 20 --output news_data.json

# 生成提取式摘要
python scripts/news_summarizer.py --method extractive --input news_data.json --output summary.json --report summary.md
```

### 2. 直接爬取特定平台

```bash
# 爬取微博热搜
python scripts/news_scraper.py --mode scrape --platform weibo --limit 10 --output news_data.json

# 生成生成式摘要(质量更好)
python scripts/news_summarizer.py --method abstractive --input news_data.json --output summary.json --report summary.md
```

### 3. 根据主题爬取新闻

```bash
# 爬取关于"人工智能"的新闻
python scripts/news_scraper.py --mode scrape --keyword "人工智能" --platforms weibo,zhihu --limit 15 --output news_data.json
```

## 输出格式

### JSON 格式
```json
[
  {
    "title": "新闻标题",
    "platform": "weibo",
    "url": "https://...",
    "hot": 1234567,
    "rank": 1,
    "timestamp": "2026-03-21T13:00:00",
    "summary": "新闻摘要内容..."
  }
]
```

### Markdown 报告格式
```markdown
# 新闻热点摘要报告

生成时间: 2026-03-21T13:00:00
总计: 20 条新闻

## 微博热搜

### 1. 热搜标题

**摘要**: 摘要内容...

**热度**: 1234567

**来源**: [微博热搜](https://...)

**时间**: 2026-03-21T13:00:00

---
```

## 使用场景

- "帮我搜集关于[主题]的国内热点新闻"
- "爬取微博热搜、知乎热榜的今日热点"
- "获取科技领域的最新新闻并生成摘要"
- "监控特定主题的新闻动态"
- "整理多个平台的热点话题"

## 技术栈

### 爬虫技术
- **requests**: HTTP 请求
- **BeautifulSoup4**: HTML 解析
- **API 接口**: 全网热榜聚合 API(uapis.cn)

### 摘要生成
- **提取式**: jieba(分词)、textrank(句子重要性排序)
- **生成式**: transformers + HuggingFace 模型

### 数据处理
- **JSON**: 数据存储和交换
- **Markdown**: 报告输出

## 注意事项

### 合规性
- 遵守网站的 robots.txt 规则
- 控制请求频率,避免对目标网站造成压力
- 尊重数据的使用条款和版权

### 反爬虫处理
- 使用合理的请求头(User-Agent)
- 添加适当的延时(建议 1-3 秒)
- 考虑使用代理 IP(如需要大量爬取)

### 数据质量
- 验证新闻来源的可靠性
- 过滤重复或低质量内容
- 记录数据获取的时间戳

## 文档说明

- **SKILL.md**: Skill 的主要使用文档
- **references/platforms.md**: 各平台爬取策略和 API 文档
- **references/summarization_methods.md**: 摘要生成方法详解
- **scripts/news_scraper.py**: 新闻数据爬取脚本
- **scripts/news_summarizer.py**: 新闻摘要生成脚本

## 常见问题

### Q: 优先使用 API 还是直接爬取?
A: 对于快速获取多平台热点,优先使用 API(如全网热榜聚合 API),它们通常已经处理了反爬虫问题。如果需要更详细的内容或特定平台的数据,再使用直接爬取。

### Q: 提取式摘要和生成式摘要哪个更好?
A: 提取式摘要速度快,但可能不够连贯;生成式摘要质量更高,但需要更长时间。根据使用场景选择:
- 实时监控/快速浏览: 提取式
- 深度分析/报告生成: 生成式

### Q: 如何处理反爬虫限制?
A: 参考 `references/platforms.md` 中的反爬虫处理建议,包括:
- 使用合理的请求头和延时
- 考虑使用代理 IP
- 遵守 robots.txt 规则
- 优先使用官方 API(如果可用)

## 扩展建议

未来可以考虑添加:
- 定时任务功能,定期自动爬取热点
- 数据可视化(词云、趋势图)
- 多语言支持
- 情感分析
- 主题聚类分析

## 📄 许可证

本项目采用 MIT 许可证 - 详见 [LICENSE](LICENSE) 文件

## 🤝 贡献

欢迎贡献代码!请遵循以下步骤:

1. Fork 本仓库
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 开启 Pull Request

## 📧 联系方式

- 项目主页: [https://clawhub.com/workbuddy/news-hot-scraper](https://clawhub.com/workbuddy/news-hot-scraper)
- 问题反馈: [Issues](https://clawhub.com/workbuddy/news-hot-scraper/issues)

## ⚠️ 免责声明

本 Skill 仅供学习和研究使用。请遵守各平台的使用条款和相关法律法规。使用本工具爬取的数据不得用于商业目的,请尊重数据来源的版权。

## 🙏 致谢

- [jieba](https://github.com/fxsjy/jieba) - 中文分词
- [transformers](https://github.com/huggingface/transformers) - HuggingFace Transformers
- [BeautifulSoup](https://www.crummy.com/software/BeautifulSoup/) - HTML 解析

---

**Made with ❤️ by WorkBuddy AI**


path: scripts/news_scraper.py
content: #!/usr/bin/env python3
"""
新闻数据爬取脚本
支持 API 和直接爬取两种方式获取新闻数据

使用方法:
    # 使用 API 方式获取多平台热点
    python news_scraper.py --mode api --platforms weibo,zhihu --limit 20

    # 直接爬取特定平台
    python news_scraper.py --mode scrape --platform weibo --limit 10

    # 根据主题爬取新闻
    python news_scraper.py --mode scrape --keyword "人工智能" --platforms weibo,zhihu --limit 15
"""

import requests
import json
import time
import argparse
from datetime import datetime
from typing import List, Dict, Optional
from bs4 import BeautifulSoup


class NewsScraper:
    """新闻爬虫类,支持多种平台和数据获取方式"""

    def __init__(self):
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
        }
        self.session = requests.Session()
        self.session.headers.update(self.headers)

    def scrape_by_api(self, platforms: List[str], limit: int = 20) -> List[Dict]:
        """
        使用 API 方式获取多平台热点数据

        Args:
            platforms: 平台列表,如 ['weibo', 'zhihu']
            limit: 每个平台获取的新闻数量

        Returns:
            新闻数据列表
        """
        all_news = []

        # 使用全网热榜聚合 API (uapis.cn)
        api_url = "https://uapis.cn/api/get-misc-hotboard"

        for platform in platforms:
            try:
                print(f"正在通过 API 获取 {platform} 热点...")

                # 根据平台映射 API 参数
                platform_map = {
                    'weibo': 'weibo',
                    'zhihu': 'zhihu',
                    'bilibili': 'bilibili',
                    'douyin': 'douyin',
                    'toutiao': 'toutiao',
                    'tencent': 'tencent',
                    'thepaper': 'thepaper'
                }

                api_platform = platform_map.get(platform, platform)
                params = {
                    'name': api_platform,
                    'limit': limit
                }

                response = self.session.get(api_url, params=params, timeout=10)
                response.raise_for_status()
                data = response.json()

                if data.get('code') == 200 and data.get('data'):
                    news_list = data['data'][:limit]
                    for item in news_list:
                        news_item = {
                            'title': item.get('title', ''),
                            'platform': platform,
                            'url': item.get('url', ''),
                            'hot': item.get('hot', 0),
                            'timestamp': datetime.now().isoformat(),
                            'summary': ''  # 稍后生成摘要
                        }
                        all_news.append(news_item)
                    print(f"✓ 从 {platform} 获取了 {len(news_list)} 条热点")
                else:
                    print(f"✗ {platform} API 返回数据格式异常")

                # 礼貌性延时
                time.sleep(1)

            except Exception as e:
                print(f"✗ 获取 {platform} 失败: {str(e)}")

        return all_news

    def scrape_by_direct(self, platform: str, keyword: Optional[str] = None, limit: int = 10) -> List[Dict]:
        """
        直接爬取新闻网站获取数据

        Args:
            platform: 平台名称
            keyword: 搜索关键词(可选)
            limit: 获取的新闻数量

        Returns:
            新闻数据列表
        """
        print(f"正在直接爬取 {platform}...")
        all_news = []

        if platform == 'weibo':
            all_news = self._scrape_weibo(keyword, limit)
        elif platform == 'zhihu':
            all_news = self._scrape_zhihu(keyword, limit)
        elif platform == 'bilibili':
            all_news = self._scrape_bilibili(keyword, limit)
        elif platform == 'tencent':
            all_news = self._scrape_tencent(keyword, limit)
        elif platform == 'thepaper':
            all_news = self._scrape_thepaper(keyword, limit)
        else:
            print(f"✗ 暂不支持直接爬取平台: {platform}")

        return all_news

    def _scrape_weibo(self, keyword: Optional[str], limit: int) -> List[Dict]:
        """爬取微博热搜"""
        news_list = []

        try:
            url = "https://s.weibo.com/top/summary"
            response = self.session.get(url, timeout=10)
            response.raise_for_status()

            soup = BeautifulSoup(response.text, 'html.parser')

            # 微博热搜列表
            hot_items = soup.find_all('a', {'href': lambda x: x and '/weibo?q=' in x})

            for i, item in enumerate(hot_items[:limit]):
                title = item.get_text().strip()
                url = "https://s.weibo.com" + item.get('href', '')

                if title:
                    news_item = {
                        'title': title,
                        'platform': 'weibo',
                        'url': url,
                        'rank': i + 1,
                        'timestamp': datetime.now().isoformat(),
                        'summary': ''
                    }
                    news_list.append(news_item)

            print(f"✓ 从微博获取了 {len(news_list)} 条热搜")

        except Exception as e:
            print(f"✗ 爬取微博失败: {str(e)}")

        return news_list

    def _scrape_zhihu(self, keyword: Optional[str], limit: int) -> List[Dict]:
        """爬取知乎热榜"""
        news_list = []

        try:
            url = "https://www.zhihu.com/hot"
            headers = {
                'User-Agent': self.headers['User-Agent'],
                'Referer': 'https://www.zhihu.com/'
            }
            response = self.session.get(url, headers=headers, timeout=10)
            response.raise_for_status()

            soup = BeautifulSoup(response.text, 'html.parser')

            # 知乎热榜项
            hot_items = soup.find_all('div', {'class': 'HotItem'})

            for i, item in enumerate(hot_items[:limit]):
                title_elem = item.find('h2', {'class': 'HotItem-title'})
                link_elem = item.find('a')

                if title_elem:
                    title = title_elem.get_text().strip()
                    url = link_elem.get('href', '')
                    if url and not url.startswith('http'):
                        url = 'https://www.zhihu.com' + url

                    news_item = {
                        'title': title,
                        'platform': 'zhihu',
                        'url': url,
                        'rank': i + 1,
                        'timestamp': datetime.now().isoformat(),
                        'summary': ''
                    }
                    news_list.append(news_item)

            print(f"✓ 从知乎获取了 {len(news_list)} 条热榜")

        except Exception as e:
            print(f"✗ 爬取知乎失败: {str(e)}")

        return news_list

    def _scrape_bilibili(self, keyword: Optional[str], limit: int) -> List[Dict]:
        """爬取B站热门"""
        news_list = []

        try:
            url = "https://www.bilibili.com/v/popular/all"
            response = self.session.get(url, timeout=10)
            response.raise_for_status()

            soup = BeautifulSoup(response.text, 'html.parser')

            # B站热门视频项
            video_items = soup.find_all('a', {'class': 'video-title'})

            for i, item in enumerate(video_items[:limit]):
                title = item.get('title', '').strip()
                url = "https:" + item.get('href', '') if item.get('href', '').startswith('//') else item.get('href', '')

                if title:
                    news_item = {
                        'title': title,
                        'platform': 'bilibili',
                        'url': url,
                        'rank': i + 1,
                        'timestamp': datetime.now().isoformat(),
                        'summary': ''
                    }
                    news_list.append(news_item)

            print(f"✓ 从B站获取了 {len(news_list)} 条热门")

        except Exception as e:
            print(f"✗ 爬取B站失败: {str(e)}")

        return news_list

    def _scrape_tencent(self, keyword: Optional[str], limit: int) -> List[Dict]:
        """爬取腾讯新闻"""
        news_list = []

        try:
            url = "https://news.qq.com/"
            response = self.session.get(url, timeout=10)
            response.raise_for_status()

            soup = BeautifulSoup(response.text, 'html.parser')

            # 腾讯新闻链接
            news_links = soup.find_all('a', {'href': lambda x: x and '/a/' in x})

            for i, item in enumerate(news_links[:limit]):
                title = item.get_text().strip()
                url = item.get('href', '')

                if title and url:
                    news_item = {
                        'title': title,
                        'platform': 'tencent',
                        'url': url,
                        'timestamp': datetime.now().isoformat(),
                        'summary': ''
                    }
                    news_list.append(news_item)

            print(f"✓ 从腾讯新闻获取了 {len(news_list)} 条")

        except Exception as e:
            print(f"✗ 爬取腾讯新闻失败: {str(e)}")

        return news_list

    def _scrape_thepaper(self, keyword: Optional[str], limit: int) -> List[Dict]:
        """爬取澎湃新闻"""
        news_list = []

        try:
            url = "https://www.thepaper.cn/"
            response = self.session.get(url, timeout=10)
            response.raise_for_status()

            soup = BeautifulSoup(response.text, 'html.parser')

            # 澎湃新闻标题
            news_titles = soup.find_all('h2')

            for i, item in enumerate(news_titles[:limit]):
                title = item.get_text().strip()
                link = item.find('a')
                url = link.get('href', '') if link else ''

                if title:
                    news_item = {
                        'title': title,
                        'platform': 'thepaper',
                        'url': url,
                        'timestamp': datetime.now().isoformat(),
                        'summary': ''
                    }
                    news_list.append(news_item)

            print(f"✓ 从澎湃新闻获取了 {len(news_list)} 条")

        except Exception as e:
            print(f"✗ 爬取澎湃新闻失败: {str(e)}")

        return news_list

    def save_to_json(self, news_list: List[Dict], output_file: str):
        """保存新闻数据到 JSON 文件"""
        with open(output_file, 'w', encoding='utf-8') as f:
            json.dump(news_list, f, ensure_ascii=False, indent=2)
        print(f"✓ 数据已保存到 {output_file}")


def main():
    parser = argparse.ArgumentParser(description='新闻数据爬取工具')
    parser.add_argument('--mode', type=str, choices=['api', 'scrape'], required=True,
                        help='数据获取方式: api(使用API) 或 scrape(直接爬取)')
    parser.add_argument('--platform', type=str, help='单个平台名称(直接爬取模式)')
    parser.add_argument('--platforms', type=str, help='多个平台名称,逗号分隔(API模式)')
    parser.add_argument('--keyword', type=str, help='搜索关键词(可选)')
    parser.add_argument('--limit', type=int, default=20, help='获取的新闻数量限制')
    parser.add_argument('--output', type=str, default='news_data.json', help='输出文件路径')

    args = parser.parse_args()

    scraper = NewsScraper()
    all_news = []

    if args.mode == 'api':
        if not args.platforms:
            print("错误: API 模式需要指定 --platforms 参数")
            return

        platforms = [p.strip() for p in args.platforms.split(',')]
        all_news = scraper.scrape_by_api(platforms, args.limit)

    elif args.mode == 'scrape':
        if not args.platform:
            print("错误: 直接爬取模式需要指定 --platform 参数")
            return

        all_news = scraper.scrape_by_direct(args.platform, args.keyword, args.limit)

    # 保存数据
    if all_news:
        scraper.save_to_json(all_news, args.output)
        print(f"\n总计获取了 {len(all_news)} 条新闻数据")
    else:
        print("\n未获取到任何新闻数据")


if __name__ == "__main__":
    main()


path: scripts/news_summarizer.py
content: #!/usr/bin/env python3
"""
新闻摘要生成脚本
支持提取式和生成式两种摘要方法

使用方法:
    # 提取式摘要(快速)
    python news_summarizer.py --method extractive --input news_data.json --output summary.json

    # 生成式摘要(质量更好)
    python news_summarizer.py --method abstractive --input news_data.json --output summary.json
"""

import json
import argparse
from typing import List, Dict, Optional
import re


# 提取式摘要依赖
try:
    import jieba
    import jieba.analyse
    JIEBA_AVAILABLE = True
except ImportError:
    JIEBA_AVAILABLE = False
    print("警告: jieba 未安装,提取式摘要功能不可用")

# 生成式摘要依赖
try:
    from transformers import pipeline
    TRANSFORMERS_AVAILABLE = True
except ImportError:
    TRANSFORMERS_AVAILABLE = False
    print("警告: transformers 未安装,生成式摘要功能不可用")


class NewsSummarizer:
    """新闻摘要生成器"""

    def __init__(self):
        self.extractive_model = None
        self.abstractive_pipeline = None

    def summarize_extractive(self, text: str, max_sentences: int = 3) -> str:
        """
        提取式摘要:基于关键词提取关键句

        Args:
            text: 原文文本
            max_sentences: 最多提取的句子数

        Returns:
            摘要文本
        """
        if not JIEBA_AVAILABLE:
            raise ImportError("需要安装 jieba 库: pip install jieba")

        # 提取关键词
        keywords = jieba.analyse.extract_tags(text, topK=10, withWeight=True)

        if not keywords:
            return text[:200] + "..."

        # 按句号、问号、感叹号分割句子
        sentences = re.split(r'[。！？\n]', text)
        sentences = [s.strip() for s in sentences if s.strip()]

        if not sentences:
            return text[:200] + "..."

        # 计算每个句子的得分(包含关键词的句子得分更高)
        sentence_scores = []
        keyword_set = set([kw[0] for kw in keywords])

        for sentence in sentences:
            score = 0
            # 包含关键词的句子得分更高
            for keyword, weight in keywords:
                if keyword in sentence:
                    score += weight * 10
            # 句子长度适中得分更高
            if 20 <= len(sentence) <= 100:
                score += 5
            sentence_scores.append((sentence, score))

        # 按得分排序并选择前 N 个句子
        sentence_scores.sort(key=lambda x: x[1], reverse=True)
        selected_sentences = [s[0] for s in sentence_scores[:max_sentences]]

        # 保持原始顺序
        summary_sentences = []
        for sentence in sentences:
            if sentence in selected_sentences and sentence not in summary_sentences:
                summary_sentences.append(sentence)

        return "。".join(summary_sentences) + "。"

    def summarize_abstractive(self, text: str, max_length: int = 150) -> str:
        """
        生成式摘要:使用预训练模型生成摘要

        Args:
            text: 原文文本
            max_length: 摘要最大长度

        Returns:
            摘要文本
        """
        if not TRANSFORMERS_AVAILABLE:
            raise ImportError("需要安装 transformers 库: pip install transformers torch")

        # 初始化摘要模型(仅第一次)
        if self.abstractive_pipeline is None:
            print("正在加载摘要模型(首次加载需要时间)...")
            # 使用中文摘要模型
            self.abstractive_pipeline = pipeline(
                "summarization",
                model="google/mt5-small-chinese",
                device=-1  # 使用 CPU
            )

        # 限制输入长度,避免超时
        if len(text) > 512:
            text = text[:512]

        # 生成摘要
        try:
            summary = self.abstractive_pipeline(
                text,
                max_length=max_length,
                min_length=30,
                do_sample=False
            )
            return summary[0]['summary_text']
        except Exception as e:
            print(f"生成式摘要失败: {str(e)}")
            # 降级到提取式摘要
            if JIEBA_AVAILABLE:
                return self.summarize_extractive(text)
            return text[:200] + "..."

    def generate_summary_for_news(self, news_data: List[Dict], method: str = 'extractive') -> List[Dict]:
        """
        为新闻数据生成摘要

        Args:
            news_data: 新闻数据列表
            method: 摘要方法 'extractive' 或 'abstractive'

        Returns:
            带有摘要的新闻数据
        """
        summarized_news = []

        for news_item in news_data:
            title = news_item.get('title', '')

            # 如果新闻内容为空,使用标题作为摘要
            if not title:
                news_item['summary'] = news_item.get('summary', '')
                summarized_news.append(news_item)
                continue

            try:
                if method == 'extractive':
                    # 提取式摘要:使用标题本身(简洁)
                    summary = title[:100]
                elif method == 'abstractive':
                    # 生成式摘要:基于标题生成摘要
                    summary = self.summarize_abstractive(title, max_length=100)
                else:
                    raise ValueError(f"不支持的摘要方法: {method}")

                news_item['summary'] = summary

            except Exception as e:
                print(f"摘要生成失败({title[:30]}...): {str(e)}")
                # 使用标题作为摘要
                news_item['summary'] = title[:100]

            summarized_news.append(news_item)

        return summarized_news

    def save_to_json(self, news_data: List[Dict], output_file: str):
        """保存摘要数据到 JSON 文件"""
        with open(output_file, 'w', encoding='utf-8') as f:
            json.dump(news_data, f, ensure_ascii=False, indent=2)
        print(f"✓ 摘要数据已保存到 {output_file}")

    def generate_markdown_report(self, news_data: List[Dict], output_file: str):
        """生成 Markdown 格式的报告"""
        with open(output_file, 'w', encoding='utf-8') as f:
            f.write("# 新闻热点摘要报告\n\n")
            f.write(f"生成时间: {news_data[0].get('timestamp', 'N/A') if news_data else 'N/A'}\n\n")
            f.write(f"总计: {len(news_data)} 条新闻\n\n")

            # 按平台分组
            platforms = {}
            for item in news_data:
                platform = item.get('platform', 'unknown')
                if platform not in platforms:
                    platforms[platform] = []
                platforms[platform].append(item)

            # 按平台输出
            for platform, items in platforms.items():
                platform_names = {
                    'weibo': '微博热搜',
                    'zhihu': '知乎热榜',
                    'bilibili': 'B站热门',
                    'douyin': '抖音热点',
                    'toutiao': '今日头条',
                    'tencent': '腾讯新闻',
                    'thepaper': '澎湃新闻'
                }
                platform_title = platform_names.get(platform, platform)

                f.write(f"## {platform_title}\n\n")

                for i, item in enumerate(items):
                    rank = item.get('rank', i + 1)
                    title = item.get('title', 'N/A')
                    summary = item.get('summary', 'N/A')
                    url = item.get('url', '')
                    hot = item.get('hot', 'N/A')
                    timestamp = item.get('timestamp', 'N/A')

                    f.write(f"### {rank}. {title}\n\n")
                    f.write(f"**摘要**: {summary}\n\n")
                    if hot != 'N/A':
                        f.write(f"**热度**: {hot}\n\n")
                    f.write(f"**来源**: [{platform_title}]({url})\n\n")
                    f.write(f"**时间**: {timestamp}\n\n")
                    f.write("---\n\n")

        print(f"✓ Markdown 报告已保存到 {output_file}")


def main():
    parser = argparse.ArgumentParser(description='新闻摘要生成工具')
    parser.add_argument('--method', type=str, choices=['extractive', 'abstractive'],
                        default='extractive', help='摘要方法: extractive(提取式) 或 abstractive(生成式)')
    parser.add_argument('--input', type=str, required=True, help='输入新闻数据文件(JSON)')
    parser.add_argument('--output', type=str, default='summary.json', help='输出文件路径(JSON)')
    parser.add_argument('--report', type=str, help='生成 Markdown 报告文件路径(可选)')
    parser.add_argument('--max-sentences', type=int, default=3,
                        help='提取式摘要的最大句子数')

    args = parser.parse_args()

    # 读取输入数据
    try:
        with open(args.input, 'r', encoding='utf-8') as f:
            news_data = json.load(f)
    except Exception as e:
        print(f"错误: 无法读取输入文件 {args.input}: {str(e)}")
        return

    # 生成摘要
    summarizer = NewsSummarizer()
    summarized_news = summarizer.generate_summary_for_news(news_data, args.method)

    # 保存 JSON
    summarizer.save_to_json(summarized_news, args.output)

    # 生成 Markdown 报告
    if args.report:
        summarizer.generate_markdown_report(summarized_news, args.report)

    print(f"\n✓ 成功为 {len(summarized_news)} 条新闻生成摘要")


if __name__ == "__main__":
    main()


path: references/platforms.md
content: # 各平台爬取策略和 API 文档

## 概述

本文档详细说明了各平台(微博、知乎、B站、抖音、今日头条、腾讯新闻、澎湃新闻)的爬取策略、API 文档和注意事项。

## 1. 微博 (Weibo)

### API 方式
- **推荐 API**: 全网热榜聚合 API (uapis.cn)
- **端点**: `https://uapis.cn/api/get-misc-hotboard`
- **参数**:
  - `name`: weibo
  - `limit`: 返回数量(默认 20)
- **返回格式**:
  ```json
  {
    "code": 200,
    "data": [
      {
        "title": "热搜标题",
        "url": "热搜链接",
        "hot": 1234567
      }
    ]
  }
  ```

### 直接爬取方式
- **热搜页面**: `https://s.weibo.com/top/summary`
- **HTML 结构**:
  - 热搜项: `<a href="/weibo?q=...">标题</a>`
  - 排名: 通过列表顺序获取
- **注意事项**:
  - 微博有较强的反爬虫机制,建议优先使用 API
  - 如果直接爬取,需要添加 User-Agent 和合理的延时
  - 注意遵守微博的使用条款

## 2. 知乎 (Zhihu)

### API 方式
- **推荐 API**: 全网热榜聚合 API (uapis.cn)
- **端点**: `https://uapis.cn/api/get-misc-hotboard`
- **参数**:
  - `name`: zhihu
  - `limit`: 返回数量(默认 20)

### 直接爬取方式
- **热榜页面**: `https://www.zhihu.com/hot`
- **HTML 结构**:
  - 热榜项: `<div class="HotItem">`
  - 标题: `<h2 class="HotItem-title">`
  - 链接: `<a href="...">`
- **注意事项**:
  - 知乎需要登录才能查看完整内容
  - 建议使用 API 获取热榜数据
  - 如果直接爬取,需要添加 Referer 头

## 3. B站 (Bilibili)

### API 方式
- **推荐 API**: 全网热榜聚合 API (uapis.cn)
- **端点**: `https://uapis.cn/api/get-misc-hotboard`
- **参数**:
  - `name`: bilibili
  - `limit`: 返回数量(默认 20)

### 直接爬取方式
- **热门页面**: `https://www.bilibili.com/v/popular/all`
- **HTML 结构**:
  - 视频项: `<a class="video-title">`
  - 标题: `title` 属性
  - 链接: `href` 属性
- **注意事项**:
  - B站的反爬虫相对较弱
  - 可以直接爬取热门视频列表
  - 建议添加 1-2 秒的延时

## 4. 抖音 (Douyin)

### API 方式
- **推荐 API**: 全网热榜聚合 API (uapis.cn)
- **端点**: `https://uapis.cn/api/get-misc-hotboard`
- **参数**:
  - `name`: douyin
  - `limit`: 返回数量(默认 20)

### 直接爬取方式
- **难度**: 高
- **原因**: 抖音使用动态加载和加密的 API,直接爬取非常困难
- **建议**: 优先使用 API,不建议直接爬取

## 5. 今日头条 (Toutiao)

### API 方式
- **推荐 API**: 全网热榜聚合 API (uapis.cn)
- **端点**: `https://uapis.cn/api/get-misc-hotboard`
- **参数**:
  - `name`: toutiao
  - `limit`: 返回数量(默认 20)

### 直接爬取方式
- **首页**: `https://www.toutiao.com/`
- **HTML 结构**: 动态加载,需要分析 API
- **建议**: 优先使用 API,直接爬取复杂度较高

## 6. 腾讯新闻 (Tencent News)

### API 方式
- **推荐 API**: 全网热榜聚合 API (uapis.cn)
- **端点**: `https://uapis.cn/api/get-misc-hotboard`
- **参数**:
  - `name`: tencent
  - `limit`: 返回数量(默认 20)

### 直接爬取方式
- **首页**: `https://news.qq.com/`
- **HTML 结构**:
  - 新闻链接: `<a href="/a/...">`
  - 需要从首页提取新闻链接
- **注意事项**:
  - 腾讯新闻的反爬虫较弱
  - 可以直接爬取首页新闻链接
  - 建议添加合理的延时

## 7. 澎湃新闻 (The Paper)

### API 方式
- **推荐 API**: 全网热榜聚合 API (uapis.cn)
- **端点**: `https://uapis.cn/api/get-misc-hotboard`
- **参数**:
  - `name`: thepaper
  - `limit`: 返回数量(默认 20)

### 直接爬取方式
- **首页**: `https://www.thepaper.cn/`
- **HTML 结构**:
  - 新闻标题: `<h2>` 标签
  - 链接: 内部的 `<a>` 标签
- **注意事项**:
  - 澎湃新闻的反爬虫较弱
  - 可以直接爬取首页标题
  - 建议添加合理的延时

## 全网热榜聚合 API (uapis.cn)

### 基本信息
- **基础 URL**: `https://uapis.cn/api/get-misc-hotboard`
- **方法**: GET
- **免费**: 是,无需注册
- **更新频率**: 约 30 分钟一次

### 参数说明
- `name`: 平台名称
  - 支持的平台: weibo, zhihu, bilibili, douyin, toutiao, tencent, thepaper
- `limit`: 返回数量
  - 默认: 20
  - 最大: 50(部分平台)

### 响应格式
```json
{
  "code": 200,
  "message": "获取成功",
  "title": "平台名称",
  "subtitle": "热榜",
  "total": 20,
  "updateTime": "2026-03-21 12:00:00",
  "data": [
    {
      "title": "新闻标题",
      "url": "新闻链接",
      "hot": 1234567,
      "rank": 1
    }
  ]
}
```

### 使用示例
```python
import requests

url = "https://uapis.cn/api/get-misc-hotboard"
params = {
    'name': 'weibo',
    'limit': 20
}

response = requests.get(url, params=params)
data = response.json()
```

### 优势
- 多平台聚合,一次调用获取多个平台数据
- 免费且无需注册
- 已处理反爬虫问题
- 数据格式统一

### 限制
- 更新频率约 30 分钟,不是实时数据
- 部分平台可能不提供完整的热度值
- 依赖第三方服务的稳定性

## 反爬虫处理建议

### 1. 请求头设置
```python
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
    'Referer': 'https://www.example.com/'
}
```

### 2. 延时设置
```python
import time
# 礼貌性延时 1-3 秒
time.sleep(2)
```

### 3. 使用 Session
```python
session = requests.Session()
session.headers.update(headers)
```

### 4. 代理 IP(如需要大量爬取)
```python
proxies = {
    'http': 'http://proxy.example.com:8080',
    'https': 'https://proxy.example.com:8080'
}
response = session.get(url, proxies=proxies)
```

### 5. 遵守 robots.txt
在爬取前,检查目标网站的 robots.txt 文件,遵守其规则。

## 合规性注意事项

1. **版权问题**: 爬取的数据仅供个人学习或研究使用,不得用于商业目的
2. **服务器压力**: 控制请求频率,避免对目标网站造成压力
3. **使用条款**: 遵守各平台的使用条款和 API 使用协议
4. **数据隐私**: 不爬取和存储用户的个人隐私信息
5. **法律风险**: 确保爬取行为符合相关法律法规

## 推荐的数据获取策略

### 快速获取
优先使用全网热榜聚合 API(uapis.cn):
- 速度快,一次调用获取多平台数据
- 已处理反爬虫问题
- 数据格式统一,易于处理

### 详细内容
使用直接爬取方式:
- 获取更详细的内容
- 自定义爬取逻辑
- 但需要处理反爬虫问题

### 混合使用
结合两种方式:
- 使用 API 快速获取热榜
- 使用直接爬取获取详细内容
- 平衡速度和详细度


path: references/summarization_methods.md
content: # 新闻摘要生成方法详解

## 概述

本文档详细介绍新闻摘要生成的两种主要方法:提取式摘要和生成式摘要,包括技术原理、实现代码和适用场景。

## 1. 提取式摘要 (Extractive Summarization)

### 原理

提取式摘要从原文中提取最重要的句子或段落,组合成摘要。核心思想是:
1. 将原文分割成句子
2. 计算每个句子的重要性得分
3. 选择得分最高的 N 个句子作为摘要

### 优点
- 实现简单,计算效率高
- 摘要完全基于原文,不会产生虚假信息
- 不需要训练模型

### 缺点
- 摘要可能不够连贯
- 可能包含冗余信息
- 摘要长度受原文句子长度限制

### 实现方法

#### 方法 1: 基于 TextRank 算法

TextRank 是基于图排序算法的文本摘要方法。

```python
import jieba
import networkx as nx
from sklearn.feature_extraction.text import TfidfVectorizer

def textrank_summarize(text, num_sentences=3):
    """
    使用 TextRank 算法生成提取式摘要

    Args:
        text: 原文文本
        num_sentences: 摘要句子数

    Returns:
        摘要文本
    """
    # 分句
    sentences = [s.strip() for s in text.split('。') if s.strip()]

    # 分词
    words_list = []
    for sent in sentences:
        words = jieba.lcut(sent)
        words_list.append(' '.join(words))

    # TF-IDF 向量化
    vectorizer = TfidfVectorizer()
    tfidf_matrix = vectorizer.fit_transform(words_list)

    # 构建相似度矩阵
    similarity_matrix = tfidf_matrix * tfidf_matrix.T

    # 构建 PageRank 图
    nx_graph = nx.from_scipy_sparse_array(similarity_matrix)
    scores = nx.pagerank(nx_graph)

    # 选择得分最高的句子
    ranked_sentences = sorted(((scores[i], s) for i, s in enumerate(sentences)), reverse=True)

    summary = '。'.join([s for score, s in ranked_sentences[:num_sentences]]) + '。'
    return summary
```

#### 方法 2: 基于关键词提取

```python
import jieba.analyse
import re

def keyword_based_summarize(text, num_sentences=3):
    """
    基于关键词提取生成摘要

    Args:
        text: 原文文本
        num_sentences: 摘要句子数

    Returns:
        摘要文本
    """
    # 提取关键词
    keywords = jieba.analyse.extract_tags(text, topK=10, withWeight=True)

    # 分句
    sentences = re.split(r'[。！？\n]', text)
    sentences = [s.strip() for s in sentences if s.strip()]

    # 计算每个句子的得分
    sentence_scores = []
    keyword_set = set([kw[0] for kw in keywords])

    for sentence in sentences:
        score = 0
        # 包含关键词的句子得分更高
        for keyword, weight in keywords:
            if keyword in sentence:
                score += weight * 10
        # 句子长度适中得分更高
        if 20 <= len(sentence) <= 100:
            score += 5
        sentence_scores.append((sentence, score))

    # 按得分排序
    sentence_scores.sort(key=lambda x: x[1], reverse=True)
    selected_sentences = [s[0] for s in sentence_scores[:num_sentences]]

    return '。'.join(selected_sentences) + '。'
```

### 适用场景
- 快速浏览大量新闻
- 实时监控系统
- 资源受限的环境
- 需要准确性的场景

## 2. 生成式摘要 (Abstractive Summarization)

### 原理

生成式摘要使用深度学习模型,理解原文内容并生成新的句子作为摘要。核心思想是:
1. 将原文编码为向量表示
2. 使用解码器生成摘要
3. 摘要是新生成的句子,不一定在原文中出现

### 优点
- 摘要更连贯、更自然
- 可以压缩信息,去除冗余
- 可以生成比原文更短的摘要

### 缺点
- 计算资源需求高
- 可能产生虚假信息(幻觉)
- 需要训练好的模型

### 实现方法

#### 方法 1: 使用 HuggingFace Transformers 库

```python
from transformers import pipeline

def abstractive_summarize(text, model="google/mt5-small-chinese", max_length=150):
    """
    使用预训练模型生成生成式摘要

    Args:
        text: 原文文本
        model: 模型名称
        max_length: 摘要最大长度

    Returns:
        摘要文本
    """
    # 初始化摘要管道
    summarizer = pipeline("summarization", model=model, device=-1)

    # 生成摘要
    summary = summarizer(
        text,
        max_length=max_length,
        min_length=30,
        do_sample=False
    )

    return summary[0]['summary_text']
```

#### 推荐的中文摘要模型

1. **google/mt5-small-chinese**
   - 基于 mT5 模型
   - 支持中文摘要
   - 轻量级,推理速度快

2. **csebuetnlp/mT5_multilingual_XLSum**
   - 多语言摘要模型
   - 支持中文
   - 在 XLSum 数据集上训练

3. **Helsinki-NLP/opus-mt-zh-en**
   - 中英翻译模型
   - 可用于跨语言摘要

#### 使用示例

```python
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM

def load_summarizer(model_name):
    """
    加载摘要模型和分词器

    Args:
        model_name: 模型名称或路径

    Returns:
        tokenizer, model
    """
    tokenizer = AutoTokenizer.from_pretrained(model_name)
    model = AutoModelForSeq2SeqLM.from_pretrained(model_name)
    return tokenizer, model

def generate_summary(tokenizer, model, text, max_length=150):
    """
    生成摘要

    Args:
        tokenizer: 分词器
        model: 模型
        text: 原文文本
        max_length: 摘要最大长度

    Returns:
        摘要文本
    """
    # 分词
    inputs = tokenizer(text, max_length=512, truncation=True, return_tensors="pt")

    # 生成摘要
    summary_ids = model.generate(
        inputs["input_ids"],
        max_length=max_length,
        min_length=30,
        length_penalty=2.0,
        num_beams=4,
        early_stopping=True
    )

    # 解码
    summary = tokenizer.decode(summary_ids[0], skip_special_tokens=True)
    return summary

# 使用示例
tokenizer, model = load_summarizer("google/mt5-small-chinese")
text = "这是一段长新闻文本..."
summary = generate_summary(tokenizer, model, text)
print(summary)
```

### 适用场景
- 生成高质量的新闻摘要
- 需要自然语言的场景
- 深度分析报告
- 用户界面展示

## 3. 混合方法 (Hybrid Summarization)

结合提取式和生成式摘要的优点:

```python
def hybrid_summarize(text):
    """
    混合摘要方法:先用提取式筛选重要句子,再用生成式改写

    Args:
        text: 原文文本

    Returns:
        摘要文本
    """
    # 第一步:提取式摘要获取关键句子
    key_sentences = keyword_based_summarize(text, num_sentences=5)

    # 第二步:生成式摘要改写
    summary = abstractive_summarize(key_sentences, max_length=150)

    return summary
```

## 4. 评估方法

### ROUGE 指标

ROUGE (Recall-Oriented Understudy for Gisting Evaluation) 是常用的摘要评估指标。

```python
from rouge import Rouge

def evaluate_summary(generated_summary, reference_summary):
    """
    使用 ROUGE 指标评估摘要质量

    Args:
        generated_summary: 生成的摘要
        reference_summary: 参考摘要

    Returns:
        ROUGE 分数
    """
    rouge = Rouge()
    scores = rouge.get_scores(generated_summary, reference_summary)
    return scores
```

### 人工评估
- 信息完整性
- 准确性
- 可读性
- 连贯性

## 5. 性能优化

### 批量处理

```python
def batch_summarize(texts, batch_size=8):
    """
    批量生成摘要

    Args:
        texts: 文本列表
        batch_size: 批次大小

    Returns:
        摘要列表
    """
    summaries = []
    for i in range(0, len(texts), batch_size):
        batch = texts[i:i+batch_size]
        # 使用 GPU 加速
        batch_summaries = [summarize(text) for text in batch]
        summaries.extend(batch_summaries)
    return summaries
```

### 缓存机制

```python
from functools import lru_cache

@lru_cache(maxsize=1000)
def cached_summarize(text):
    """
    带缓存的摘要生成

    Args:
        text: 原文文本

    Returns:
        摘要文本
    """
    return abstractive_summarize(text)
```

## 6. 实际应用建议

### 选择依据

| 场景 | 推荐方法 | 原因 |
|------|---------|------|
| 实时监控 | 提取式 | 速度快,资源消耗低 |
| 深度分析 | 生成式 | 质量高,连贯性好 |
| 大规模处理 | 提取式 | 效率高,可批量处理 |
| 用户展示 | 生成式 | 自然度高,体验好 |
| 准确性优先 | 提取式 | 基于原文,无幻觉 |

### 参数调优

1. **摘要长度**
   - 新闻摘要: 100-150 字
   - 快速浏览: 50-80 字
   - 深度分析: 200-300 字

2. **模型选择**
   - 轻量级: mT5-small
   - 高质量: mT5-base, BART
   - 特定领域: 微调模型

3. **后处理**
   - 去除重复句子
   - 修正语法错误
   - 调整句子顺序

## 7. 常见问题

### Q: 提取式摘要不够连贯怎么办?
A: 可以使用句子重排序或使用生成式摘要改写提取的句子。

### Q: 生成式摘要产生虚假信息怎么办?
A: 可以:
- 使用事实一致性检查
- 限制摘要长度
- 添加源文档作为输入
- 使用校验模型

### Q: 如何提高摘要质量?
A: 可以:
- 使用更大的模型
- 在特定领域数据上微调
- 结合提取式和生成式
- 优化超参数

### Q: 如何处理长文档?
A: 可以:
- 分段摘要
- 层次化摘要
- 先提取关键段落再摘要


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)