1. 项目概述用Notion和GitHub Actions打造你的个人RSS信息中枢如果你和我一样每天需要从几十个博客、新闻源和技术社区获取信息但又苦于信息过载和分散管理那么这个项目可能就是你的“解药”。它不是一个复杂的商业软件而是一个完全由你掌控、部署在自己技术栈上的个人信息流自动化系统。核心思路非常清晰将Notion作为你的RSS源管理、内容筛选和最终阅读的中心数据库然后利用GitHub Actions这个免费的“机器人”定时去抓取、解析和过滤信息最后再把筛选后的精华内容自动同步回Notion形成一个完美的闭环。我最初被这个想法吸引是因为受够了各种在线RSS阅读器的限制——要么收费要么功能简陋要么数据不在自己手里。而Notion作为一个极其灵活的数据管理工具它的数据库Database功能天生就适合用来做信息归档和分类。rainyear/dailybot这个项目巧妙地将两者结合让你能用几行配置和零成本GitHub Actions免费额度足够日常使用搭建一个高度定制化的信息流管道。这个方案特别适合以下几类朋友技术爱好者/开发者希望完全掌控自己的数据流享受DIY的乐趣和灵活性。内容创作者/研究者需要持续追踪特定领域如AI、编程、设计的多个信息源并进行关键词过滤和归档。效率工具爱好者已经在使用Notion作为个人知识库希望将外部信息流无缝集成进来。追求零成本自动化的人不想为信息管理工具付费希望利用现有免费服务GitHub, Notion实现高级功能。接下来我将为你彻底拆解这个项目的每一个环节从核心设计思路到每一步的实操细节包括我踩过的坑和总结出的最佳实践让你能轻松复现并定制属于你自己的“Daily Bot”。1.1 核心需求与设计思路解析为什么是Notion GitHub Actions这个组合这背后是一套非常务实的设计哲学。1.1.1 为什么选择Notion作为信息中枢Notion不仅仅是一个笔记工具它的数据库功能才是真正的王牌。你可以把每个RSS源比如某个技术博客看作一张数据表Database里的一条记录而这条记录包含的字段Properties可以非常丰富RSS链接、分类标签、更新频率、是否启用等等。更重要的是当抓取到新的文章条目Entry时Notion可以自动创建新的页面Page来保存标题、链接、摘要、发布时间并且能通过“关联”Relation字段轻松地回溯到是哪个RSS源产生的。这种结构化的存储方式远比在某个阅读器里一堆未读标签要清晰和强大得多便于你日后搜索、筛选和建立知识关联。1.1.2 为什么选择GitHub Actions作为执行引擎自动化需要触发器。你可以写个脚本放在自己的电脑上定时跑但这意味着你的电脑必须一直开着。而GitHub Actions提供了免费的、云端调度的定时任务schedule cron job。你只需要把脚本和配置放在GitHub仓库里它就会在指定的时间比如每天凌晨2点自动启动一个干净的虚拟机环境执行你的抓取和同步脚本完成后自动关闭。整个过程完全无需你干预稳定、免费且可靠。对于每日一次的RSS抓取任务GitHub的免费额度绰绰有余。1.1.3 核心工作流程整个系统的数据流可以概括为以下几步配置阶段你在Notion中创建一个主数据库例如叫“RSS Feeds”里面记录所有你要追踪的RSS源信息。触发阶段GitHub Actions的定时任务被触发。抓取与解析阶段Action运行脚本通过Notion API读取“RSS Feeds”数据库获取所有活跃的RSS链接。过滤阶段脚本抓取每个RSS源的最新内容并根据你在Notion中为每个源配置的关键词例如只为某个AI博客过滤包含“LLM”或“Transformer”的文章进行筛选。回写阶段将筛选后的文章条目通过Notion API创建为新的页面保存到另一个专门用于阅读的数据库例如叫“RSS Entries”中并关联回源RSS记录。可选通知阶段如果配置了Bot如通过Deta等Serverless平台可以在有新文章时发送通知到Telegram、Slack等。这个设计的美妙之处在于所有的“逻辑配置”都留在了Notion这个界面友好的前端。你想增加一个源、修改关键词、临时禁用某个源都只需要在Notion表格里点几下下次自动化任务运行时就会自动生效。无需去修改复杂的脚本代码。2. 前期准备与环境搭建在开始写一行代码之前我们需要把“舞台”搭好。这主要包括在Notion端创建数据库、获取API权限以及在GitHub端创建仓库。2.1 Notion侧配置创建数据库与集成这是整个项目的控制中心所有配置都将在这里完成。2.1.1 创建Notion集成Integration并获取API密钥Notion集成相当于一个被授权访问你特定Notion页面的“机器人账户”。访问 Notion Developers 页面点击“ New integration”。为你的集成起个名字比如“My RSS Bot”。选择关联的工作区Workspace。点击“Submit”创建。创建成功后你会看到“Internal Integration Token”。请立即复制并妥善保存这个Token它只会显示一次。这就是你的NOTION_TOKEN脚本将通过它来与Notion对话。在这个集成页面你还可以配置其能力Capabilities通常保持默认的“Read content”和“Update content”即可。2.1.2 创建RSS管理数据库你需要至少两个数据库一个管理RSS源一个存放抓取到的文章。在你的Notion工作区新建一个页面。在页面中输入/database并选择 “Database - Full page” 或 “Database - Inline”。我们首先创建RSS源管理库命名为“RSS Feeds”。为这个数据库设计以下核心字段Properties你可以根据喜好调整类型和名字Name(Title类型): RSS源的名称如“TechCrunch”。URL(URL类型): RSS源的完整链接。Enabled(Checkbox类型): 一个开关用于临时禁用某个源而不删除它。Keywords(Text类型): 过滤关键词多个关键词可以用英文逗号分隔如“AI, Machine Learning”。注意原项目可能用多选类型但文本类型更灵活脚本中按逗号分割即可。Category(Select类型): 分类如“Technology”, “Design”, “News”。Last Fetched(Date类型): 记录上次成功抓取的时间用于脚本去重和日志。在这个数据库里手动添加几条你常用的RSS源记录并把“Enabled”勾选上。2.1.3 创建文章条目数据库并关联在同一页面或新页面再创建一个文章数据库命名为“RSS Entries”。为其设计字段Name(Title类型): 文章标题。URL(URL类型): 文章原文链接。Summary(Text类型): 文章摘要或内容片段。Published(Date类型): 文章发布时间。Source(Relation类型):这是关键创建这个字段时选择关联到刚才创建的“RSS Feeds”数据库。这样每篇文章都能知道它来自哪个源。Read(Checkbox类型): 标记是否已读。Saved(Checkbox类型): 标记是否收藏。分享数据库给集成这是最容易出错的一步。光有API Token你的“机器人”还没权限访问这些数据库。你需要分别打开“RSS Feeds”和“RSS Entries”数据库的页面点击右上角的“Share”按钮在邀请框中输入你刚才创建的集成名称如“My RSS Bot”并确保权限至少是“Can edit”。添加成功后你的集成就获得了这两个数据库的读写权限。注意每个Notion数据库都有一个唯一的database_id。获取方法是打开数据库页面浏览器的地址栏URL中在www.notion.so/之后、?v或?p之前的那一串字符就是。例如https://www.notion.so/yourworkspace/a1b2c3d4e5f67890123456789abcdef?v...那么a1b2c3d4e5f67890123456789abcdef就是该数据库的ID。请记下这两个数据库的ID后续配置会用到。2.2 GitHub侧配置创建仓库与Secrets我们将使用GitHub Actions来运行自动化脚本因此需要一个GitHub仓库来存放代码和配置。2.2.1 创建新仓库并初始化在GitHub上创建一个新的私有仓库Private Repository如果你不想公开你的配置和Notion Token的话。命名为my-daily-rss-bot或任何你喜欢的名字。将原项目rainyear/dailybot的代码克隆或下载到本地。你可以直接Fork原仓库但为了理解透彻我建议新建仓库并手动复制核心文件。核心文件通常包括.github/workflows/目录下的YAML文件如daily.yml定义了GitHub Actions的工作流程。脚本文件如sync.py或index.py包含主要的抓取、过滤和写入逻辑。配置文件如config.json或通过环境变量配置用于存放Notion数据库ID等。requirements.txtPython依赖列表。2.2.2 配置仓库机密Secrets为了安全地使用Notion Token等敏感信息我们必须将其设置为GitHub仓库的Secrets这样在Action运行时可以环境变量的形式注入而不会暴露在代码日志中。进入你的GitHub仓库页面点击 “Settings” - “Secrets and variables” - “Actions”。点击 “New repository secret”。创建以下机密NOTION_TOKEN: 值为你之前保存的Notion集成Token。NOTION_FEEDS_DATABASE_ID: 值为你的“RSS Feeds”数据库ID。NOTION_ENTRIES_DATABASE_ID: 值为你的“RSS Entries”数据库ID。可选如果你后续配置通知Bot可能还需要DETA_PROJECT_KEY等。现在Notion和GitHub的基础配置就完成了。接下来我们要深入核心看看自动化脚本是如何工作的。3. 核心脚本解析与定制化修改原项目提供了可运行的脚本但为了让它更好地为你服务理解其原理并进行必要的修正是关键。我们以典型的Python脚本为例进行拆解。3.1 脚本工作流程详解一个健壮的同步脚本通常会遵循以下步骤我将其概括为“读、抓、滤、写、记”五步3.1.1 读从Notion读取配置脚本首先使用NOTION_TOKEN和NOTION_FEEDS_DATABASE_ID调用Notion API查询“RSS Feeds”数据库。它会构造一个过滤器Filter只获取Enabled属性为true的记录。对于每一条RSS源记录脚本会读取Name,URL,Keywords等字段。Keywords字段是一个文本需要按逗号分割成列表以备后续过滤使用。3.1.2 抓抓取并解析RSS内容对于每个有效的RSS URL脚本会使用如feedparser或httpx这样的Python库发起网络请求获取RSS/Atom格式的XML数据并解析成一个结构化的对象。从中提取出本次抓取的所有文章条目每个条目通常包含title,link,published(或updated),summary(或description) 等字段。3.1.3 滤基于关键词和去重过滤这是提升信息质量的核心环节。过滤分为两层关键词过滤如果某个RSS源配置了关键词如“Python, Django”脚本会检查文章的标题或摘要中是否包含任何一个关键词不区分大小写。只有匹配的文章才会进入下一轮。如果关键词字段为空则默认放过所有文章。去重过滤为了避免在Notion中创建重复的文章记录脚本需要判断一篇文章是否已经存在。最可靠的方式是使用文章的URLlink作为唯一标识。在写入前脚本可以查询“RSS Entries”数据库中是否已存在相同URL的记录。更高效的做法是利用Notion数据库的“Last Fetched”时间戳只处理发布时间晚于该时间戳的文章这需要RSS源提供准确的发布时间。3.1.4 写将文章写入Notion对于通过过滤的文章脚本需要构造Notion API请求在“RSS Entries”数据库中创建新页面。创建页面时需要填充我们设计好的各个属性Name(title): 文章标题。URL(url): 文章链接。Summary(rich_text): 文章摘要。Published(date): 文章发布时间。Source(relation): 这里需要填入关联的“RSS Feeds”数据库中的对应页面的ID即page_id。这个ID在第一步读取源信息时就可以获取到。3.1.5 记更新状态与日志所有源处理完毕后良好的脚本应该更新“RSS Feeds”数据库中每个源的Last Fetched时间为当前时间以便下次抓取时参考。同时应该在GitHub Actions的运行日志中输出简要报告如“成功处理X个源新增Y篇文章跳过Z篇重复文章”便于排查问题。3.2 关键代码片段与避坑指南这里分享几个在实际编写或修改脚本时容易出错的关键点和我总结的解决方案。3.2.1 Notion API调用与分页查询Notion API对数据库的查询默认有分页限制最多100条结果。如果你的RSS源很多或者文章数据库很大需要处理分页。import requests NOTION_TOKEN os.environ.get(NOTION_TOKEN) DATABASE_ID os.environ.get(NOTION_FEEDS_DATABASE_ID) headers { Authorization: fBearer {NOTION_TOKEN}, Notion-Version: 2022-06-28, # 注意使用稳定的API版本 Content-Type: application/json } def query_notion_database(database_id, filter_conditionNone): url fhttps://api.notion.com/v1/databases/{database_id}/query all_results [] has_more True next_cursor None while has_more: payload {page_size: 100} if filter_condition: payload[filter] filter_condition if next_cursor: payload[start_cursor] next_cursor response requests.post(url, jsonpayload, headersheaders) response.raise_for_status() # 确保请求成功 data response.json() all_results.extend(data.get(results, [])) has_more data.get(has_more, False) next_cursor data.get(next_cursor, None) return all_results # 查询所有已启用的RSS源 filter_enabled { property: Enabled, checkbox: { equals: True } } feeds query_notion_database(DATABASE_ID, filter_enabled)注意务必处理网络请求异常如超时、断连和API响应错误如权限不足、频率限制。建议使用try...except包裹关键API调用并记录详细的错误信息到日志方便在GitHub Actions的界面查看。3.2.2 RSS解析的时区与日期处理不同RSS源提供的发布时间格式千奇百怪且可能包含时区信息。直接将其字符串存入Notion的Date类型可能会导致显示错误。最佳实践是将其统一解析为ISO 8601格式的字符串如2023-10-27T08:00:00.000Z。import feedparser import dateutil.parser # 需要安装 python-dateutil def parse_feed(feed_url): feed feedparser.parse(feed_url) entries [] for entry in feed.entries: # 处理标题和链接 title entry.get(title, No Title) link entry.get(link, ) # 处理发布时间优先使用published_parsed其次published published None if hasattr(entry, published_parsed): # 将time.struct_time转换为datetime对象 import datetime dt datetime.datetime(*entry.published_parsed[:6]) published dt.isoformat() Z # 转为ISO格式 elif hasattr(entry, published): try: # 尝试解析日期字符串 dt dateutil.parser.parse(entry.published) published dt.isoformat() except Exception as e: print(f无法解析日期 {entry.published}: {e}) published None # 处理摘要 summary entry.get(summary, entry.get(description, )) # 可以清理摘要中的HTML标签 from html import unescape import re summary unescape(summary) summary re.sub(r[^], , summary) # 简单移除HTML标签 summary summary[:2000] # Notion文本字段有长度限制 entries.append({ title: title, link: link, published: published, summary: summary }) return entries3.2.3 关键词过滤的逻辑优化简单的关键词匹配可能产生很多误报。例如关键词“go”会匹配到“google”、“golang”甚至“go to market”。我们可以通过引入单词边界或更智能的匹配来优化。def filter_by_keywords(entry, keyword_list): 根据关键词列表过滤文章条目 if not keyword_list: return True # 无关键词则不过滤 text_to_search f{entry[title]} {entry[summary]}.lower() for keyword in keyword_list: kw keyword.strip().lower() if not kw: continue # 简单检查关键词是否在文本中 if kw in text_to_search: return True # 进阶检查尝试匹配单词边界更精确但可能漏掉连字符词 # import re # if re.search(rf\b{re.escape(kw)}\b, text_to_search, re.IGNORECASE): # return True return False掌握了脚本的核心逻辑后我们就可以将其部署到GitHub Actions让它自动运行起来了。4. GitHub Actions工作流配置与自动化部署GitHub Actions的配置文件.yml定义了自动化任务的“剧本”。我们需要确保这个剧本稳定、高效且易于监控。4.1 剖析工作流配置文件一个典型的工作流文件.github/workflows/daily-sync.yml可能长这样name: Daily RSS Sync on: schedule: # 每天UTC时间2点运行对应北京时间上午10点 - cron: 0 2 * * * # 允许手动触发工作流 workflow_dispatch: jobs: sync: runs-on: ubuntu-latest steps: - name: Checkout repository code uses: actions/checkoutv4 - name: Set up Python uses: actions/setup-pythonv5 with: python-version: 3.11 - name: Install dependencies run: | python -m pip install --upgrade pip if [ -f requirements.txt ]; then pip install -r requirements.txt; fi # 安装脚本所需的额外库 pip install feedparser requests python-dateutil - name: Run RSS sync script env: NOTION_TOKEN: ${{ secrets.NOTION_TOKEN }} NOTION_FEEDS_DATABASE_ID: ${{ secrets.NOTION_FEEDS_DATABASE_ID }} NOTION_ENTRIES_DATABASE_ID: ${{ secrets.NOTION_ENTRIES_DATABASE_ID }} run: | python sync.py 21 | tee sync.log # 同时输出到控制台和文件 - name: Upload log artifact (optional) if: always() # 无论成功失败都上传日志 uses: actions/upload-artifactv4 with: name: sync-logs path: sync.log关键配置解析on.schedule.cron: 定时表达式。0 2 * * *表示每天UTC时间2点0分运行。你可以使用 crontab guru 这个网站来生成和测试你的cron表达式。注意GitHub Actions的定时可能稍有延迟不适合要求精确到分钟的任务。on.workflow_dispatch: 允许在GitHub仓库的Actions页面手动点击“Run workflow”触发这在调试时非常有用。env: 在这里将我们在仓库Secrets中设置的机密注入为环境变量脚本中通过os.environ.get(NOTION_TOKEN)来读取。tee sync.log: 这个命令将脚本的输出同时显示在控制台和保存到文件sync.log便于后续作为Artifact下载查看详细日志。4.2 调试与监控实战经验即使配置正确脚本在Actions中运行时也可能遇到各种环境问题。以下是几个关键的调试技巧4.2.1 充分利用GitHub Actions日志每次工作流运行后点击对应的运行记录可以逐步查看每个Step的详细输出。如果脚本失败错误信息会在这里显示。务必仔细阅读常见的错误包括模块导入错误说明requirements.txt遗漏了某个依赖需要在Install dependencies步骤中显式安装。Notion API认证错误检查NOTION_TOKEN是否正确以及集成是否已被邀请到数据库。网络超时错误某些RSS源可能响应慢。考虑在脚本中为requests或httpx设置超时参数并对单个源的失败做容错处理不影响其他源。4.2.2 使用Artifact保存详细日志如上例所示将脚本的输出保存为日志文件并上传为Artifact可以让你下载完整的日志包括所有打印的调试信息这对于分析复杂问题至关重要。4.2.3 本地测试先行在提交到GitHub之前强烈建议在本地进行测试。在本地项目目录创建.env文件填入你的NOTION_TOKEN和数据库ID。使用pip install -r requirements.txt安装依赖。运行python sync.py。观察输出检查Notion数据库中是否成功创建了条目。模拟Actions环境你可以使用act这类工具在本地运行GitHub Actions但更简单的方法是确保你的脚本在纯净的Python环境下也能运行。4.2.4 处理速率限制与错误重试Notion API和某些RSS源可能有速率限制。在脚本中加入简单的延迟和重试机制可以提升稳定性。import time import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry def create_session_with_retry(): session requests.Session() retries Retry(total3, backoff_factor1, status_forcelist[429, 500, 502, 503, 504]) session.mount(https://, HTTPAdapter(max_retriesretries)) return session # 在调用Notion API时使用这个session session create_session_with_retry() response session.post(notion_url, headersheaders, jsonpayload, timeout30)当自动化流程稳定运行后你可能希望在新文章到来时得到即时通知而不是每天去Notion里查看。这就引出了可选的Bot通知环节。5. 可选扩展搭建Bot通知服务原项目提到了通过Deta等Serverless平台部署一个Bot来接收GitHub Actions的Webhook并发送通知。这是一个锦上添花的功能。其核心架构是GitHub Actions任务完成后向一个你部署好的、公开的API地址Webhook发送一个HTTP请求携带本次同步的摘要信息如“新增5篇文章”然后由这个API服务将消息转发到Telegram、Slack、Discord甚至邮箱。5.1 方案选择与Deta部署示例Deta是一个对开发者非常友好的Serverless平台提供免费的额度和简单的部署方式。以下是一个极简的Python Webhook处理器示例部署到Deta后可以将通知发送到Telegram。5.1.1 创建Telegram Bot并获取Chat ID在Telegram中搜索BotFather发送/newbot指令按提示创建你的Bot最终你会获得一个Bot Token形如1234567890:ABCdefGhIJKlmNoPQRsTUVwxyZ。给你的Bot发送一条消息如/start。在浏览器中访问这个URL来获取你的Chat IDhttps://api.telegram.org/botYourBOTToken/getUpdates。在返回的JSON中找到message.chat.id的值。5.1.2 编写Deta MicroServerless函数创建一个新的Python文件例如bot_server.pyfrom http.server import BaseHTTPRequestHandler import json import os import requests TELEGRAM_BOT_TOKEN os.environ.get(TELEGRAM_BOT_TOKEN) TELEGRAM_CHAT_ID os.environ.get(TELEGRAM_CHAT_ID) def send_telegram_message(message): if not TELEGRAM_BOT_TOKEN or not TELEGRAM_CHAT_ID: return False url fhttps://api.telegram.org/bot{TELEGRAM_BOT_TOKEN}/sendMessage payload { chat_id: TELEGRAM_CHAT_ID, text: message, parse_mode: Markdown } try: response requests.post(url, jsonpayload, timeout10) return response.status_code 200 except Exception as e: print(f发送Telegram消息失败: {e}) return False class Handler(BaseHTTPRequestHandler): def do_POST(self): content_length int(self.headers[Content-Length]) post_data self.rfile.read(content_length) try: data json.loads(post_data.decode(utf-8)) # 假设GitHub Actions发送的数据格式为 {new_entries: 5, feed_name: TechCrunch} new_entries data.get(new_entries, 0) feed_name data.get(feed_name, RSS Sync) message f *{feed_name} 更新通知*\\n新增 {new_entries} 篇文章已同步至Notion。 if send_telegram_message(message): self.send_response(200) self.send_header(Content-type, application/json) self.end_headers() self.wfile.write(json.dumps({status: ok}).encode()) else: self.send_response(500) self.end_headers() except Exception as e: self.send_response(400) self.end_headers() print(f处理请求错误: {e}) # Deta特定需要导出 app 变量 from deta import App app App(Handler)5.1.3 部署到Deta并配置GitHub Actions在Deta官网注册并安装CLI工具。在项目目录下运行deta new --python bot_server创建一个Micro。在Deta Micro的设置中配置环境变量TELEGRAM_BOT_TOKEN和TELEGRAM_CHAT_ID。部署deta deploy。部署成功后你会获得一个类似https://your-project.deta.dev的公开URL。修改你的GitHub Actions工作流文件在Run RSS sync script步骤之后添加一个新的步骤来调用Webhook- name: Notify via Webhook if: success() # 仅在同步成功时通知 env: WEBHOOK_URL: ${{ secrets.WEBHOOK_URL }} # 在仓库Secrets中设置你的Deta Micro URL run: | # 假设你的sync.py脚本最后输出了一个JSON格式的摘要到summary.json if [ -f summary.json ]; then curl -X POST \ -H Content-Type: application/json \ -d summary.json \ $WEBHOOK_URL fi你需要修改你的sync.py脚本在运行结束后将摘要信息处理了多少源新增多少文章写入一个summary.json文件。5.2 其他通知方案考量除了DetaTelegram你还可以考虑Serverless平台Vercel Netlify AWS Lambda等部署一个类似的Webhook处理器。通知渠道Slack Incoming Webhook Discord Webhook 甚至直接发送邮件使用SMTP库。选择你最常用的那个。简化方案如果觉得部署Serverless服务麻烦可以退而求其次使用GitHub Actions自带的actions/github-script在Issue中评论或者使用现成的第三方Action如appleboy/telegram-action直接发送通知但这通常需要将Bot Token放在Secrets中。至此一个功能完整、高度自动化的个人RSS管理系统就搭建完成了。从信息源的配置、内容的抓取过滤、到最终的归档和通知全部在你的控制之下且几乎零成本。6. 高级技巧与常见问题排查在长期使用和迭代这个系统的过程中我积累了一些能显著提升体验和稳定性的技巧也总结了一些常见问题的排查方法。6.1 提升系统稳定性和可维护性6.1.1 为RSS源设置独立的错误处理与重试不要因为一个“顽固”的RSS源失败而导致整个任务失败。将每个源的抓取逻辑包裹在独立的try...except块中。for feed in enabled_feeds: feed_name feed[name] feed_url feed[url] try: entries parse_feed(feed_url) # ... 过滤和写入逻辑 print(f[OK] {feed_name} 处理成功获取{len(entries)}条。) except requests.exceptions.Timeout: print(f[Timeout] {feed_name} 请求超时已跳过。) log_error(feed_name, Timeout) except Exception as e: print(f[Error] 处理 {feed_name} 时发生未知错误: {e}) log_error(feed_name, str(e)) time.sleep(1) # 在每个源处理间增加短暂延迟避免对服务器造成压力6.1.2 实现增量抓取与智能去重每次都抓取所有历史文章并去重效率低下。更优的策略是在“RSS Feeds”数据库中记录每个源Last Fetched的时间。抓取时如果RSS条目提供了发布时间只处理发布时间晚于Last Fetched的文章。如果RSS不提供可靠时间则退回到URL去重但可以定期如每周一次全量同步以防漏抓。更新Last Fetched时间为本次抓取开始的时间而不是结束时间避免因网络延迟导致少量文章被重复抓取。6.1.3 优化Notion数据库视图利用Notion数据库的视图View功能可以极大提升阅读体验。创建“今日未读”视图添加过滤器Published“Today” 且Read“Is unchecked”。按源分类视图按Source属性分组方便追踪特定博客的更新。看板视图用Category或自定义的Status如“待读”、“已读”、“收藏”作为分组实现简单的阅读流管理。6.2 常见问题与解决方案速查表问题现象可能原因排查步骤与解决方案GitHub Action运行失败报ModuleNotFoundError1.requirements.txt文件缺失或内容不正确。2. 依赖未正确安装。1. 检查仓库根目录是否有requirements.txt并包含feedparser,requests等库。2. 在Actions日志的“Install dependencies”步骤查看pip安装输出是否成功。脚本成功运行但Notion里没有新文章1. Notion API Token或Database ID错误。2. 集成Integration未被邀请到数据库。3. RSS源URL错误或已失效。4. 关键词过滤过于严格所有文章都被过滤掉。1. 检查GitHub Secrets设置是否正确无多余空格。2. 分别打开两个数据库页面点击Share确认你的集成名称在共享列表中。3. 手动在浏览器访问RSS URL看是否能打开并看到XML内容。4. 暂时清空Notion中某个源的Keywords字段再次运行任务测试。Notion中出现重复文章去重逻辑失效。通常是因为以文章标题去重不可靠标题可能微调或者Last Fetched时间逻辑有误。最佳实践是使用文章链接URL作为唯一标识进行去重。在写入前先查询“RSS Entries”数据库中是否存在相同URL的记录。Action日志显示429 Too Many Requests触发了Notion API的速率限制。Notion API对请求频率和并发有一定限制。1. 在脚本的API请求间增加延迟如time.sleep(0.5)。2. 减少单次任务处理的RSS源数量或分批次处理。3. 使用更高效的批量操作如batch create如果Notion API支持的话。抓取某些源特别慢或超时该RSS源服务器响应慢或网络状况不佳。1. 在requests.get或feedparser.parse时设置超时参数如timeout10。2. 对该源实行独立的错误捕获和跳过机制不影响其他源。文章摘要包含大量HTML标签RSS源提供的摘要description字段本身包含HTML。在脚本中增加一个清理函数使用BeautifulSoup或简单的正则表达式移除HTML标签只保留纯文本。注意不要移除必要的换行符。Bot通知没有收到1. Webhook URL错误。2. Deta Micro环境变量未设置。3. Telegram Bot Token或Chat ID错误。4. GitHub Actions中通知步骤的条件判断if: success()未满足。1. 在本地使用curl或Postman手动向Webhook URL发送测试数据看Deta的日志。2. 检查Deta Micro的日志输出。3. 在浏览器中访问https://api.telegram.org/botYourToken/getMe测试Token访问getUpdates确认Chat ID。4. 检查Actions运行是否真的成功以及summary.json文件是否存在。这个由Notion和GitHub Actions构建的系统其魅力在于它的可塑性。你可以根据自己的需求轻松地修改它比如增加对JSON Feed的支持为文章自动添加标签或者将抓取的内容同时保存到其他笔记软件。它不再是一个黑盒工具而是一个真正属于你、理解你、并随着你需求成长的信息伙伴。