最近有个需求,由于最近在某平台更新内容,其提供的订阅机制为RSS订阅分发,不过其中带有的一些额外的信息有点尴尬,并不能直接发送到其他同类型内容平台分发,因此想到了通过程序先将不适宜信息处理后,定期更新RSS文件到自己的Github Pages上,然后其他同类型内容平台获取的RSS为自己的Github Pages上托管的RSS文件。
于是,需求比较明确了:
- 可以托管并执行程序,不仅可以获取RSS文件内容,又可以通过程序修改;
- 可以定时更新任务,并且根据更新任务内容push到仓库指定分支。
我第一时间想起了Github Actions这个工具,众所周知,这个工具自2019年内测到向公众开放后,众多从业者将自己的博客的编译工作从本地线下扔到了Github Actions上;一些从业者所写的前端小玩意儿,都可以很轻松的通过Github Actions将工程迅速部署,提高了效率以及节约了成本。甚至一些有后端的工程,只需要寻(bai)找(piao)一个后端存储数据的地儿,就可以低成本甚至零成本搭建个人主页,这简直是一个十分有效提高生产率的东西啊!
不过说起来,其实Github Actions与Jenkins的功能是一致的,都是一个CI/CD的DevOps生产力工具,只不过Github Actions以其简单易用一经推出就受到了十分的欢迎。
虽然一直有知道这个功能,但是苦于没什么场景可以使用,今天这个需求正好让我能够使用Github Actions,零成本的解决一下需求。
首先,准备一下更新RSS的主程序convertRSS.py
和requirements.txt
:
import requests
import os, sys
import argparse
# the main get content codes
def get_url(url):
# some server requests need headers, otherwise return empty
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36',
}
page = requests.get(url, headers = headers).content
# convert to str within utf-8 encoding
page = page.decode('utf-8')
return page
# the main convert codes
def convert_content(content):
content = content.replace("ZNing源创库","张宁网·源创库")
return content
if __name__ == '__main__':
# need system args input
arg_prsr = argparse.ArgumentParser()
arg_prsr.add_argument('--url', required=True, type=str, default="", help = 'Required. Which one RSS Xml do you want to convert.')
args = arg_prsr.parse_args(sys.argv[1:])
url = args.url
# place a flag to judge should write file to disk or not
flag = False
url_content = convert_content(get_url(url))
url_list = url.split("/")
if os.path.exists(url_list[-1]):
with open(url_list[-1], 'r', encoding='utf-8') as file:
if(file.read()!=url_content):
flag = True
else:
# if the file dose not exist, the flag should placed True to convert first time
flag = True
if flag:
# writing to disk codes
with open(url_list[-1], 'w', encoding='utf-8') as file:
file.write(url_content)
print("The RSS Xml had update, convert done.")
sys.exit(0)
else:
print("The RSS Xml have no change, convert abort.")
sys.exit(1)
这里解释下我的程序的逻辑:通过系统执行传参--url
将需要处理的RSS XML URL传值进入,后通过函数get_url()
完成源文件的获取并转换成字符串,紧接着通过convert_content()
函数处理替换源文件字符串。完成后紧接着判断本地是否有该文件,如果没有则直接创建,如果有则判断本地文件是否与处理替换后文件内容是否相同,如果不相同则覆盖修改本地文件完成更新,并以0
返回值正常退出,如果相同则无需更新,以1
返回值返回退出程序。
至于为什么设计这两个返回值,文末会讲到。
下面是该程序的requirements.txt
,显然得,不再赘述:
requests==2.25.1
之后Github Actions创建一个仓库,把这俩文件放进去。
另外是需要去Settings-Developer settings-Personal access tokens(链接:https://github.com/settings/tokens)里面生成一个密钥,将这个密钥添加到仓库设置的Actions secrets(链接:https://github.com/``{username}/``{reponame}/settings/secrets/actions),在Actions secrets的名字即是配置文件引入的变量名,这里我的仓库叫CONVERT_TOKEN
。
文件和密钥均备妥后,点击菜单标签Actions,后点击set up a workflow yourself
,进入创建自己的工作流。
工作流创建文件使用的是YAML语法,具体使用文档可以查阅:https://docs.github.com/cn/actions 这里不再赘述更多用法,直接贴出本示例项目创建的工作流文件convert-rss.yml
:
name: 'Convert RSS Actions'
on:
schedule:
- cron: '0,15,30,45 * * * *'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout from repo
uses: actions/checkout@main
with:
ref: main
- name: Install Python latest
uses: actions/setup-python@main
with:
python-version: '3.x'
architecture: 'x64'
- name: Install dependencies
run: |
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Doing fetch
run: python convertRSS.py --url https://zning.me/atom.xml
- name: Commit files
run: |
git config --local user.email "[email protected]"
git config --local user.name "ZNing"
git add .
git commit -m "提交RSS XML更新 $(date "+%Y-%m-%d %H:%M:%S")"
- name: Push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.CONVERT_TOKEN }}
branch: main
Github会在该分支仓库里创建.github/workflow
文件夹,并在里面创建工作流文件convert-rss.yml
,文件名没有任何要求,Github Actions会对该文件夹下所有.yml
进行解析与执行。
这里稍微解释一下我自己这个工作流文件所干的事情:
- 工作流名称为
Convert RSS Actions
; - 工作流为定时计划工作流,工作时间是每隔15分钟一次;
- 工作流build有6个任务,顺序执行,每个步骤的具体是:
- 检出main仓库;
- 安装最新版Python 3;
- 根据仓库是否有
requirements.txt
安装Python依赖; - 执行Python程序,对RSS XML进行处理;
- 对更新的RSS XML进行提交;
- 对更新的RSS XML进行推送至指定分支。
创建好后,就等着Github Actions自己按计划调起Actions工作即可,不过根据实际测试,由于这玩意儿全球从业者估计使用的都挺多的,所以实际执行时间并不会完全按照设定的时间走,一般会晚个8-12分钟。
仓库所有内容其实都可以本地创建,其中Actions的定义文件在本地创建
.github/workflow
文件夹后放置提交推送给Github也是可以的,只不过我这边为了演示方便,就不再在本地做操作了,直接在Github网页上直接将所有步骤都解决了。
这里解释一下刚才Python返回值的问题,因为我需要区分两种状态情况,而Github Actions是可以根据返回值判断该节点运行正常与否(详见:https://docs.github.com/cn/actions/creating-actions/setting-exit-codes-for-actions)只要是0就认为是正常,非0则是异常,且异常不会继续执行接下来的节点。
而我的需求其实就正好是,如果有更新则提交并推送仓库,如果没有则终止即可。因此上面的Python程序才会设置如此的返回值。
不过可能是我Python程序有点小问题,发现如果内容相同的时候,后台程序也会提交更新,但是这个情况出现的很随机,有的时候又比对相同1值退出,正常返回错误。目前不太清楚这是为什么,欢迎知道的大佬在评论区留言。
最后,本文示例程序正常开源,协议MIT,欢迎自取使用: