资讯动态

Python新闻追踪器:基于网络爬虫与关键词过滤的个性化信息聚合工具

发布时间:2026/9/9 13:16:29 来源:尧图企业网站定制
1. 项目概述一个新闻追踪器的诞生与价值最近在整理自己的信息流时发现了一个挺普遍的问题每天被各种App推送的新闻轰炸但真正想持续跟进的某个特定事件、某个公司动态或者某个技术领域的最新进展却总是淹没在信息洪流里。手动去各个网站搜索效率低不说还容易遗漏。于是一个想法就冒了出来——能不能自己写个工具让它自动帮我追踪我关心的新闻并且把结果整理好推送给我这就是newstracer这个项目最初的由来。简单来说newstracer是一个基于Python的新闻追踪与聚合工具。它的核心功能是你可以给它一个或多个你关心的“关键词”或“主题”它会定期比如每天或每小时自动去指定的新闻源如主流新闻网站、科技博客、RSS订阅源进行抓取和扫描然后通过智能过滤和去重将包含这些关键词的最新报道或文章通过邮件、即时通讯工具如Telegram Bot或者直接生成一个摘要页面推送给你。它解决的核心痛点就是信息过载下的精准获取让你从被动的信息接收者变为主动的信息管理者。这个项目特别适合几类朋友一是对某个垂直领域如人工智能、金融市场、特定行业政策需要保持高度敏感度的从业者或研究者二是关注特定公司或产品动态的市场、产品人员三是像我一样的普通用户只是想更高效地跟进几个长期兴趣点避免在无关信息上浪费时间。从技术上看它涉及网络爬虫、文本处理、任务调度和消息推送等多个环节是一个典型的“胶水”项目能把多个实用的技术点串联起来解决一个实际需求。2. 核心设计思路与技术选型2.1 需求拆解与架构设计动手之前我先仔细拆解了一下需求。一个新闻追踪器听起来简单但细想下来有几个关键模块必须处理好数据获取Crawler/ Fetcher从哪里获取新闻频率如何如何应对网站反爬内容解析与过滤Parser Filter抓回来的HTML页面或RSS源如何提取出干净的标题、正文、发布时间如何根据我设定的关键词进行过滤去重与存储Deduplicator Storage同一条新闻可能被多个源报道如何识别并去重历史数据存哪里方便后续查询或分析趋势通知推送Notifier过滤后的新内容通过什么渠道、以什么格式通知我任务调度Scheduler如何让整个流程自动化、周期性地运行基于这些模块我设计了一个简单清晰的数据流架构调度器触发抓取任务 - 抓取器从各新闻源获取原始数据 - 解析器提取结构化信息 - 过滤器根据关键词匹配 - 去重器对比历史记录 - 将新内容存入数据库并触发推送器。整个架构是松耦合的每个模块都可以独立替换或升级比如今天用RSS源明天可以增加API接口今天推邮件明天可以加个钉钉机器人。2.2 关键技术栈选型与考量技术选型上我遵循“成熟、高效、易于维护”的原则主要基于Python生态。爬虫与解析requestsBeautifulSoup4这是处理静态网页的黄金组合。requests负责网络请求简单易用BeautifulSoup4负责解析HTML定位并提取所需数据。对于大多数新闻网站这套组合拳足够用了。feedparser对于提供了RSS/Atom订阅源的网站这是首选。它比解析HTML更稳定、更规范能直接获取结构化的标题、链接、摘要和发布时间极大降低了开发复杂度。备用方案Selenium/Playwright考虑到一些现代网站大量使用JavaScript渲染纯requests无法获取内容。我预留了使用无头浏览器Headless Browser的接口。但这会显著增加资源消耗和运行时间所以仅作为针对特定“顽固”目标的备选方案。文本处理与过滤核心正则表达式与字符串操作初级的关键词过滤直接用in操作符或正则表达式匹配标题和正文即可。为了更灵活我支持了多种匹配模式如全词匹配、模糊匹配包含子串、以及多个关键词的“与/或”逻辑组合。进阶jieba分词与TF-IDF可选如果需求升级比如想追踪一个“概念”而非具体关键词例如追踪“量子计算”相关的所有文章而不仅限于出现这四个字的可以引入中文分词库jieba和简单的TF-IDF算法来计算文章与主题的相关性。在newstracer的初期版本中我将其作为可扩展的插件点并未强制集成以保持核心轻量。数据存储SQLite项目首选。它是一个单文件数据库无需安装和配置独立的数据库服务非常适合这种个人使用的、数据量不大的工具。我用它来存储已抓取文章的唯一标识如URL的MD5值、标题、链接、来源、抓取时间等主要用于去重和历史查询。可选Redis如果未来需要实现更快的去重判断基于内存的集合操作或者做简单的缓存Redis是很好的选择。目前用SQLite的简单表查询已能满足需求。任务调度schedule库一个轻量级的、人性化的Python任务调度库。可以用类似schedule.every(1).hours.do(job)这样的语法来定义周期任务非常直观。它运行在单进程中适合本机或服务器上作为常驻脚本运行。系统级方案Cron (Linux/macOS) 或 Task Scheduler (Windows)更传统和可靠的方式。将Python脚本写好然后用系统的定时任务工具来调用。这种方式与程序本身解耦更利于管理和监控。newstracer的设计兼容这两种方式脚本可以一次性运行也可以被外部调度器周期性触发。消息推送电子邮件 (smtplibemail)最通用、最稳定的方式。几乎人人都有邮箱手机也能实时提醒。我实现了通过SMTP服务器发送HTML格式的邮件可以将多条新闻整理成一个美观的摘要。Telegram Bot实时性更强交互也更方便。Telegram提供了非常友好的Bot API可以很方便地实现发送消息、甚至接收一些简单指令如临时添加关键词。这对于希望随时收到提醒的用户体验更好。其他架构上留出了推送接口理论上可以接入钉钉、企业微信、Slack等任何支持Webhook的通讯工具。注意在编写爬虫时务必遵守网站的robots.txt协议并设置合理的请求间隔如每次请求后time.sleep(2-5)秒避免对目标服务器造成压力这也是基本的网络礼仪和规避反爬虫策略的有效手段。3. 核心模块实现与实操详解3.1 新闻源配置与抓取器实现新闻追踪的源头是新闻源。我设计了一个灵活的配置系统支持多种类型的源。1. RSS/Atom 源配置这是最推荐的方式。在配置文件如sources.yaml或sources.json里可以这样配置rss_sources: - name: Solidot url: https://www.solidot.org/index.rss category: 科技 - name: Reuters Technology url: http://feeds.reuters.com/reuters/technologyNews category: 科技 language: en抓取器会遍历这个列表使用feedparser解析每个URL。feedparser.parse(url)返回一个包含所有条目的对象我们可以轻松地获取entry.title,entry.link,entry.published发布时间需解析和entry.summary摘要。2. 自定义爬虫针对无RSS的网站对于没有RSS的网站需要编写特定的抓取和解析函数。例如抓取某个新闻板块import requests from bs4 import BeautifulSoup def crawl_custom_news(): url https://example.com/news headers {User-Agent: Mozilla/5.0...} # 模拟浏览器头 try: resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() # 检查请求是否成功 soup BeautifulSoup(resp.content, html.parser) news_list [] # 假设新闻在 div classnews-item 里 for item in soup.select(div.news-item): title_elem item.select_one(h2 a) if not title_elem: continue title title_elem.text.strip() link title_elem[href] # 补全可能为相对路径的链接 if link.startswith(/): link requests.compat.urljoin(url, link) # 尝试获取发布时间 time_elem item.select_one(.time) pub_time parse_time(time_elem.text) if time_elem else None news_list.append({title: title, link: link, pub_time: pub_time}) return news_list except requests.RequestException as e: print(f抓取 {url} 失败: {e}) return []这里的关键在于使用select或find方法通过CSS选择器或标签属性精准定位到需要的元素。每个网站的页面结构都不同所以每新增一个此类源都需要单独分析其HTML结构并编写解析逻辑。建议将每个源的解析函数独立成模块便于维护。3.2 内容过滤与关键词匹配引擎抓取到文章列表后下一步是根据用户兴趣进行过滤。我实现了一个可配置的过滤引擎。基础关键词匹配用户在配置文件中定义自己关心的关键词列表以及匹配规则。keywords: - 人工智能 - AI - 大模型 - LLM match_mode: or # 匹配模式or (任一关键词命中) 或 and (全部关键词命中) case_sensitive: false # 是否区分大小写过滤函数会遍历每篇文章的标题和摘要或正文如果已抓取检查是否包含列表中的关键词。match_mode为or时只要包含任意一个关键词即视为匹配为and时则需包含所有关键词适用于非常精确的主题。进阶正则表达式与排除词为了更灵活我支持了正则表达式模式并增加了“排除词”功能。keyword_patterns: - pattern: 苹果(公司|发布会)? is_regex: true # 使用正则匹配能匹配“苹果”、“苹果公司”、“苹果发布会” exclude_words: - 吃的苹果 # 排除与水果苹果相关的内容这样当匹配到“苹果”时如果文章内容中也出现了“吃的苹果”这条新闻可能会被过滤掉取决于排除逻辑的严格程度。这能有效减少误报。实操心得关键词的设置是一门艺术。太宽泛如“科技”会抓到太多无关信息太具体如某个产品的完整型号可能会遗漏相关报道。我的建议是从核心术语开始逐步根据推送结果进行调整。例如追踪“电动汽车”时可以同时加上“特斯拉”、“比亚迪”、“蔚来”等具体品牌以及“电池”、“续航”、“自动驾驶”等相关技术词形成一个小的关键词网络。3.3 持久化存储与高效去重策略为了避免重复推送同一条新闻并保留历史记录存储和去重是必不可少的。1. 数据库设计我使用SQLite创建了一张简单的articles表。CREATE TABLE IF NOT EXISTS articles ( id INTEGER PRIMARY KEY AUTOINCREMENT, url_hash TEXT UNIQUE NOT NULL, -- 文章URL的哈希值用于去重唯一标识 title TEXT NOT NULL, url TEXT NOT NULL, source TEXT NOT NULL, published_at TIMESTAMP, -- 新闻发布时间 fetched_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 抓取时间 summary TEXT -- 摘要或正文片段 );url_hash字段是去重的关键。通常对文章的URL进行MD5或SHA256哈希生成一个固定长度的字符串作为唯一标识。相比直接存储URL哈希值长度固定索引效率更高。2. 去重流程每次抓取并过滤出一批新文章后在存入数据库前先计算每个文章的url_hash然后查询数据库中是否已存在。import hashlib import sqlite3 def get_url_hash(url): return hashlib.md5(url.encode(utf-8)).hexdigest() def is_duplicate(conn, url_hash): cursor conn.cursor() cursor.execute(SELECT 1 FROM articles WHERE url_hash ?, (url_hash,)) return cursor.fetchone() is not None只有is_duplicate返回False的文章才会被插入数据库并加入待推送列表。3. 存储优化考虑索引务必在url_hash字段上创建索引可以极大加速去重查询的速度。CREATE INDEX idx_url_hash ON articles (url_hash);数据清理新闻的时效性很强可以定期比如每月清理3个月或更久以前的数据控制数据库大小。可以在调度任务中增加一个清理子任务。3.4 多渠道通知推送实现将过滤后的新文章推送给用户是价值实现的最后一步。我实现了邮件和Telegram Bot两种主要方式。1. 邮件推送使用Python内置的smtplib和email库。需要先配置发件邮箱的SMTP服务器信息如QQ邮箱、163邮箱或Gmail的SMTP。import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart from datetime import datetime def send_email(subject, html_content, to_emails, smtp_config): msg MIMEMultipart(alternative) msg[Subject] subject msg[From] smtp_config[sender] msg[To] , .join(to_emails) # 创建HTML版本 html_part MIMEText(html_content, html, utf-8) msg.attach(html_part) try: with smtplib.SMTP_SSL(smtp_config[host], smtp_config[port]) as server: server.login(smtp_config[user], smtp_config[password]) server.send_message(msg) print(f[{datetime.now()}] 邮件发送成功) except Exception as e: print(f[{datetime.now()}] 邮件发送失败: {e})可以设计一个漂亮的HTML模板将多条新闻以列表形式清晰展示包含标题带链接、来源、时间和简短摘要。2. Telegram Bot推送首先需要在Telegram上找BotFather创建一个Bot获取API Token。import requests TELEGRAM_BOT_TOKEN YOUR_BOT_TOKEN TELEGRAM_CHAT_ID YOUR_CHAT_ID # 你的个人或群组Chat ID def send_telegram_message(text): url fhttps://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage payload { chat_id: TELEGRAM_CHAT_ID, text: text, parse_mode: HTML # 支持简单HTML格式如加粗、链接 } try: resp requests.post(url, jsonpayload, timeout10) resp.raise_for_status() return True except requests.RequestException as e: print(fTelegram推送失败: {e}) return FalseTelegram消息更即时适合推送突发新闻。可以将多条新闻合并成一条消息发送避免刷屏。更高级的玩法可以让Bot接收命令动态修改追踪关键词。提示无论是邮箱密码还是Telegram Bot Token都属于敏感信息。绝对不要将它们硬编码在脚本里或提交到公开的代码仓库。务必使用环境变量或单独的配置文件如config.ini并将该配置文件加入.gitignore。4. 系统集成、部署与自动化运行4.1 配置管理与项目组织一个清晰的项目结构能让维护变得轻松。我的newstracer项目目录大致如下newstracer/ ├── config/ │ ├── config.yaml # 主配置数据库路径、推送方式、全局开关 │ └── sources.yaml # 新闻源定义 ├── core/ │ ├── __init__.py │ ├── fetcher.py # 抓取器抽象与RSS/自定义爬虫实现 │ ├── parser.py # 内容解析器 │ ├── filter.py # 关键词过滤引擎 │ ├── deduplicator.py # 去重逻辑与数据库交互 │ ├── notifier.py # 邮件、Telegram等推送器 │ └── scheduler.py # 任务调度封装 ├── scripts/ │ └── run_tracer.py # 主运行脚本 ├── data/ │ └── news.db # SQLite数据库文件.gitignore忽略 ├── logs/ # 日志目录.gitignore忽略 ├── requirements.txt # Python依赖列表 └── README.md # 项目说明文档config.yaml示例database: path: ./data/news.db notification: email: enabled: true smtp_host: smtp.example.com smtp_port: 465 sender: your-emailexample.com receivers: - receiver1example.com telegram: enabled: false # 按需开启 bot_token: YOUR_TOKEN chat_id: YOUR_CHAT_ID schedule: interval_minutes: 60 # 每60分钟运行一次当使用schedule库时通过配置文件可以灵活地开关功能、调整参数而无需修改代码。4.2 主流程串联与错误处理主脚本run_tracer.py的工作流非常直接# run_tracer.py import logging from core.fetcher import fetch_all_articles from core.filter import filter_articles from core.deduplicator import Deduplicator from core.notifier import notify_new_articles def main(): # 1. 初始化日志和去重器 logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) deduper Deduplicator(config/database_path) # 2. 抓取所有配置源的文章 all_raw_articles fetch_all_articles() logging.info(f共抓取到 {len(all_raw_articles)} 条原始文章。) # 3. 关键词过滤 filtered_articles filter_articles(all_raw_articles) logging.info(f关键词过滤后剩余 {len(filtered_articles)} 条。) # 4. 去重 new_articles [] for article in filtered_articles: if not deduper.is_duplicate(article[url]): deduper.save_article(article) new_articles.append(article) logging.info(f去重后新增 {len(new_articles)} 条文章。) # 5. 推送新文章 if new_articles: notify_new_articles(new_articles) else: logging.info(没有新文章需要推送。) if __name__ __main__: main()错误处理是保证长期稳定运行的关键。在上述每个步骤网络请求、解析、数据库操作、网络推送都需要用try...except包裹并记录详细的错误日志而不是让整个程序崩溃。例如某个新闻源临时不可用应该记录错误并跳过继续处理其他源。4.3 部署方案从本地到服务器如何让这个脚本“永远”在后台运行本地开发/测试直接运行python run_tracer.py。可以使用schedule库让脚本循环运行或者更简单地用while True循环配合time.sleep(interval)。个人电脑后台运行macOS/Linux使用nohup命令nohup python run_tracer.py tracer.log 21 。这样即使关闭终端脚本也会在后台运行日志输出到tracer.log。使用tmux或screen会话创建一个持久化的会话运行脚本可以随时断开和重连查看。服务器部署推荐使用系统Cron这是最稳定、最标准的方式。将脚本修改为一次性任务即运行一次就结束然后通过Cron定时调用。# 编辑当前用户的cron任务 crontab -e # 添加一行例如每30分钟运行一次 */30 * * * * cd /path/to/newstracer /usr/bin/python3 run_tracer.py /path/to/newstracer/cron.log 21使用Supervisor进程管理如果脚本需要作为常驻进程例如内部使用了schedule库循环可以用Supervisor来管理它能保证进程意外退出后自动重启并方便地管理日志。; /etc/supervisor/conf.d/newstracer.conf [program:newstracer] command/usr/bin/python3 /path/to/newstracer/run_tracer.py directory/path/to/newstracer autostarttrue autorestarttrue stderr_logfile/var/log/newstracer.err.log stdout_logfile/var/log/newstracer.out.log容器化部署Docker为了环境一致性可以创建Docker镜像。编写Dockerfile安装依赖设置启动命令为python run_tracer.py然后使用Cron或Kubernetes的CronJob来调度容器运行。这对于在云服务器上管理多个此类小工具非常整洁。5. 常见问题排查与优化经验5.1 抓取失败与反爬虫应对问题1请求被拒绝返回403或429状态码。原因网站检测到爬虫行为如无User-Agent、请求过快。解决设置合理的请求头始终在requests.get()中模拟一个常见的浏览器User-Agent。添加延迟在连续请求之间加入随机延时例如time.sleep(random.uniform(2, 5))。使用代理IP池针对严格封锁对于大规模抓取可能需要轮换使用不同的IP地址。个人小规模使用通常不需要。尊重robots.txt使用urllib.robotparser检查目标网站是否允许爬取特定路径。问题2页面内容为空或结构不符解析失败。原因网站改版或内容由JavaScript动态加载。解决定期检查与更新解析规则自定义爬虫的解析逻辑CSS选择器需要随网站改版而更新。切换到无头浏览器对于JS渲染的页面使用Selenium或Playwright。但这会慢很多仅作为最后手段。可以先检查网站是否有“移动版”或“简化版”页面这些页面通常结构更简单。寻找替代源看看该网站是否提供了官方的RSS源或API这是最稳定友好的方式。5.2 误报与漏报的调优问题推送的内容不相关误报或者相关的内容没抓到漏报。原因关键词设置不合理或者过滤只在标题/摘要进行。优化精细化关键词使用更长的短语、添加排除词、利用正则表达式精确匹配。引入摘要或正文分析如果RSS只提供标题漏报率会很高。可以考虑抓取文章链接的正文前几段进行分析但这会增加抓取负担和复杂度。一个折中方案是对初步过滤后的文章再发起一次轻量级请求获取摘要。人工反馈循环在推送的消息里可以加入“这条不相关”的快速反馈按钮Telegram Bot可以做到。收集这些反馈用来动态调整关键词权重或作为训练数据如果未来想引入机器学习模型。5.3 性能与稳定性提升问题随着追踪源增多单次运行时间变长可能错过实时性。优化异步抓取使用aiohttp和asyncio库进行异步HTTP请求可以同时抓取多个新闻源极大缩短总抓取时间。增量抓取与缓存对于RSS源可以记录上次抓取的最新条目发布时间下次只请求比这个时间更新的条目。对于自定义爬虫可以分析网站的分页或时间归档规律进行增量抓取。数据库连接池与批量操作如果推送量很大频繁开关数据库连接会影响性能。可以使用连接池并在去重和保存时采用批量操作executemany。问题脚本运行一段时间后内存占用高或意外退出。解决资源释放确保数据库连接、网络会话在使用后正确关闭。使用with语句上下文管理器是很好的习惯。异常捕获与日志在最外层进行异常捕获记录错误并优雅退出或重试避免静默崩溃。使用进程管理工具如前所述使用Supervisor或systemd来管理进程可以自动重启失败的脚本。5.4 扩展思路与高级玩法当基础功能稳定后可以考虑一些扩展方向让工具更强大情感分析与趋势判断对抓取到的新闻正文进行简单的情感分析使用预训练模型或词典判断舆论是正面还是负面。长期积累数据后可以绘制某个关键词的“舆情热度趋势图”。多语言支持使用翻译API如Google Translate API或开源库将外文新闻的关键部分翻译后推送实现跨语言信息追踪。生成式摘要对于长篇报道可以调用大模型的API如ChatGPT、文心一言等生成一段简洁的要点摘要附在推送信息里节省阅读时间。可视化仪表盘将数据库中的历史数据用Flask或Streamlit做成一个简单的Web仪表盘展示新闻数量随时间的变化、不同来源的占比等。协同过滤与推荐如果有多人使用可以匿名收集大家的订阅关键词和点击行为实现简单的“关注了X的人也关注了Y”的推荐功能。这个项目的魅力在于它从一个具体的个人需求出发串联起了软件开发的多个核心环节需求分析、架构设计、编码实现、部署运维。你可以根据自己的技术兴趣在其中任何一个环节进行深化和拓展。它可能永远只是一个“小工具”但正是这些解决实际问题的“小工具”构成了我们数字生活的高效基石。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价