完了,小林网站的图片都挂了
作者:小林coding
图解网站:https://xiaolincoding.com/
大家好,我是小林。
最近几天收到好几位读者私信说,我的网站有些文章的图片加载不出来,是不是被攻击了?
倒不是这个原因,是因为我用的图床在国内凉了。
我的图床方案是 Github + jsDelivr CDN,这套不花一毛钱的方案,一用就用了好几年了。
羊毛总就会被薅完的一天。在去年 12 月 jsDelivr 就出问题了,jsDelivr 域名备案被吊销,导致国内 CDN 提供商网宿移除了 jsDelivr 的账号,然后访问的速度越来越慢。
现在测速 jsDelivr CDN,访问延时基本都是好几千毫秒,这感人速度,感谢大家没把图解网站拉黑
五一节也来了,假期里肯定有不少人也会卷起来,更换图床地址这件事迫在眉头,所以自己掏钱买了 OSS 存储服务器。
可是,我网站的图片有 1000 多张啊!不可能手动一个一个去替换每一张图片的图床地址吧,这太不符合程序员的做法了。
这种繁琐的事情,肯定得要用程序来解决。所以,后面我想了一个快速替换图床地址的方案:
先把所有图片下载下来,并且要按 URL 目录结构保存图片; 然后以目录的方式上传所有图片到某云厂商 OSS 对象服务; 最后把所有文章的图床地址的域名替换到新图床地址的域名;
这个替换方案保持了原本图片地址的 URL 层级结构,所以只需要替换图片地址的域名就可以了。
接下来,给大家实战一把。
下载图片
过滤图片地址到文件
首先,需要把所有文章用了 cdn.jsdelivr.net
的图片地址给过滤到文件。
进入文章目录后,通过下面这个命令递归找出所有文章的图片地址。
grep -r "cdn.jsdelivr.net" ./*
通过下面这个命令,可以看到总共有 839 处地方用了 jsdelivr 图床地址。
[root@xiaolin docs]# grep -r "cdn.jsdelivr.net" ./ | wc -l
839
但是这样过滤还不够,得把图片地址单独过滤出来,于是我通过下面这个命令,把(地址)
字符串中的地址
给过滤出来。
grep -r "cdn.jsdelivr.net" ./* | cut -d '(' -f2 | cut -d ')' -f1
然后把过滤出来的图片地址保存到一个 list.txt 文件中。
grep -r "cdn.jsdelivr.net" ./* | cut -d '(' -f2 | cut -d ')' -f1 > list.txt
编写 Python 程序
过滤出所有文章的图片地址后,就可以写一个 Python 程序,遍历 list.txt 文件中的图片地址,然后将图片下载下来,并按照 URL 的目录结构保存图片文件。
我在网上找了个下载网站文件 Python 程序,然后在此基础上改了一点。
import urllib.request
import requests
import re, os
from urllib.parse import quote
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
def get_file(url):
'''
递归下载网站的文件
:param url:
:return:
'''
if isFile(url):
try:
download(url)
except Exception as e:
print(url)
print("download failed : " + str(e))
pass
else:
urls = get_url(url)
for u in urls:
get_file(u)
def isFile(url):
'''
判断一个链接是否是文件
:param url:
:return:
'''
if url.endswith('/'):
return False
else:
return True
def download(url):
'''
:param url:文件链接
:return: 下载文件,自动创建目录
'''
full_name = url.split('//')[-1]
url = quote(url, safe='/:?=@')
filename = full_name.split('/')[-1]
dirname = "/".join(full_name.split('/')[:-1])
if os.path.exists(dirname):
pass
else:
os.makedirs(dirname, exist_ok=True)
print(url)
urllib.request.urlretrieve(url, full_name)
def get_url(base_url):
'''
:param base_url:给定一个网址
:return: 获取给定网址中的所有链接
'''
text = ''
try:
text = requests.get(quote(base_url, safe='/:?=@')).text
except Exception as e:
print("error - > ",base_url,e)
pass
reg = '<a href="(.*)">.*</a>'
urls = [base_url + url for url in re.findall(reg, text) if url != '../']
return urls
if __name__ == '__main__':
'''
遍历list.txt文件中的 URL,并下载
'''
with open('list.txt', 'r') as f:
lines = f.readlines()
url_list = []
for line in lines:
get_file(line.strip('\n'))
执行完 Python 程序后,图片都按 URL 目录结构保存起来了。
上传图片
下载完图片后,直接把图片目录上次到某云厂商 OSS 对象存储服务。
所以,最后的工作就是把全部文章里的图片地址中的域名从 cdn.jsdelivr.net
替换成 xiaolincoding.oss-cn-shenzhen.aliyuncs.com
。
替换图床地址
替换文件里的字符串,我们可以使用 sed 命令。举个例子,假设 a.txt 文件内容如下:
https://cdn.jsdelivr.net/abc/1.jpg
然后我们可以使用下面这条命令替换图片域名地址:
sed -i 's/cdn.jsdelivr.net/xiaolincoding.oss-cn-shenzhen.aliyuncs.com/g' a.txt
注意这条 sed 命令是加了 -i
参数,是直接修改文件内容的,所以最好修改文件前,先去掉 -i
参数,测试下输出的结果是否是你预期的。
我写了一个简单 Shell 脚本,把所有文章中的图片域名地址替换掉。
#!/bin/bash
for file in `find /home/vuepress_xiaolincoding/docs/ -name "*.md"`
do
echo $file
sed -i 's/cdn.jsdelivr.net/xiaolincoding.oss-cn-shenzhen.aliyuncs.com/g' $file
done
执行完这个 Shell 脚本后,替换图床地址的工作就全部完成了!
最后,测试一下访问图片的速度,访问速度从几千毫秒下降至 100 毫秒了。
忘记充钱
网站的图床在昨晚就迁移完了,然后早上有读者说,网站的图片都挂了。
然后看手机短信,原来是我没有充钱。。。。。
哦对,五一节了,大家不要偷偷自己卷,要卷一起卷