public_markdown博客图片自动上传

2021-12-10 14:21:08 浏览数 (1)

0.目的

为了实现博客的多平台(简书、掘金、知乎等)自动化发布,需要将本地的markdown中的图片自动转为图床链接,尽管已经有PicGO这种神器,但是自动调用PicGo上传图床有以下两个问题

  • 本地保留:大量图片为直接从visio中复制过来,如果直接上传本地没有保留副本
  • 隐私性:有些笔记不做公开,不希望图片公开

因此使用另一种方法解决自动化发布问题,即优先在本地完成文章,设置编辑器为将图片保存在本地,编写一个自动化替换脚本实现三个功能:

  • 将图片上传到图床(选择Gitee)
  • 将文章中的链接替换为图床链接

1.Gitee图床

Gitee是国内的代码托管网站,和Github相比具有访问块的优势,要将Gitee作为图床,需要在Gitee中建立一个公开仓库并获取Token,首先建立公开仓库:

image-20211204153342474

随后点击头像,在安全设置中选择私人令牌,勾选需要的权限,点击提交即可生成token,后续脚本可以使用这个token通过gitee的API进行自动的图像上传。自此Gitee图床搭建完毕,可以尝试向该仓库中上传图片,如下所示:

image-20211204154619404

该图片的位置为<仓库名称>/raw/master/<图片路径>,例如上述图片位于:<仓库路径>/raw/master/assert/player_structure.png

2.自动化上传

Gitee有API处理新建文件。根据API文档,新建文件的请求类型为POST,请求地址如下所示:

代码语言:javascript复制
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请求,构建代码如下所示:

代码语言:javascript复制
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文件,读取部分代码如下所示:

代码语言:javascript复制
def get_config(cfg_path):
    with open(cfg_path,"r") as f:
        data = json.load(f)
    return data

另外path、content和message需要根据图片文件生成,其中path由原文件名加上时间戳防止重复,content内容需要以二进制读取图片文件,并将其使用base64编码,该部分代码如下所示:

代码语言:javascript复制
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,使用正则表达式识别,正则表达式如下所示:

代码语言:javascript复制
r"^s*![.*?](.*?)"

当识别出上述内容后,判断当前行为图片,这里仅对单独出现的图片做处理,不考虑和文字出现在同一行的图片。代码如下所示:

代码语言:javascript复制
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可自动发布到各个平台

0 人点赞