應對掘金CDN開啓防盜鏈 記一次爬取markdown圖片的經歷

使用markdown寫文章有什麼好處?

  • markdown是一種純文本格式(後綴.md), 寫法簡單, 不用考慮排版, 輸出的文章樣式簡潔優雅
  • markdown自帶開源屬性, 一次書寫後, 便可在任意支持markdown格式的平臺發佈 (國內支持的平臺有, 掘金, 知乎(以文檔方式導入), 簡書(本來是最好用的, 最近在走下坡路))
  • 著名代碼託管平臺github, 每一個代碼倉庫的說明書README.md就是典型的markdown格式

原來我喜歡在 掘金或簡書後臺 寫markdown文章, 而後複製粘貼到 gitbook(前提是gitbook已經和github作了關聯), 就能夠發佈到github倉庫, 因爲內容很吸引人, 在github收穫一波stars(stars至關於點贊)python

但最近掘金和簡書等平臺忽然宣佈, 在本身網站存儲的圖片再也不支持外鏈, 也就是在其它網站請求本站服務器存儲的圖片一概404 ! 簡書是直接封了外鏈; 掘金髮了一個公告, 延期一週執行;git

怎麼辦?

我只好將md文檔保存到本地, 而後根據md保存的源圖片信息,使用爬蟲爬取圖片到本地, 而後將圖片上傳到github倉庫(github倉庫支持圖片上傳, 並且不封外鏈), 將原圖片信息替換爲github倉庫保存的圖片信息github

首先在github新建一個名爲 GraphBed 的倉庫, 用來存儲圖片

  • 將倉庫clone到本地 的 /Users/lijianzhao/github文件夾
cd /Users/lijianzhao/github
git clone https://github.com/zhaoolee/GraphBed.git
複製代碼

並保證 在此文件夾下, 有權限push到github, 權限添加方法 www.jianshu.com/p/716712278…bash

將github已有的.md文章對應的倉庫下載到本地(以星聚棄療榜爲例)

git clone https://github.com/zhaoolee/StarsAndClown.git
複製代碼

編寫python腳本 md_images_upload.py

此腳本:

  • 能搜索當前目錄下全部md文件, 將每一個md中的圖片爬取到本地, 存放到/Users/lijianzhao/github/GraphBed/images目錄;
  • 圖片爬取完成後, 自動將/Users/lijianzhao/github/GraphBed/images目錄下的全部圖片, push到Github
  • 使用Github中的新圖片地址,替換原圖片地址
  • 大功告成
import os
import imghdr
import re
import requests
import shutil
import git
import hashlib

## 用戶名
user_name = "zhaoolee";
## 倉庫名
github_repository = "GraphBed";

## git倉庫在本機的位置
git_repository_folder = "/Users/lijianzhao/github/GraphBed"

## 存放圖片的git文件夾路徑
git_images_folder = "/Users/lijianzhao/github/GraphBed/images"

## 設置忽略目錄
ignore_dir_list=[".git"]

# 設置用戶代理頭
headers = {
    # 設置用戶代理頭(爲狼披上羊皮)
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36",
}


# 根據輸入的url輸入md5命名
def create_name(src_name):
    src_name = src_name.encode("utf-8")
    s = hashlib.md5()
    s.update(src_name)
    return s.hexdigest()

# 獲取當前目錄下全部md文件
def get_md_files(md_dir):
    md_files = [];
    for root, dirs, files in sorted(os.walk(md_dir)):
        for file in files:
            # 獲取.md結尾的文件
            if(file.endswith(".md")):
                file_path = os.path.join(root, file)
                print(file_path)
                #忽略排除目錄
                need_append = 0
                for ignore_dir in ignore_dir_list:
                    if(ignore_dir in file_path.split("/") == True):
                        need_append = 1
                if(need_append == 0):
                    md_files.append(file_path)
    return md_files

# 獲取網絡圖片
def get_http_image(image_url):
    image_info = {"image_url": "", "new_image_url": ""}
    file_uuid_name = create_name(image_url)
    image_data = requests.get(image_url, headers=headers).content
    # 建立臨時文件
    tmp_new_image_path_and_name = os.path.join(git_images_folder, file_uuid_name)
    with open(tmp_new_image_path_and_name, "wb+") as f:
        f.write(image_data)
    img_type = imghdr.what(tmp_new_image_path_and_name)
    if(img_type == None):
        img_type = ""
    else:
        img_type = "."+img_type
    # 生成新的名字加後綴
    new_image_path_and_name = tmp_new_image_path_and_name+img_type
    # 重命名圖片
    os.rename(tmp_new_image_path_and_name, new_image_path_and_name)

    new_image_url = "https://raw.githubusercontent.com/"+ user_name + "/" +github_repository+"/master/"+git_images_folder.split("/")[-1]+"/"+new_image_path_and_name.split("/")[-1]
    image_info = {
        "image_url": image_url,
        "new_image_url": new_image_url
    }
    print(image_info)

    return image_info


# 獲取本地圖片
def get_local_image(image_url):
    image_info = {"image_url": "", "new_image_url": ""}
    try:
        # 建立文件名
        file_uuid_name = uuid.uuid4().hex
        # 獲取圖片類型
        img_type = image_url.split(".")[-1]
        # 新的圖片名和文件後綴
        image_name = file_uuid_name+"."+img_type
        # 新的圖片路徑和名字
        new_image_path_and_name = os.path.join(git_images_folder, image_name);
        shutil.copy(image_url, new_image_path_and_name)
        # 生成url
        new_image_url = "https://raw.githubusercontent.com/"+ user_name + "/" +github_repository+"/master/"+git_images_folder.split("/")[-1]+"/"+new_image_path_and_name.split("/")[-1]
        # 圖片信息
        image_info = {
            "image_url": image_url,
            "new_image_url": new_image_url
        }
        print(image_info)
        return image_info
    except Exception as e:
        print(e)

    return image_info
    
# 爬取單個md文件內的圖片
def get_images_from_md_file(md_file):
    md_content = ""
    image_info_list = []
    with open(md_file, "r+") as f:
        md_content = f.read()
        image_urls = re.findall(r"!\[.*?\]\((.*?)\)", md_content)
        for image_url in image_urls:
            # 處理本地圖片
            if(image_url.startswith("http") == False):
                image_info = get_local_image(image_url)
                image_info_list.append(image_info)
            # 處理網絡圖片
            else:
                # 不爬取svg
                if(image_url.startswith("https://img.shields.io") == False):
                    try:
                        image_info = get_http_image(image_url)
                        image_info_list.append(image_info)
                    except Exception as e:
                        print(image_url, "沒法爬取, 跳過!")
                        pass
        for image_info in image_info_list:
            md_content = md_content.replace(image_info["image_url"], image_info["new_image_url"])

        print("替換完成後::", md_content);

        md_content = md_content

    with open(md_file, "w+") as f:
        f.write(md_content)


def git_push_to_origin():
    # 經過git提交到github倉庫
    repo = git.Repo(git_repository_folder)
    print("初始化成功", repo)
    index = repo.index
    index.add(["images/"])
    print("add成功")
    index.commit("新增圖片1")
    print("commit成功")
    # 獲取遠程倉庫
    remote = repo.remote()
    print("遠程倉庫", remote);
    remote.push()
    print("push成功")

def main():
    if(os.path.exists(git_images_folder)):
        pass
    else:
        os.mkdir(git_images_folder)
    # 獲取本目錄下全部md文件
    md_files = get_md_files("./")

    # 將md文件依次爬取
    for md_file in md_files:
      # 爬取單個md文件內的圖片
      get_images_from_md_file(md_file)
    
    git_push_to_origin()
    


if __name__ == "__main__":
    main()
複製代碼
幾個優化點:
  • 支持md引用本地目錄圖片的爬取(之後就能夠在本地編寫markdown文件了, 編寫完成後, 運行上述腳本, 便可自動將md引用的本地圖片上傳到github, 同時本地圖片的引用地址被github在線圖片地址所取代)
  • 爲防止圖片重名, 使用uuid重命名圖片名稱(後面發現使用uuid會致使相同的網絡圖片反覆爬取保存, 因此後面使用網絡圖片的url地址對應的md5碼爲新名稱, 便可防止生成內容相同, 名稱不一樣的圖片)
  • 爬取本地圖片,依然使用uuid重名防止重複(我的命名可能會反覆使用001.png, 002.png等經常使用名稱)
  • 對爬取的圖片, 進行了類型判斷, 自動補充圖片擴展名

使用方法

  1. 安裝python3

安裝方法見 Python數據挖掘 環境搭建服務器

  1. 將腳本md_images_upload.py放到/Users/lijianzhao/github/GraphBed目錄 (這裏目錄能夠按照本身的來, 但腳本頂部的幾行參數也要修改)

  1. 在命令行安裝相關依賴包
pip3 install requests
pip3 install git
複製代碼
  1. 從命令行進入/Users/lijianzhao/github/GraphBed
cd /Users/lijianzhao/github/GraphBed
複製代碼
  1. 運行腳本
python3 md_images_upload.py
複製代碼

這裏我已是第二次替換圖片了, 因此上面的動圖顯示的原圖片也是GitHub的圖片, 說明腳本第一次已徹底替換成功~

圖片又能夠顯示了markdown

被替換爲github圖片替換後md在線展現地址: zhaoolee.gitbooks.io/starsandclo…網絡

相關文章
相關標籤/搜索