背景
需求的功能:①不额外下载软件(洁癖是这样的 )②能够提醒我每天进行阅读,但是不愿意关闭免打扰模式③可以一键部署,但是要保留可diy性
思考
最难解决的问题其实是第二条,我之前尝试过在专门的软件上配制rss,但是死活无法养成“打开手机-进行阅读”的链条(阅读的内容是有关学习的,原生吸引力不强),后来一直在想,有哪个软件是我一打开手机肯定会点开的呢?于是我把目光投向了微信。微信的小红点是我最无法忍受的东西,于是结合微信的这种特性,提出了一种简易的rss方案
方案
需要准备两个邮箱,一个是QQ邮箱,另一个任意。获取另一个邮箱的专用密码(本文以gmail为例),在GitHub新建仓库使用下面的代码
import feedparser
import smtplib
import random
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from datetime import datetime, timezone, timedelta
# --- 1. 配置信息 (请根据需要修改) ---
# 发件人Gmail地址
SENDER_EMAIL = '[email protected]'
# Gmail应用专用密码
SENDER_APP_PASSWORD = 'ndmb eppv ndmb eppv'
# 收件人邮箱
RECIPIENT_EMAIL = '[email protected]'
# SMTP服务器地址
SMTP_SERVER = 'smtp.gmail.com'
# SMTP服务器端口 (SSL)
SMTP_PORT = 465
# --- 2. RSS源列表 ---
# 在这里添加或删除您想订阅的RSS源
# 格式为 {'name': '自定义名称', 'url': 'RSS地址'}
RSS_FEEDS = [
# 您之前提供的RSS源
{'name': 'RSS App Feed', 'url': 'https://rss.app/feeds/o6eUCKonflhxeRZO.xml'},
{'name': 'Sitemap Generator 1', 'url': 'https://cdn.mysitemapgenerator.com/shareapi/rss/25061165417'},
{'name': 'Sitemap Generator 2', 'url': 'https://cdn.mysitemapgenerator.com/shareapi/rss/25061165418'},
{'name': 'Sitemap Generator 3', 'url': 'https://cdn.mysitemapgenerator.com/shareapi/rss/25061165450'},
{'name': 'IBTimes', 'url': 'https://www.ibtimes.com/rss'},
{'name': 'The Guardian', 'url': 'https://www.theguardian.com/world/rss'},
{'name': 'NYT HomePage', 'url': 'https://rss.nytimes.com/services/xml/rss/nyt/HomePage.xml'},
{'name': 'RSSHub Finance', 'url': 'https://news.google.com/rss/search?q=when:24h+allinurl:bloomberg.com&hl=en-US&gl=US&ceid=US:en'},
{'name': 'Sitemap Generator 4', 'url': 'https://cdn.mysitemapgenerator.com/shareapi/rss/25061165479'},
{'name': 'Sitemap Generator 5', 'url': 'https://cdn.mysitemapgenerator.com/shareapi/rss/25061165480'},
# 您代码中原有的RSS源
{'name': 'V2EX', 'url': 'https://www.v2ex.com/index.xml'},
{'name': 'Telegram - NodeSelect', 'url': 'https://rss.wudifeixue.com/telegram/channel/nodeselect'},
{'name': '吾爱破解精选', 'url': 'https://www.52pojie.cn/forum.php?mod=guide&view=digest&rss=1'},
{'name': 'Hack News', 'url': 'https://hn.buzzing.cc/feed.xml'},
{'name': '少数派', 'url': 'https://rss.app/feeds/1h8et5HcZccKZeDu.xml'},
]
# --- 3. 发送数量控制 ---
# 设置每天要发送的文章总数
TOTAL_POSTS_TO_SEND = 20
# --- 4. 功能实现 (通常无需修改) ---
def fetch_and_select_random_posts():
"""获取所有RSS源的文章,随机选择指定数量"""
all_posts = []
print("开始获取所有RSS源的文章...")
for feed_info in RSS_FEEDS:
name = feed_info['name']
url = feed_info['url']
print(f"正在处理: {name} ({url})")
try:
feed = feedparser.parse(url)
if feed.bozo:
print(f"警告: RSS源 '{name}' 可能格式不正确: {feed.bozo_exception}")
# 为每篇文章添加来源名称
for post in feed.entries:
post.source_name = name
all_posts.append(post)
except Exception as e:
print(f"获取RSS源 '{name}' 失败: {e}")
continue
print(f"所有RSS源获取完毕,共收集到 {len(all_posts)} 篇文章。")
# 如果收集到的文章少于要发送的数量,直接使用所有文章
if len(all_posts) < TOTAL_POSTS_TO_SEND:
print(f"警告: 总文章数 ({len(all_posts)}) 少于目标发送数 ({TOTAL_POSTS_TO_SEND}),将发送所有已获取文章。")
selected_posts = all_posts
else:
# 随机打乱所有文章的顺序
random.shuffle(all_posts)
# 选择指定数量的文章
selected_posts = all_posts[:TOTAL_POSTS_TO_SEND]
print(f"已随机选择 {len(selected_posts)} 篇文章进行发送。")
# 对最终选择的文章按发布时间排序,方便阅读
selected_posts.sort(key=lambda p: p.get('published_parsed'), reverse=True)
return selected_posts
def format_email_html(posts):
"""将帖子列表格式化为HTML邮件内容"""
if not posts:
return "<h3>今天所有RSS源都没有获取到新帖子。</h3>", "每日RSS推送"
beijing_time = datetime.now(timezone(timedelta(hours=8)))
title = f"每日RSS精选 - {beijing_time.strftime('%Y-%m-%d')}"
html_content = f"""
<html>
<head>
<style>
body {{ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; line-height: 1.6; background-color: #f4f4f4; margin: 0; padding: 0; }}
.container {{ max-width: 680px; margin: 20px auto; padding: 20px; border: 1px solid #ddd; border-radius: 8px; background-color: #ffffff; }}
h2 {{ color: #333; text-align: center; }}
.post {{ margin-bottom: 18px; padding-bottom: 18px; border-bottom: 1px solid #eee; }}
.post-title {{ font-size: 18px; margin: 0 0 8px 0; }}
.post-title a {{ color: #0056b3; text-decoration: none; font-weight: bold;}}
.post-title a:hover {{ text-decoration: underline; }}
.post-meta {{ font-size: 13px; color: #555; }}
.source-tag {{ background-color: #007bff; color: white; padding: 3px 8px; border-radius: 4px; font-weight: bold; font-size: 12px; display: inline-block;}}
</style>
</head>
<body>
<div class="container">
<h2>{title}</h2>
"""
for post in posts:
post_title = post.title
post_link = post.link
source_name = getattr(post, 'source_name', '未知来源')
pub_time_str = "未知时间"
if 'published_parsed' in post and post.published_parsed:
try:
# 创建UTC时区的datetime对象
pub_time_utc = datetime(*post.published_parsed[:6], tzinfo=timezone.utc)
# 转换为北京时间
pub_time_beijing = pub_time_utc.astimezone(timezone(timedelta(hours=8)))
pub_time_str = pub_time_beijing.strftime('%Y-%m-%d %H:%M')
except Exception as e:
print(f"处理时间戳时出错: {e}")
pub_time_str = "时间格式错误"
html_content += f"""
<div class="post">
<p class="post-title"><a href="{post_link}" target="_blank">{post_title}</a></p>
<div class="post-meta">
<span class="source-tag">{source_name}</span> | 发布于: {pub_time_str}
</div>
</div>
"""
html_content += """
</div>
</body>
</html>
"""
return title, html_content
def send_email(subject, html_body):
"""发送邮件"""
print("准备发送邮件...")
msg = MIMEMultipart()
msg['From'] = SENDER_EMAIL
msg['To'] = RECIPIENT_EMAIL
msg['Subject'] = subject
msg.attach(MIMEText(html_body, 'html', 'utf-8'))
try:
with smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) as server:
server.login(SENDER_EMAIL, SENDER_APP_PASSWORD)
server.sendmail(SENDER_EMAIL, [RECIPIENT_EMAIL], msg.as_string())
print(f"邮件已成功发送至 {RECIPIENT_EMAIL}!")
except Exception as e:
print(f"邮件发送失败: {e}")
def main():
"""主函数"""
posts = fetch_and_select_random_posts()
if posts:
subject, html_body = format_email_html(posts)
send_email(subject, html_body)
else:
print("没有获取到任何文章,不发送邮件。")
if __name__ == "__main__":
main()
然后在workflow里面配制
name: V2EX Daily Push
on:
workflow_dispatch: # 允许手动触发
schedule:
# 每天北京时间上午9点运行
# cron表达式格式为:分钟 小时 日 月 周
# UTC时间 1:00 对应北京时间 9:00
- cron: '0 1 * * *'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install feedparser
- name: Run script
env:
# 引用下面设置的 Secrets
SENDER_EMAIL: ${{ secrets.SENDER_EMAIL }}
SENDER_APP_PASSWORD: ${{ secrets.SENDER_APP_PASSWORD }}
RECIPIENT_EMAIL: '[email protected]'
run: |
# 运行Python脚本
python v2ex_daily.py
效果
我主要用于每日进行外刊推送,另外微信客户端自带了翻译(右上角有翻译功能),可以在微信内部进行每日外刊阅读而不用跳到其它APP
RSS推荐
代码里面已经有一些我自己在用的,下面再推荐一些比较优质的rss源给大家