部落格圖床遷移記

glumes發表於2019-05-03

微博圖床一時爽,遷移火葬場

前幾天在群裡看到說新浪微博圖床掛掉了,圖床上的圖片連結單獨訪問還可以,但是在部落格文章上就顯示不出來了。

去自己網站上看一下,果然,連部落格首頁圖片都載入不出來了,極大地影響了閱讀體驗呀。

還好圖片連結是可以訪問的,這就意味著圖片還在,還來得及做遷移和備份。

回顧之前用了好多免(hao)費(yang)圖(mao)床,從最早的 七牛,到 Cloudinary,再到 微博圖床。七牛由於是臨時域名,沒有及時備份圖片,導致圖都沒了,而 Cloudinary 和 微博圖床 倒還是可以繼續訪問的。不過這種薅羊毛總不是個辦法,萬一服務商政策變了,又得再遷移圖片了。

果然,免費的才是最貴的。

利用 VPS 搭建圖床

考慮到還有個 VPS 主機每個月都在續費呢,並且 15 G 的儲存空間和 1T 的流量也完全夠用了,就在 VPS 上面搭建 自己的圖床

正式搭建之前,還有一些準備工作,首先就是要有自己的 VPS ,如果你也想使用 Vultr 的主機,可以通過如下的連結進行註冊,獲得 $50 的優惠~~~

https://www.vultr.com/?ref=7845784-4F
複製程式碼

將自己的域名解析到伺服器地址,同時還需要安裝配置好 NginxPHP 等環境。

伺服器的配置可以使用 LNMP一鍵安裝包 一鍵安裝包。

域名的話,我在萬網註冊的,但是 DSN 解析使用的是 cloudflare ,這樣就可以使用 HTTPS 了,由於我是在子域名上搭建的圖床程式,所以還得在 cloudflare 中新增子域名的解析才行。

完成以上工作,就可以利用 Chevernote 程式來搭建圖床了。

Chevernote 的安裝過程還是比較簡單的,基本上按照步驟就好了,中間可能要設定一些許可權問題和 Nginx 配置。

自動遷移圖片到 Chevernote 圖床

安裝好 Chevernote 之後就可以開始將圖片遷移到圖床上了。

Chevernote 有個 API 介面,正好可以通過圖片連結,將圖片上傳到圖床上,通過這個介面就能搞定遷移了,前提的要拿到自己的 api key 。

// 通過該介面上傳圖片
GET http://mysite.com/api/1/upload/?key=12345&source=http://somewebsite/someimage.jpg&format=json
複製程式碼

簡單地寫了個 Python 指令碼來實現自動替換:

import os
import re
import requests

class ReplaceImage:

    path = ''
    lineNum = 0
    s = r'http[s]?://(?:ws1.sinaimg.cn|res.cloudinary.com)/.*?(?:jpg|png)'
    subpath = ''
    key=''
    upload_url = ''
    failednum = 0
    payload = {'key': key, 'source': upload_url, 'format': 'json'}

    website = 'https://image.glumes.com/api/1/upload/'

    def __init__(self):
        self.url_re = re.compile(self.s)

    def search(self, path,key):
        self.path = path
        self.handleDir(path)
        self.key = key

    def handleDir(self, path):
        dirs = os.listdir(path)
        for d in dirs:
            subpath = os.path.join(path, d)
            if os.path.isfile(subpath) and subpath.endswith(".md"):
                self.handleFile(subpath)
            elif os.path.isdir(subpath):
                self.handleDir(subpath)

        print("program end")

    def handleFile(self, fileName):
        print("\n")
        print("start read file %s..." % fileName)
        self.subpath = fileName

        f = open(fileName, 'r+')
        self.lineNum = 1
        data = ""
        while True:
            line = f.readline()
            if not line:
                break
            line = self.replaceImage(line)
            self.lineNum = self.lineNum + 1
            data += line
        f.close()

        with open(fileName, "w+") as f:
            f.writelines(data)

    def replaceImage(self, line):

        searchResult = self.searchImage(line)

        if not searchResult:
            return line
        oldline = line

        for result in searchResult:
            replace_url = self.uploadImage(result)
            line = self.replaceLine(line, result, replace_url)

        print("before replace is %s" % oldline)
        print("after replace is %s" % line)

        return line

    def searchImage(self, line):
        if self.url_re.search(line):
            all_search = search.url_re.findall(line)
            return all_search
        else:
            return []

    def replaceLine(self, line, search, url):
        return line.replace(search, url)

    def uploadImage(self, url):

        print("start uploadImage and file name is %s line num is %d..." % (self.subpath, self.lineNum))

        self.payload['source'] = url
        r = requests.get(self.website, self.payload)
        res = r.json()

        statuscode = res['status_code']

        if statuscode == 400:
            print("upload failed and code is %d and msg is %s" % (statuscode,res['error']['message']))
            print("upload image failed is %s and linenum is %d" % (url, self.lineNum))
            self.failednum += 1
            return url
        else:
            print("upload success and code is %d" % statuscode)
            print("upload img %s to %s" % (url, res['image']['url']))
            return res['image']['url']

if __name__ == "__main__":
    search = ReplaceImage()
    print("please input dir path and api key:\n")
    dir = input("dir:")
    key = input("key:")
    search.search(dir, key)
複製程式碼

實現思路也比較簡單:

  1. 首先是要遍歷給定目錄中的所有資料夾和檔案。
  2. 逐行讀取檔案內容,然後利用正規表示式匹配 Cloudinary 和微博圖床的圖片連結,找到該行中符合條件的連結。
  3. 再使用 requests 庫做網路請求,向 Chevernote 的 API 傳送 GET 請求,解析返回的 JSON 資料,得到上傳圖床後的連結。
  4. 將該行中匹配的圖片連結替換成上傳圖床後得到的連結,並寫入檔案中。
  5. 讀取完當前檔案後,重複步驟二,繼續讀取檔案,直到讀取結束。

程式碼的實現也比較簡單,主要就是一個正規表示式的匹配了:

    s = r'http[s]?://(?:ws1.sinaimg.cn|res.cloudinary.com)/.*?(?:jpg|png)'
複製程式碼

使用上面的表示式,就可以匹配到想要的內容,要注意在括號 () 表示或的匹配前面有 ?: ,否則拿到的匹配內容不對。

執行上述的程式碼,輸入正確的檔案地址和 api key,然後等待一段時間,就完成了上傳到圖床並自動轉換的功能。

不足之處

用自己的圖床也有不足之處,除了訪問速度沒有國內的圖床速度快,還有就是萬一 VPS 掛了,那圖床又 GG 了,一個方案就是:把 GitHub 當做備份的圖床。

因為圖片是儲存在 VPS 具體目錄下的,可以把圖片所在目錄當做工程,然後上傳到 Github ,萬一哪天 VPS 掛了,就把文章中的連結替換成 Github 上的連結就好了。

歡迎關注微信公眾號:【紙上淺談】,獲得最新文章推送~~~

掃碼關注

相關文章