去不图床适用方案一(已过时,参考方案三),自建图床适用方案二,最佳方案三适用多种情况

原理不难,自己第一次写,出了一些意外所以着重记录为笔记

前言

因为先前一直在使用兰空图床,@心流问我大量图片如何迁入。回想当时一千多张图片,按不同路径,我是一点一点用picgo拖进去的,但是picgo有最大上传限制50张。翻了翻文档,貌似接口可以做一个,以前没做过,所以尝试一下喽(这也是写这篇的原因,重点是学习实践,如果你是自建图床,直接去看心流的方案,方案一对自建来说有点脱裤子放屁,不是最佳方案)

参考:接口文档

第三方支持:因为之前卸载了图床,懒得搭建了,所以买了一个去不图床做测试用,对于没有服务器的同学有一个稳定的图床挺合适的(10r一年贵么?饭钱罢了)

思路

思路:大众使用本地存储的图库一般策略是『../img/Lsky图床迁入方案/01.png』,即用文件夹去分类每篇文章的图片(也许是其它方式的分类但一定有一个统一的前缀而不是一概的塞入一个文件夹里),那么我们想要将图片上传后,保持图片文件夹路径『/Lsky图床迁入方案/01.png』,仅批量替换文章中『../img』为域名『xxx.cn』即可以访问图片资源

小tip:替换文件夹中所有文章的图片地址前缀,可以巧用VScode,ctrl+shift+f全局替换所有md文件中的字符

方案一

优点:适用购买的兰空构建的图床(自建图床也可以但是方法二更好),用户不能直接对服务器操作,但有批量上传的需求,如去不图床与清酒图床

缺点:不能使用思路中的方案,图片路径将变为『域名+日期+uid』。例如https://bu.dusays.com/2022/10/23/6354e790488fa.png。且此问题无解,每次上传前需要修改角色组中的路径命名规则为图片所在文件夹名称如『Lsky图床迁入方案』,而这需要管理员权限

根据接口文档,先上传一张图片试试,正确填写13~15行,运行代码检查一下py模块是否存在?token、url是否正确?网页端是否正确上传?(切记勿开代理,否则报错Cannot connect to proxy

"""
@Author:张时贰
@Date:2022年10月21日
@CSDN:张时贰
@Blog:zhangshier.vip
@Function:上传单张图片测试
@request请求:https://blog.csdn.net/m0_37737957/article/details/123843265
"""
import os

import requests

token = 'Bearer 335|aatlbU9CTHKKbemsTXxB7F2uSd2PXL3m7By5uD7i' # token Bearer+空格+token
url = 'https://7bu.top/api/v1/upload' # 图床地址 域名/api/v1/upload'
path = 'test/background.png' # 图片路径

headers = {
# "Content-Type": "multipart/form-data", # 文档声明中必须有改字段,但是程序无法运行,详见github.com/lsky-org/lsky-pro/issues/403
"Authorization": token,
"Accept": "application/json",
}

if __name__ == "__main__":
files = {
"file": ('file.png', open ( path, 'rb' ).read (), 'image/png') # 加个read方法,之后使用os不会造成资源占用
}
json = {
# "album_id": 188 # 相册ID Int
# 如果你不是图床的搭建者,以下值请忽略
# "strategy_id": # 存储策略 Int
# 以下参数为企业版
# "permission": 0 # 权限 Int 1=公开,0=私有 默认0
# "expired_at": # 过期时间 String 'yyyy-MM-dd HH:mm:ss'
}
r = requests.post ( url, data=json, files=files, headers=headers )
r.encoding = "utf-8"
print ( r.json () )
os.remove ( path )

接下来是完整代码,根据注释说明正确填写59~69行,其中path为图片备份路径!服务器自建的,把上传频率设大一点,如果你是购买的杜老师的去不图床,每分钟上传频率与购买订阅有关,具体在仪表盘中查看

"""
@Author:张时贰
@Date:2022年10月21日
@CSDN:张时贰
@Blog:zhangshier.vip
@Function:批量上传图片
"""
import os
import time

import requests


def show_files(path, all_files):
# 首先遍历当前目录所有文件及文件夹
file_list = os.listdir ( path )
# 准备循环判断每个元素是否是文件夹还是文件,是文件的话,把名称传入list,是文件夹的话,递归
for file in file_list:
# 利用os.path.join()方法取得路径全名,并存入cur_path变量,否则每次只能遍历一层目录
cur_path = os.path.join ( path, file )
# 判断是否是文件夹
if os.path.isdir ( cur_path ):
show_files ( cur_path, all_files )
else:
all_files.append ( file )
if file.endswith ( ('.jpeg', '.jpg', '.png', '.gif', '.tif', '.bmp', '.ico', '.psd', '.webp') ):
end = (os.path.splitext ( file )[ -1 ])
end = end.replace ( '.', '' ) # 获取后缀
files = {
"file": (file, open ( cur_path, 'rb' ).read (), 'image/' + end) # 加个read方法,之后使用os不会造成资源占用
}
r = requests.post ( url, data=json, files=files, headers=headers )
r.encoding = "utf-8"
print ( r.json () )
# 去不图床仪表盘显示每分钟是200张请求,一次性上传多张图片,会出现上传失败
# 解决办法:每成功上传一张就删除一张(如果代码中断可以反复运行上传剩余图片直至所有图片上传完成),额外加一个sleep,超出频率就歇一会
while not r.json ()[ 'status' ]:
print ( '小歇一下叭' )
time.sleep ( 60 )
print ( '开干开干' )
r = requests.post ( url, data=json, files=files, headers=headers )
r.encoding = "utf-8"
print ( r.json () )
print ( '删除 ' + cur_path )
os.remove ( cur_path )

return all_files


if __name__ == "__main__":
'''
必填:
token:兰空的 token
url:域名/api/v1/upload
path:图片文件夹
选填 json 参考注释
请将本地文件夹备份,path=备份路径,原因详见35~36
'''
token = 'Bearer 335|aatlbU9CTHKKbemsTXxB7F2uSd2PXL3m7By5uD7i' # token Bearer+空格+token
url = 'https://7bu.top/api/v1/upload' # 图床地址 域名/api/v1/upload
path = 'test' # 图片文件夹路径,图片可以嵌套多个文件夹
json = {
# "album_id": 188 # 相册ID Int
# 如果你不是图床的搭建者,以下值请忽略
# "strategy_id": # 存储策略 Int
# 以下参数为企业版
# "permission": 0 # 权限 Int 1=公开,0=私有 默认0
# "expired_at": # 过期时间 String 'yyyy-MM-dd HH:mm:ss'
}
headers = {
# "Content-Type": "multipart/form-data", # 文档声明中必须有改字段,但是程序无法运行,详见github.com/lsky-org/lsky-pro/issues/403
"Authorization": token,
"Accept": "application/json"
}

contents = show_files ( path, [ ] ) # 参数一传入所有文章存在的目录

方案二

优点:对自建十分友好,直接上传文件夹即可,方法简单粗暴,三个方案中最快!往后的图片使用新的用户策略上传

缺点:仅支持自建的兰空图床

转自兰空图床使用体验以及图床迁移解决方案 | 心流

首先在 /www/lskypro/storage/app/uploads 上传本地的 img 文件夹(心流这个思路很巧,直接对网站根路径访问,我当时怎么就没想到呢,一直在想图片塞一个位置然后数据库里图片路径的数据怎么写,更没有想接口…)

Lsky图床迁入方案01

测试访问

Lsky图床迁入方案03

修改文件夹所有者以及文件权限:

chown -R 33 /www/lskypro/storage/app/uploads/img/
chmod -R 700 /www/lskypro/storage/app/uploads/img/

创建一个储存策略,其中储存路径是 /var/www/html/storage/app/uploads/img,最后的 img 就是上传服务器的图片文件夹名称,例如../img/xxxx/xxx.png

Lsky图床迁入方案02

在 vscode 一键替换这些图片链接即可

Lsky图床迁入方案04

新建文章时可在角色组编辑上传路径为文章链接即图片分类的文件夹名字,例如../img/d71ca461/xxx.png见下图。如果 CDN 没了或者链接失效,可以立即回滚到原方案

Lsky图床迁入方案05

方案三

方案三源自杜老师推荐博文:图床转换工具-picvt - Bing’s Blog,奈何兰空进行了一次大更,方案不适配了,本来想在方案一的基础上改进来,但是它(即优点)这么好用!所以…找了bug问题向@Bing大佬催更了一下😄

优点:适用购买图床与自建图床,多平台适配,适用路过图床迁移Github,Github迁移本地,本地迁移去不图床,且在上传图片的同时,将md中的图片链接更换

缺点:没有缺点即它的缺点!

下载作者源码:caibingcheng/picvt: 图传切换工具 (github.com),从本地迁移到去不图床:

git clone https://github.com/caibingcheng/picvt.git
cd picvt
python3 ./picvt.py -D /home/ubuntu/picvt/blog/ -F local -T 7bu --path /home/ubuntu/picvt/blog/ --user 1310446718@qq.com --token aatlbU9CTHKKbemsTXxB7F2uSd2PXL3m7By5uD7i

其中-D /home/ubuntu/picvt/blog/表示存放md的文件夹,图片在blog/img下,文章中图片格式为:

  • ![image-20220116151940879](/img/xxx/xxx02.png)
  • ![image-20220116151940879](img/xxx/xxx02.png)

所以-F local -T 7bu --path /home/ubuntu/picvt/blog/ 表示图片路径

--user 1310446718@qq.com --token aatlbU9CTHKKbemsTXxB7F2uSd2PXL3m7By5uD7i表示图床用户名与token

感谢@Bing提供的开源工具,解读代码学到了好多东西!

附获取相册ID

"""
@Author:张时贰
@Date:2022年10月21日
@CSDN:张时贰
@Blog:zhangshier.vip
@Function:查看相册ID
"""
import json

import requests

token = 'Bearer 335|aatlbU9CTHKKbemsTXxB7F2uSd2PXL3m7By5uD7i' # token,Bearer+空格+token
url = 'https://7bu.top/api/v1/albums' # 图床地址 域名/api/v1/albums

headers = {
"Content-Type": "multipart/form-data",
"Authorization": token,
"Accept": "application/json",
}

if __name__ == "__main__":
r = requests.get ( url, headers=headers )
r.encoding = "utf-8"
getJson = r.json ()[ 'data' ][ 'data' ]
photoID = [ ]
for i in getJson:
tmp = {'id': i[ 'id' ],
'name': i[ 'name' ]}
photoID.append ( tmp )
# print ( json.dumps(photoID,indent=4, ensure_ascii=False) )
for i in photoID:
print ( i )

后记

自己也迁移过了多次,图片一定要做好分类有一个文件夹的前缀方便后续迁移。无服务器方案包括Gitee(已被Gitee用户规则禁止)、Github套jsdelivr的各种cdn(太容易挂了)、帮@梦想高地搭建npm图床,还挺稳的,服务器方案包括兰空、Github Actions推送至服务器站点下(现在的策略)

虽然我已经不用兰空了,发这篇文章不仅是分享,更多的是记录自己的代码学习笔记

起初根据文档,我的request是这样写的,会报错『’album id’必须是一个数字』,但是输出type(data[ "album_id" ])就是int?

files = {
"file": ('file.png', open ( path, 'rb' ), 'image/png'),
"album_id": 188 # 相册ID Int
# 如果你不是图床的搭建者,以下值请忽略
# "strategy_id": # 存储策略 Int
# 以下参数为企业版
# "permission": 0 # 权限 Int 1=公开,0=私有 默认0
# "expired_at": # 过期时间 String 'yyyy-MM-dd HH:mm:ss'
}
r = requests.post ( url, files=files, headers=headers )
r.encoding = "utf-8"
print ( r.json () )

后经@二花指点说『requests 有三个 payload 参数:json、data、files,功能都不一样,注意区分,就记住 files 跟 data 是两个物种,不能放一起』(先前看了一些request教程,都没有提到过files,我就给塞到一个字典数据里了…,尝试搜了好多报错也没有找到)

之后再带着二花的指点,二次学习:data和json的本质区别是提交的形式不同,data是表单形式,json就默认json,在head指定content-type=application/json可以修改data的形式,所以我的代码中data实际上传的是一个json数据

谢谢@二花叕帮我解决疑问😁