客至汲泉烹茶, 抚琴听者知音

利用python将md文件的本地图片自动上传并替换网络链接

前言

几天前我搭建了自己的wiki网站,打算有时间就把本地的笔记(md格式)上传到网站上去,这样方便我方便地查看我的知识体系。我wiki网站用的是hexo+github+Wikitten主题,支持md,而且能通过github很方便地更新。本地笔记用的是vnote,这个笔记软件非常好用,就有一点:因为我做笔记的时候为了方便和数据安全,所有的图片全都存在本地,vnote为我生成的链接是类似![](_v_images/20191012183346115_26004.png =500x)的,我还不能手动下载笔记内的图片,只能到_v_images文件夹内找到它。

试想一下,我要把我的笔记传到wiki上需要几步?

有图片的情况下,首先要在vnote中打开笔记,切换成编辑模式,看一下图片的名字,然后打开图片文件夹,搜索到这张图片,上传到图床,返回链接替换本地链接……想想就兴致全无。

基于此,我用python写了一个小程序,可以帮我自动做以上的事。

github地址

思路

给定一个文件夹,需要遍历文件夹内所有md文件,这个好做,只要判断后缀就行了。

file[-2:] == 'md'

接下来要复制到目标路径中,毕竟我不想改动原文件,这个用shutil.copy

然后打开md文件,搜索本地图片链接,这里需要用到正则表达式,但是我不知道如何全文替换,只能用最笨的方法,找到一个替换一个。

pattern = re.compile(r'_v_images/.+\s??=??\d*?x??')
replacelist = pattern.findall(content)
for each in replacelist:
    content = pattern.sub(pic_url +')',content,count = 1) 

这里面有个小问题,我不知道为什么正则会替换掉本地图片格式的最后一个括号,只能手动加上一个了。

替换的中间,还需要一个上传到图床的函数,我首先找了支持api的图床,发现免费的没多少,最后选择了sm.ms。它的api有两种,api1是不需要账号的,但是似乎有频率的限制,api2需要账号,每个账号给5g的空间。先拿api1练练手。

url='https://sm.ms/api/upload'
file_obj=open(pic_path,'rb')
file={'smfile':file_obj}    # 参数名称必须为smfile 
pic_url = data_result['data']['url']

但是每次都要上传图片太傻了,因为我可能会经常改动笔记,再次转化的时候会有大量已经上传过的图片,不说图床的频率限制,上传图片也要比较长的时间,更何况即使上传了sm.ms也会提示你图片重复,所以最好有个图片检测机制,如果已经上传过,就获取存储在本地的已经上传好的图片链接。

于是我选择了mongodb数据库,配合hashlib生成的图片hash值进行检测。

这下程序就基本完成了。

代码

# -*- coding: utf-8 -*-
"""
Created on Fri Sep 13 13:14:22 2019
        self.
@author: 雁陎
"""

import os
import re
from shutil import copy
from requests import post
from hashlib import sha1
import pymongo

def copyfile(org_path,copy_path):
    current_folder = os.listdir(org_path) # 路径下所有文件组成一个列表
    for file in current_folder:
        if file[-2:] == 'md':
            file_path = org_path+'\\'+ file  # 拼接出要存放的文件夹的路径
            copy(file_path,copy_path) # 将指定的文件file复制到file_dir的文件夹里面

def openmd(org_path,copy_path):  # 替换url链接
    myclient = pymongo.MongoClient("mongodb://localhost:27017/")  # 连接数据库
    mydb = myclient["mdpicture"]   # 创建数据库
    mycol = mydb["hash_url"]   # 创建集合(数据表)
    pattern = re.compile(r'_v_images/.+\s??=??\d*?x??')
    for file in os.listdir(copy_path):        
        file_path = copy_path+'\\'+ file
        with open(file_path,'r+',encoding = "utf-8") as handler:
             content = handler.read()
             handler.seek(0)
             handler.truncate()
             replacelist = pattern.findall(content)
             for each in replacelist:
                 pic_name = each[:int(each.index(r'.')+4)]
                 pic_path = org_path+'\\'+pic_name.replace('/','\\')
                 pic_url = upload(mycol,pic_path,pic_name)
                 if pic_url:
                    content = pattern.sub(pic_url +')',content,count = 1)   
                    # 不知为什么正则替换会把最后一个括号替换掉,所以只能手动加了一个  
             handler.write(content)
             print(file,"链接已经转化完毕")

def calchash(filepath):  # 计算图片hash值
    with open(filepath,'rb') as f:
        sha1obj = sha1()
        sha1obj.update(f.read())
        hash = sha1obj.hexdigest()
        return hash

        
def upload(mycol,pic_path,pic_name): # 上传图片至sm.ms
    url='https://sm.ms/api/upload'
    try:
        file_obj=open(pic_path,'rb')
        file={'smfile':file_obj}    # 参数名称必须为smfile 
        pic_hash = calchash(pic_path)
        # 先检查是否上传过,若无才进行上传
        if mycol.find_one({"hash": pic_hash}):
            print('查询mongodb,图片',pic_name,'已存在')
            result =  mycol.find_one({"hash": pic_hash})['url']       
        else:
            data_result=post(url,data=None,files=file).json()
            if data_result['message'] == 'Upload success.':
                mycol.insert_one({"hash":pic_hash,"url":data_result['data']['url'],"delete":data_result['data']['delete']}) 
                print(pic_name,'上传成功,链接为',data_result['data']['url'],'删除链接为',data_result['data']['delete'])
                result =  data_result['data']['url']
            elif data_result['message'][0:21] == 'Image upload repeated':
                print(pic_name,'上传失败,图片已存在')    
                result = None    
            else:
                print('其他错误')
                result = None
    except FileNotFoundError:
        print(pic_name,'图片未找到,请检查该图是否存在')
        result = None
    return result

def main():
    org_path = r'E:\vnote笔记数据\待转区'  # 原始路径
    copy_path = r'E:\vnote笔记数据\转化完成区'  # 目标路径,原始路径的md会将所有图片转为url后放到这里
    copyfile(org_path,copy_path)
    openmd(org_path,copy_path)


if __name__ == '__main__':
    main()

添加新评论