├── .DS_Store ├── .github └── workflows │ └── rssbot.yml ├── .gitignore ├── README.md ├── robot ├── models.py ├── requirements.txt ├── rss.db └── rss.py └── screens └── 效果图.png /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeetaoGoooo/dingding-rssbot/8f841851f76832ee2879e01d8d7626dff4d7c3fc/.DS_Store -------------------------------------------------------------------------------- /.github/workflows/rssbot.yml: -------------------------------------------------------------------------------- 1 | # 钉钉 rss 推送机器人 2 | name: DingDingRssBot 3 | 4 | on: 5 | schedule: 6 | - cron: '0 0/1 * * *' 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: 'Checkout codes' 13 | uses: actions/checkout@v2 14 | - name: Set up Python Version 15 | uses: actions/setup-python@v2 16 | with: 17 | python-version: '3.10' 18 | - name: Install dependencies 19 | run: | 20 | cd robot 21 | pip install -r requirements.txt 22 | - name: send rss 23 | env: 24 | DD_WEBHOOK: ${{ secrets.webhook }} 25 | DD_SECRET: ${{ secrets.secret }} 26 | run: | 27 | cd robot 28 | python rss.py 29 | - name: Commit 30 | run: | 31 | git config --global user.email leetao94cn@gmail.com 32 | git config --global user.name lt94 33 | git add . 34 | git commit -m "update" -a 35 | - name: Push changes 36 | uses: ad-m/github-push-action@master 37 | with: 38 | branch: main 39 | github_token: ${{ secrets.TOKEN }} 40 | 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | venv 3 | .venv -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DingDing Rss Robot 2 | 钉钉 rss 订阅机器人 3 | 4 | # 功能 5 | 6 | - rss 订阅 7 | - rss 定时推送 8 | 9 | # 使用说明 10 | 11 | fork 本项目后,需要进行配置后才能正常使用 12 | 13 | ## rss 源配置 14 | 15 | 使用数据库管理源打开 rss.db 文件,修改 rss.db 表中的 Rss 表 16 | 17 | ```python 18 | class Rss(BaseModel): 19 | feed = CharField(unique=True) # 订阅地址 20 | cover = CharField(max_length=255, null=True) # 封面(图片地址) 21 | title = CharField(max_length=20) # 订阅名称 22 | url = CharField(max_length=255) # 网站地址 23 | ``` 24 | 25 | 26 | ## 定时配置 27 | 28 | 修改 `.github/workflows/rssbot.yml` 文件第 8 行 cronb 的表达式 29 | 30 | ⚠️ **频率不要太频繁,避免被误判滥用** 31 | 32 | 其中 31 和 32 行配置可以设置为自己的邮箱和名称 33 | 34 | ```yaml 35 | git config --global user.email lineporte@gmail.com 36 | git config --global user.name linep47 37 | ``` 38 | 39 | ## 配置环境变量 40 | 41 | 钉钉机器人需要使用 `WEBHOOK` 和 `SECRET`(对应**加签**) 这两个参考钉钉机器人文档自行申请。 42 | 43 | 还需要申请一个 `TOKEN`, 点击 [Personal access tokens (classic)](https://github.com/settings/tokens) 申请 44 | 45 | 然后在项目的 Settings 中依次添加 `WEBHOOK`,`SECRET`,`TOKEN` 三个参数 46 | 47 | 48 | image 49 | 50 | 51 | # 效果 52 | 53 | image 54 | -------------------------------------------------------------------------------- /robot/models.py: -------------------------------------------------------------------------------- 1 | from peewee import * 2 | import datetime 3 | 4 | db = SqliteDatabase('rss.db') 5 | 6 | 7 | class BaseModel(Model): 8 | class Meta: 9 | database = db 10 | 11 | 12 | class Rss(BaseModel): 13 | feed = CharField(unique=True) # 订阅地址 14 | cover = CharField(max_length=255, null=True) # 封面(图片地址) 15 | title = CharField(max_length=20) # 订阅名称 16 | url = CharField(max_length=255) # 网站地址 17 | 18 | 19 | class History(BaseModel): 20 | url = CharField(max_length=255) 21 | publish_at = DateField(default=datetime.datetime.now) 22 | 23 | 24 | def create_tables(): 25 | with db: 26 | db.create_tables([Rss, History]) 27 | -------------------------------------------------------------------------------- /robot/requirements.txt: -------------------------------------------------------------------------------- 1 | dateparser==0.7.6 2 | DingtalkChatbot==1.5.1 3 | feedparser==6.0.1 4 | peewee==3.13.3 -------------------------------------------------------------------------------- /robot/rss.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeetaoGoooo/dingding-rssbot/8f841851f76832ee2879e01d8d7626dff4d7c3fc/robot/rss.db -------------------------------------------------------------------------------- /robot/rss.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | 3 | """ 4 | rss.py 5 | 6 | 钉钉 Rss 机器人 7 | 推送 Rss 信息到钉钉机器人Api 8 | 9 | """ 10 | from datetime import datetime, timedelta 11 | from itertools import takewhile 12 | import feedparser 13 | from dingtalkchatbot.chatbot import DingtalkChatbot, CardItem 14 | import dateparser 15 | from models import db, Rss, History 16 | import os 17 | 18 | 19 | class RssRobot: 20 | def __init__(self): 21 | # 说明文档的效果图中的 post_cover 22 | self.post_cover = "https://leetao.zhubai.love/api/wechat/miniprogram_qrcode?page=pages%2Fpublication%2Fpublication&publication_id=2170089804120211456&scene=token%3Dleetao&width=200" 23 | self.robot = DingtalkChatbot( 24 | os.environ.get("DD_WEBHOOK"), 25 | pc_slide=True, secret=os.environ.get("DD_SECRET")) 26 | self.remove_old_history() 27 | 28 | @property 29 | def sended_urls(self): 30 | return [rss_history.url for rss_history in History.select()] 31 | 32 | @property 33 | def subscriptions(self): 34 | return Rss.select() 35 | 36 | def get_post_cards(self): 37 | feeds = [] 38 | for subscription in self.subscriptions: 39 | feed = feedparser.parse(subscription.feed) 40 | pic_url = subscription.cover if subscription.cover else self.post_cover 41 | feed_header = CardItem( 42 | title=subscription.title, url=subscription.url, pic_url=pic_url) 43 | posts = self.get_posts(feed.entries) 44 | if posts: 45 | feeds.append([feed_header, *posts]) 46 | return feeds 47 | 48 | def get_posts(self, entries): 49 | post_cards = [] 50 | post_urls = [] 51 | for entry in takewhile(self.is_not_sended, entries): 52 | post_cards.append(CardItem(title=entry.title, 53 | url=entry.link, pic_url=self.post_cover)) 54 | post_urls.append(History(url=entry.link)) 55 | with db.atomic(): 56 | History.bulk_create(post_urls, batch_size=100) 57 | return post_cards 58 | 59 | def is_not_sended(self, url): 60 | return url not in self.sended_urls 61 | 62 | def is_today(self, entry): 63 | return dateparser.parse(entry['updated']).date() == datetime.today().date() 64 | 65 | def send_rss(self): 66 | post_cards = self.get_post_cards() 67 | for post_card in post_cards: 68 | self.robot.send_feed_card(post_card) 69 | 70 | def remove_old_history(self): 71 | # 只保留最近一周的记录 72 | week_date_range = datetime.now() + timedelta(days=-7) 73 | History.delete().where(History.publish_at < 74 | week_date_range.strftime("%Y-%m-%d")).execute() 75 | 76 | 77 | def send_rss(): 78 | rss_bot = RssRobot() 79 | rss_bot.send_rss() 80 | 81 | 82 | if __name__ == '__main__': 83 | send_rss() 84 | -------------------------------------------------------------------------------- /screens/效果图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeetaoGoooo/dingding-rssbot/8f841851f76832ee2879e01d8d7626dff4d7c3fc/screens/效果图.png --------------------------------------------------------------------------------