DewXIT/osint-feed

GitHub: DewXIT/osint-feed

一个基于配置驱动的 Node.js 新闻采集器,从 RSS 和 HTML 页面抓取文章、自动去重并生成可直接注入 LLM 上下文的紧凑摘要。

Stars: 2 | Forks: 0

# osint-feed 基于配置驱动的 Node.js 新闻采集器。从 RSS 订阅源和 HTML 页面中提取文章,进行去重处理,并生成准备注入 LLM 上下文窗口的紧凑摘要。 内部不包含 AI。不对你的技术栈做任何假设。只需文章输入,结构化数据输出。 有 RSS 时使用 RSS。没有时使用 HTML 选择器。针对特定主题的过滤应由调用此库的应用程序负责处理。 ## 为什么需要它 你正在构建需要最新新闻上下文的应用——例如 SITREP(态势报告)生成器、威胁监控器或研究助手。你拥有 30 多个跨语言和格式的信息源。你需要将数据压缩得足够紧凑,以便在 Llama/GPT 上下文窗口中运行而不超支预算。 现有工具要么仅支持 Python (newspaper4k),要么是需要大量维护的自托管平台,要么是商业 API (Newscatcher, NewsAPI)。在 JS/TS 生态系统中,没有哪种工具能实现配置驱动的多源采集并内置适配 LLM 的压缩功能。 `osint-feed` 填补了这一空白。 ## 安装 ``` npm install osint-feed ``` 需要 Node.js 18+。 ## 快速开始 ``` import { createHarvester } from "osint-feed"; const harvester = createHarvester({ sources: [ { id: "bbc-world", name: "BBC World", type: "rss", url: "https://feeds.bbci.co.uk/news/world/rss.xml", tags: ["global", "uk"], interval: 15, }, { id: "nato", name: "NATO Newsroom", type: "html", url: "https://www.nato.int/cps/en/natohq/news.htm", tags: ["nato"], interval: 30, selectors: { article: ".event-list-item", title: "a span:first-child", link: "a", date: ".event-date", }, }, ], }); // Fetch everything const articles = await harvester.fetchAll(); // Or get an LLM-ready digest const { articles: digest, stats } = await harvester.digest(); console.log(`${stats.totalFetched} articles -> ${stats.afterDedup} unique -> ${stats.estimatedTokens} tokens`); ``` ## 源类型 ### RSS / Atom 开箱即用。无需选择器——订阅源会被自动解析。 ``` { id: "france24", name: "France24", type: "rss", url: "https://www.france24.com/en/rss", tags: ["global", "europe"], interval: 15, } ``` ### HTML 抓取 你可为每个源定义 CSS 选择器。该库使用 [cheerio](https://github.com/cheeriojs/cheerio)——无需无头浏览器,也没有 Puppeteer 的开销。 这依然是配置驱动的抓取:该库不会自动发现文章列表或推断哪些内容与你的用例相关。 ``` { id: "defence24", name: "Defence24", type: "html", url: "https://defence24.pl/", tags: ["poland", "defence"], interval: 15, selectors: { article: "article", // repeating container title: "h2 a", // title text (within article) link: "h2 a", // link href (within article) date: "time", // optional: publication date summary: ".lead", // optional: description text }, } ``` ## API ### `createHarvester(options)` 创建采集器实例。选项: | 选项 | 类型 | 默认值 | 描述 | |--------|------|---------|-------------| | `sources` | `SourceConfig[]` | 必填 | 源定义数组 | | `dedup.known` | `() => string[]` | — | 返回数据库中已存在的哈希值(用于跨会话去重) | | `digest` | `DigestOptions` | 见下文 | 默认摘要设置 | | `requestTimeout` | `number` | `15000` | HTTP 超时时间(毫秒) | | `requestGap` | `number` | `1000` | 请求之间的最小间隔毫秒数(速率限制) | | `maxItemsPerSource` | `number` | `50` | 单个源返回的文章数上限 | | `fetch` | `Function` | global fetch | 用于代理或测试的自定义 fetch 函数 | | `onError` | `Function` | — | 每个源的获取或解析错误的回调 | | `onWarning` | `Function` | — | 非致命源诊断信息的回调 | ### `harvester.fetchAll()` 获取所有已启用的源。返回 `Article[]`。 如果其中一个源失败,该方法仍会返回其他源的文章,并在提供 `onError` 的情况下报告问题。 ### `harvester.fetch(sourceId)` 按 ID 获取单个源。 ### `harvester.fetchByTags(tags)` 获取匹配任意给定标签的源。 ### `harvester.digest(options?)` 核心功能。获取所有源,然后运行压缩流水线: 1. **去重** — 将相似的标题分组(基于 Jaccard 相似度)并保留内容最丰富的版本 2. **排序** — 最新优先 3. **标签预算** — 限制每个标签的文章数量,以免单一主题占据主导 4. **截断** — 将每篇文章的内容截断至 N 个字符 5. **Token 预算** — 从底部开始修剪,直到低于 token 限制 ``` const { articles, stats } = await harvester.digest({ maxTokens: 12_000, // total token budget maxArticlesPerTag: 10, // max articles per tag group maxContentLength: 500, // chars per article content similarityThreshold: 0.6, // title dedup threshold (0-1) sort: "recency", }); // stats.totalFetched → 700 (raw from all sources) // stats.afterDedup → 200 (unique stories) // stats.afterBudget → 80 (within tag limits) // stats.estimatedTokens → 18000 (final token count) ``` ### `harvester.start(callbacks)` / `harvester.stop()` 按配置的间隔运行源。由你自行处理存储。 ``` harvester.start({ onArticles: async (articles, source) => { await db.insert("articles", articles); console.log(`${articles.length} new from ${source.name}`); }, onError: (err, source) => { console.error(`${source.name} failed:`, err); }, onWarning: (warning, source) => { console.warn(`${source.name}: ${warning.code} - ${warning.message}`); }, }); // Later: harvester.stop(); ``` ## 文章 Schema ``` interface Article { sourceId: string; // matches source config id url: string; // canonical article URL title: string; content: string | null; // full text (when available) summary: string | null; // short description publishedAt: Date | null; hash: string; // SHA-256 of URL (dedup key) fetchedAt: Date; tags: string[]; // inherited from source } ``` ## 跨会话去重 该库会自动处理批次内的去重。对于跨会话去重(不重复处理数据库中已有的文章),请传入 `known` 回调: ``` const harvester = createHarvester({ sources, dedup: { known: async () => { const rows = await db.query("SELECT hash FROM articles"); return rows.map(r => r.hash); }, }, }); // fetchAll() now skips articles whose URL hash is already known ``` ## 诊断 该库保持了正常路径的简洁性:`fetchAll()` 和 `digest()` 依然直接返回文章数据。 如果你希望了解部分失败或低质量源输出的情况,请使用 `onError` 和 `onWarning`。 - `onError` 涵盖诸如超时、HTTP 错误和解析失败等严重错误。 - `onWarning` 涵盖诸如源结果为空、缺少发布日期或单源截断等非致命问题。 这符合典型的小型库 OSS 模式:易于使用的默认值,为日志和监控提供的可选钩子。 ## 范围与限制 - RSS 和 HTML 是一等源类型。 - 当你能定义稳定的列表选择器时,HTML 效果最佳。 - 该库不执行页面 JavaScript 或运行无头浏览器。 - 该库不决定哪些内容与你的领域相关;请在下游应用你自己的过滤器。 ## 配合 Next.js 使用 ``` // app/api/feed/route.ts import { createHarvester } from "osint-feed"; const harvester = createHarvester({ sources: [...] }); export async function GET() { const { articles, stats } = await harvester.digest({ maxTokens: 8000 }); return Response.json({ articles, stats }); } ``` ## 配合 Express 使用 ``` import express from "express"; import { createHarvester } from "osint-feed"; const app = express(); const harvester = createHarvester({ sources: [...] }); app.get("/digest", async (_req, res) => { const result = await harvester.digest(); res.json(result); }); ``` ## 摘要算法的工作原理 来自 10 个 RSS + 3 个 HTML 源冒烟测试的实际数据: ``` Raw fetch: 324 articles After title dedup: 319 unique stories After tag budget: 47 (8 per tag, 6 tags) Estimated tokens: 5,781 ``` 这仅占 **Llama 3 128k 上下文的 1.8%**。为系统提示词、历史记录和推理留足了空间。 如果 35 个源每 15 分钟轮询一次,你每小时将获得约 700 篇文章。摘要流水线会将其压缩至约 80 篇文章 / 约 1.8 万个 token。可根据需要调整 `maxArticlesPerTag` 和 `maxTokens`。 ## 依赖项 仅有两个: - [`cheerio`](https://github.com/cheeriojs/cheerio) — HTML 解析 - [`rss-parser`](https://github.com/rbren/rss-parser) — RSS/Atom 解析 没有无头浏览器。没有原生模块。没有臃肿代码。 ## 许可证 MIT ## 免责声明 本库是用于获取和解析公开可用的网络内容的工具。用户需自行负责遵守目标网站的服务条款及适用法律。作者对本库的使用方式不承担任何责任。
标签:DLL 劫持, ESC4, GNU通用公共许可证, HTTP/HTTPS抓包, LLM数据预处理, MITM代理, Node.js, npm包, OSINT, RSS解析, SITREP, TypeScript, URL抓取, 去重, 大语言模型, 威胁情报, 安全插件, 开发者工具, 态势感知, 情报收集, 数据可视化, 数据抓取, 数据清洗, 文本摘要, 新闻采集, 漏洞研究, 自动化攻击