博客图床迁移记

图床一时爽,迁移火葬场

前几天在群里看到说新浪微博图床挂掉了,图床上的图片链接单独访问还可以,但是在博客文章上就显示不出来了。

去自己网站上看一下,果然,连博客首页图片都加载不出来了,极大地影响了阅读体验呀。

还好图片链接是可以访问的,这就意味着图片还在,还来得及做迁移和备份。

回顾之前用了好多免(hao)费(yang)图(mao)床,从最早的 七牛,到 Cloudinary,再到 微博图床。七牛由于是临时域名,没有及时备份图片,导致图都没了,而 Cloudinary 和 微博图床 倒还是可以继续访问的。不过这种薅羊毛总不是个办法,万一服务商政策变了,又得再迁移图片了。

果然,免费的才是最贵的。

利用 VPS 搭建图床

考虑到还有个 VPS 主机每个月都在续费呢,并且 15 G 的存储空间和 1T 的流量也完全够用了,就在 VPS 上面搭建 自己的图床 。

正式搭建之前,还有一些准备工作,首先就是要有自己的 VPS ,如果你也想使用 Vultr 的主机,可以通过如下的链接进行注册,获得 $50 的优惠~~~

1https://www.vultr.com/?ref=7845784-4F

将自己的域名解析到服务器地址,同时还需要安装配置好 NginxPHP 等环境。

服务器的配置可以使用 LNMP一键安装包 一键安装包。

域名的话,我在万网注册的,但是 DSN 解析使用的是 cloudflare ,这样就可以使用 HTTPS 了,由于我是在子域名上搭建的图床程序,所以还得在 cloudflare 中添加子域名的解析才行。

完成以上工作,就可以利用 Chevernote 程序来搭建图床了。

Chevernote 的安装过程还是比较简单的,基本上按照步骤就好了,中间可能要设置一些权限问题和 Nginx 配置。

自动迁移图片到 Chevernote 图床

安装好 Chevernote 之后就可以开始将图片迁移到图床上了。

Chevernote 有个 API 接口,正好可以通过图片链接,将图片上传到图床上,通过这个接口就能搞定迁移了,前提的要拿到自己的 api key 。

1// 通过该接口上传图片
2GET http://mysite.com/api/1/upload/?key=12345&source=http://somewebsite/someimage.jpg&format=json

简单地写了个 Python 脚本来实现自动替换:

  1import os
  2import re
  3import requests
  4
  5class ReplaceImage:
  6
  7    path = ''
  8    lineNum = 0
  9    s = r'http[s]?://(?:ws1.sinaimg.cn|res.cloudinary.com)/.*?(?:jpg|png)'
 10    subpath = ''
 11    key=''
 12    upload_url = ''
 13    failednum = 0
 14    payload = {'key': key, 'source': upload_url, 'format': 'json'}
 15
 16    website = 'https://image.glumes.com/api/1/upload/'
 17
 18    def __init__(self):
 19        self.url_re = re.compile(self.s)
 20
 21    def search(self, path,key):
 22        self.path = path
 23        self.handleDir(path)
 24        self.key = key
 25
 26    def handleDir(self, path):
 27        dirs = os.listdir(path)
 28        for d in dirs:
 29            subpath = os.path.join(path, d)
 30            if os.path.isfile(subpath) and subpath.endswith(".md"):
 31                self.handleFile(subpath)
 32            elif os.path.isdir(subpath):
 33                self.handleDir(subpath)
 34
 35        print("program end")
 36
 37    def handleFile(self, fileName):
 38        print("\n")
 39        print("start read file %s..." % fileName)
 40        self.subpath = fileName
 41
 42        f = open(fileName, 'r+')
 43        self.lineNum = 1
 44        data = ""
 45        while True:
 46            line = f.readline()
 47            if not line:
 48                break
 49            line = self.replaceImage(line)
 50            self.lineNum = self.lineNum + 1
 51            data += line
 52        f.close()
 53
 54        with open(fileName, "w+") as f:
 55            f.writelines(data)
 56
 57    def replaceImage(self, line):
 58
 59        searchResult = self.searchImage(line)
 60
 61        if not searchResult:
 62            return line
 63        oldline = line
 64
 65        for result in searchResult:
 66            replace_url = self.uploadImage(result)
 67            line = self.replaceLine(line, result, replace_url)
 68
 69        print("before replace is %s" % oldline)
 70        print("after replace is %s" % line)
 71
 72        return line
 73
 74    def searchImage(self, line):
 75        if self.url_re.search(line):
 76            all_search = search.url_re.findall(line)
 77            return all_search
 78        else:
 79            return []
 80
 81    def replaceLine(self, line, search, url):
 82        return line.replace(search, url)
 83
 84    def uploadImage(self, url):
 85
 86        print("start uploadImage and file name is %s line num is %d..." % (self.subpath, self.lineNum))
 87
 88        self.payload['source'] = url
 89        r = requests.get(self.website, self.payload)
 90        res = r.json()
 91
 92        statuscode = res['status_code']
 93
 94        if statuscode == 400:
 95            print("upload failed and code is %d and msg is %s" % (statuscode,res['error']['message']))
 96            print("upload image failed is %s and linenum is %d" % (url, self.lineNum))
 97            self.failednum += 1
 98            return url
 99        else:
100            print("upload success and code is %d" % statuscode)
101            print("upload img %s to %s" % (url, res['image']['url']))
102            return res['image']['url']
103
104if __name__ == "__main__":
105    search = ReplaceImage()
106    print("please input dir path and api key:\n")
107    dir = input("dir:")
108    key = input("key:")
109    search.search(dir, key)

实现思路也比较简单:

  1. 首先是要遍历给定目录中的所有文件夹和文件。
  2. 逐行读取文件内容,然后利用正则表达式匹配 Cloudinary 和微博图床的图片链接,找到该行中符合条件的链接。
  3. 再使用 requests 库做网络请求,向 Chevernote 的 API 发送 GET 请求,解析返回的 JSON 数据,得到上传图床后的链接。
  4. 将该行中匹配的图片链接替换成上传图床后得到的链接,并写入文件中。
  5. 读取完当前文件后,重复步骤二,继续读取文件,直到读取结束。

代码的实现也比较简单,主要就是一个正则表达式的匹配了:

1    s = r'http[s]?://(?:ws1.sinaimg.cn|res.cloudinary.com)/.*?(?:jpg|png)'

使用上面的表达式,就可以匹配到想要的内容,要注意在括号 () 表示或的匹配前面有 ?: ,否则拿到的匹配内容不对。

执行上述的代码,输入正确的文件地址和 api key,然后等待一段时间,就完成了上传到图床并自动转换的功能。

不足之处

用自己的图床也有不足之处,除了访问速度没有国内的图床速度快,还有就是万一 VPS 挂了,那图床又 GG 了,一个方案就是:把 GitHub 当做备份的图床。

因为图片是存储在 VPS 具体目录下的,可以把图片所在目录当做工程,然后上传到 Github ,万一哪天 VPS 挂了,就把文章中的链接替换成 Github 上的链接就好了。

原文发布于微信公众号 - 纸上浅谈(glumes_blog)

原文发表时间:2019-05-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券