0.目的
为了实现博客的多平台(简书、掘金、知乎等)自动化发布,需要将本地的markdown中的图片自动转为图床链接,尽管已经有PicGO这种神器,但是自动调用PicGo上传图床有以下两个问题
- 本地保留:大量图片为直接从visio中复制过来,如果直接上传本地没有保留副本
- 隐私性:有些笔记不做公开,不希望图片公开
因此使用另一种方法解决自动化发布问题,即优先在本地完成文章,设置编辑器为将图片保存在本地,编写一个自动化替换脚本实现三个功能:
- 将图片上传到图床(选择Gitee)
- 将文章中的链接替换为图床链接
1.Gitee图床
Gitee是国内的代码托管网站,和Github相比具有访问块的优势,要将Gitee作为图床,需要在Gitee中建立一个公开仓库并获取Token,首先建立公开仓库:
随后点击头像,在安全设置中选择私人令牌,勾选需要的权限,点击提交即可生成token,后续脚本可以使用这个token通过gitee的API进行自动的图像上传。自此Gitee图床搭建完毕,可以尝试向该仓库中上传图片,如下所示:
该图片的位置为<仓库名称>/raw/master/<图片路径>,例如上述图片位于:<仓库路径>/raw/master/assert/player_structure.png
2.自动化上传
Gitee有API处理新建文件。根据API文档,新建文件的请求类型为POST,请求地址如下所示:
https://gitee.com/api/v5/repos/{owner}/{repo}/contents/{path}
路径中所需要的内容如下所示:
-
owner
:仓库所属空间的地址,对个人用户即为用户名 -
repo
:仓库路径,即图床的名称 -
path
:上传文件的目标路径,例如上一部分中为assert/player_structure.png
POST的formDate中需要带的参数如下所示:
-
access_token
:数据类型为string,为用户生成的token -
content
:文件内容,数据类型为string,使用base64编码 -
message
:提交信息,数据类型为string
这里使用Python3+requests库构建POST请求,构建代码如下所示:
def uploader_picture_gitee(post_data):
url = "https://gitee.com/api/v5/repos/{owner}/{repo}/contents/{path}".format(
owner=post_data["owner"],repo=post_data["repo"],path=post_data["path"])
formdata = {
"access_token":post_data["token"],
"content":post_data["content"],
"message":post_data["message"]
}
r = requests.post(url=url,data=formdata)
if r.status_code == 201:
print("INFO:upload {} successful".format(post_data["path"]))
return r.json()["content"]["download_url"]
return None
其中post_data是包括所有参数的dict,其中owner、repo和token来自预先写好的json文件,读取部分代码如下所示:
def get_config(cfg_path):
with open(cfg_path,"r") as f:
data = json.load(f)
return data
另外path、content和message需要根据图片文件生成,其中path由原文件名加上时间戳防止重复,content内容需要以二进制读取图片文件,并将其使用base64编码,该部分代码如下所示:
def get_picture(pic_path):
with open(pic_path,'rb') as f:
data = base64.b64encode(f.read())
picture_name = os.path.split(pic_path)[-1]
time_name = int(time.time() * 1000)
return {
"content":data,
"path":"assert/{}_{}".format(time_name,picture_name),
"message":"{}-upload{}".format(time_name,picture_name)
}
3.markdown图片替换
需要将markdown中的图片语句![]()
中的内容替换为上传后的URL,使用正则表达式识别,正则表达式如下所示:
r"^\s*!\[.*?\]\(.*?\)"
当识别出上述内容后,判断当前行为图片,这里仅对单独出现的图片做处理,不考虑和文字出现在同一行的图片。代码如下所示:
def handle_markdown(mk_path,cfg_path):
# read config
cfg = get_config(cfg_path)
# read markdown
with open(mk_path,'r',encoding='utf-8') as f:
data = f.read().split("\n")
# search pic and upload
for i,line in enumerate(data):
m = re.search(r"^\s*!\[(.*?)\]\((.*?)\)",line)
if m is not None:
pic_name,pic_path = m.groups()
if "://" in pic_path:
print("INFO:{} is url,ignore".format(pic_path))
continue
pic = get_picture(pic_path)
url = uploader_picture_gitee({**cfg,**pic})
if url is None:
raise ValueError("upload {} failed".format(pic_name))
data[i] = "![{}]({})".format(pic_name,url)
# add thanks
data.append("> 感谢gitee提供图片托管服务,BlogHelper提供快捷发布服务")
data.append("> 该版本由自动发布工具生成,原始内容为原创,转载需联系作者获得授权")
# generate new markdown
root,name = os.path.split(mk_path)
new_path = os.path.join(root,"public_{}".format(name))
with open(new_path,'w') as f:
f.write("\n".join(data))
该部分代码处理的内容如下所示:
- 读取配置信息
- 读取markdown文件
- 扫描markdown的每一行,若在这一行发现图片插入语句,则判断其是否为url,若不是url则读取图片并将其上传,并替换为返回的URL
- 在尾部添加版权声明和感谢信息
- 生成新文件文件名并写入内容
4.发布
至此,生成了将图片替换为图床URL的可发布版本,通过BlogHelper可自动发布到各个平台
感谢gitee提供图片托管服务,BlogHelper提供快捷发布服务
该版本由自动发布工具生成,原始内容为原创,转载需联系作者获得授权