逃出七牛云
备份云中数据
由于众所周知的原因,国内的云存储服务不再可靠。但是我在过往中大量的使用了七牛云的外链,所以需要将七牛中的文件保存起来。
在海外vps或者国内服务仍然可用的情况下,使用七牛的SDK批量备份文件,代码如下:
# -*- coding: utf-8 -*-
# RUN TIME: Python 3.6.5
# CREATION ON: 7/30, 2018
from qiniu import Auth, BucketManager
from secret import key, secret
import urllib.request
import threading
import time,os,shutil
# 七牛相关配置
host = "rs.qbox.me"
q = Auth(key, secret)
bucket = BucketManager(q)
cdn_prefix = 'http://r9rqga72n.bkt.clouddn.com/'
bucket_name = "evink-southerneast"
prefix = 'images'
threads_count = 0
def get_file_list():
bucket = BucketManager(q)
# 前缀
prefix = f"/{prefix}"
# 列举条目
limit = 1000
# 列举出除'/'的所有文件以及以'/'为分隔的所有前缀
delimiter = None
# 标记
marker = None
ret, eof, info = bucket.list(bucket_name, prefix, marker, limit, delimiter)
# print(info)
items: list = ret.get('items')
# 所有百分号(%25)都被转义为了百分号(%), 将 25 补充回去
keys = []
for item in items:
key = item.get('key')
idx = key.find('%')
if idx >= 0:
key = f'{key[:idx+1]}25{key[idx+1:]}'
keys.append(key)
print(keys)
return keys
def download(key, cb):
try:
urllib.request.urlretrieve(cdn_prefix+key, key)
cb(None, None)
except Exception as e:
cb(key, e)
return False
def download_callback(key, e):
global threads_count
if key:
print(e)
print(f'Failed: {key}')
threads_count -= 1
def download_task(key):
global threads_count
while True:
if threads_count < 10:
break
time.sleep(1)
t = threading.Thread(target=download, args=(key, download_callback))
threads_count += 1
t.start()
if __name__ == '__main__':
keys = get_file_list()
dp = __file__[:-7]
shutil.rmtree(f'{dp}{imags}')
os.mkdir(f'{dp}{imags}')
for key in keys:
download_task(key)
由于使用了多线程,大量访问可能会导致七牛云拒绝响应,或者下载超时,控制台会打印出失败的文件,需要手动处理,例如:
<urlopen error retrieval incomplete: got only 1048576 out of 1592895 bytes>
Failed: images/2017-01-26/IMG_3434.JPG
<urlopen error retrieval incomplete: got only 0 out of 2400540 bytes>
Failed: images/2021-11-07/2021_11_07_07_16_IMG_4437.jpg
<urlopen error retrieval incomplete: got only 0 out of 3448056 bytes>
Failed: images/2021-11-07/2021_11_06_12_47_IMG_4407.jpg
<urlopen error retrieval incomplete: got only 0 out of 2354957 bytes>
Failed: images/2021-11-07/2021_11_07_11_24_IMG_4438.jpg
<urlopen error retrieval incomplete: got only 0 out of 3071984 bytes>
Failed: images/IMG_0747.JPG
注:如果大量失败,需要手动调整代码以适用于不同的需求。
上传文件至新的云存储(B2Cloud)中
B2Cloud免费用户有10G存储空间和1G/天的流量,虽然1G流量看起来很少,但是套上CDN以后基本是用不完的。
B2Cloud提供了方便的CLI工具,备份文件可使用CLI上传,亦可以使用PicGo+B2上传插件上传,前者适用于VPS用户,而后者有GUI。
使用CLI
1.基于Python版本的B2 CLI
$ pip3 install --upgrade b2
或者下载对应平台的可执行文件,点这里查看下载页
2.B2 Auth
输入命令,并按照提示输入KeyId和AppKey
$ b2 authorize-account
如何获取Id和Key,见下图:

3.上传文件
$ b2 upload-file <your_bucket_name> <local_file_name> "<prefix>/<file_name>"
使用GUI上传
1.安装PicGo
2.安装B2上传插件
CDN的选择
虽然现在可以访问存储桶内的资源了,但速度慢如蜗牛,加上B2提供的外链丑陋,都是不想使用它的理由。而且如果直接使用B2外链,那么之前使用的cdn链接则处于失效状态。所以套接一个CDN网络很重要。
Cloudflare
Backblaze可以使用Cloudflare加速,并且官方出了教程,详见:https://help.backblaze.com/hc/en-us/articles/217666928-Using-Backblaze-B2-with-the-Cloudflare-CDN
另外使用CF的边缘网络进行URL重写(或者Workers),可以去掉冗余的/file/<your_bucket_name>前缀,具体效果如下:
https://cdn.evink.cn/file/test-bucket/picgo/20220423172558.png —> https://cdn.evink.cn/picgo/20220423172558.png

CloudImage
相较于Cloudfalre,CloudImage更专注于提供于图片分发服务,它有多达32种的预处理图片格式和每个月25G的免费流量和图片缓存,虽然CF也提供这些功能,但是CF需要额外收费,所以CloudImage是一个非常友好的替代品。
CloudImage使用也非常简单,它会提供一个token给你,然后你就可以加速互联网上的任意图片资源了。例如:
-
Cloudimage链接 https://<token>.cloudimg.io/sample.li/bag_demo.jpg
上面两个链接均指向此图:

这两个链接会指向同一张图片,当然CloudImage可设置
除此之外,CloudImage还提供图片预处理功能,本站的相册之前一直使用的七牛云的预处理功能,迁移至CloudImage之后,只需少量的修改后便可以继续使用。而且CloudImage提供了alias,以缩短图片链接。
原图: https://img.evink.cn/light/fullsizeoutput_30b.jpeg
- CloudImage 预处理 https://img.evink.cn/light/fullsizeoutput_30b.jpeg?w=200&h=200&gravity=face
- CloudImage Alias https://img.evink.cn/light/fullsizeoutput_30b.jpeg?p=c_face
上面两个链接均指向此图:

最后
CF和CloudImage既可以单独使用,亦可以相互结合使用,更多功能不在此赘述。
这一次转移,有点仓促,但不完全出乎意料,很早以前我就在寻找七牛云的替代品了,并不是因为它难用,相反我认为它非常好用。但朝令夕改的政策,不自由的互联网环境,加上这次的清朗行动的铁拳,都是我逃离七牛云的原因。作为个人玩家,真的没有多余的精力去应付无休止的电话骚扰。