Python+Golang的好处
- 上传的脚本很自然的想到用python,似乎没有更好的选择了,速度取决于服务器带宽
- 图床用golang,早就想试一下golang写服务端了,gogs的性能给我很深的印象,部署后居然常驻只用了3.966MB,以后服务端还会考虑其他语言么,不可能的。
为什么不用Picgo
大部分攻略用的都是Picgo,试了一下除了上传外还有其他小功能,几百兆的体积只是干几句python干的事似乎有点浪费,于是有了下面这个脚本,一共3kb,还不用常驻。
import os
import sys
import json
import requests
import mimetypes
import argparse
import time
APP_DESC = """
upload pictures automatically
"""
print(APP_DESC)
if len(sys.argv) == 1:
sys.argv.append('--help')
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--source', type=str, nargs='+', help="", required=True)
# parser.add_argument('-c', '--config', default="./config.json", help="读取配置文件", required=True)
args = parser.parse_args()
# 从参数中获取要上传的文件列表
img_list = args.source
# print(img_list)
Auth_Code = 'abcdef123456'
Image_Host = 'https://demo.com'
def uploadImage(filePath):
fileName = os.path.basename(filePath)
fileName = bytes(fileName, "utf-8").decode("unicode_escape")
files = {'file': (fileName, open(filePath, 'rb'), mimetypes.guess_type(fileName)[0])}
# Convert all non ASCII characters to UTF-8 escape sequence
res = requests.post(url=Image_Host + '/upload',
files=files,
headers={'Authorization': Auth_Code, 'Uri': time.strftime("/%Y/%m/"), 'Image_Host': Image_Host})
return json.loads(res.text)
def parse_response_url(json, img_path):
# 从返回的json中解析字段
if json['status_code'] != 200:
print("{}\tweb端返回失败,可能是APIKey不对. status_code {} .".format(
img_path, json['status_code'])
)
else:
img_url = Image_Host + json["data"]["url"]
print(img_url)
def uploadImageList(img_list):
# 获得本地图片路径后,上传至图床并记录返回的json字段
for img in img_list:
# 先判断传过来的是本地路径还是远程图片地址
if "http" == img[:4]:
# 非本地图片的话可以考虑下载到本地再上传,但是没这个必要
print(img)
try:
filename = img.split('/')[-1]
r = requests.get(img, allow_redirects=True)
filepath = r'~/srv/tmp/' + filename
if os.path.isfile(filepath):
os.remove(filepath)
open(filepath, 'wb').write(r.content)
uploadImage(filepath)
os.remove(filepath)
print(img)
except:
print(img + "\t上传失败")
continue
else:
try:
res_json = uploadImage(img)
parse_response_url(res_json, img)
except:
print(img + "\t上传失败")
uploadImageList(img_list)
为什么要自建图床?而不是使用本地相对路径的目录或者是github/gittee免费图床
本地相对路径限制太大,不好分享,也不方便文档的在组织。
各种免费图床,这个世界变化这么快,我宁可自己花钱靠得住一些,也没有容量大小限制等问题。
自建会不会麻烦,其实自用的简单图床只需要很少的代码比如下面:
package main
import (
"io"
"log"
"net/http"
"os"
)
var (
// 文件 key
uploadFileKey = "file"
// 上传的图片保存根路径
filePath = "/images/"
)
func main() {
http.HandleFunc("/upload", uploadHandler)
if err := http.ListenAndServe(":8081", nil); err != nil {
log.Fatalf("error to start http server:%s", err.Error())
}
}
func uploadHandler(w http.ResponseWriter, r *http.Request) {
// 接受文件
file, header, err := r.FormFile(uploadFileKey)
if err != nil {
// ignore the error handler
}
log.Printf("selected file name is %s", header.Filename)
authValue := r.Header.Get("Authorization")
authCode := "abcdef123456"
authCodeEnv, exists := os.LookupEnv("Authorization_Code")
if exists {
authCode = authCodeEnv
}
if authValue != authCode {
log.Printf("auth fail")
return
}
path := filePath + r.Header.Get("Uri")
createFile(path)
imgPath := path + header.Filename
log.Printf("path is %s", path)
// 将文件拷贝到指定路径下,或者其他文件操作
dst, err := os.Create(imgPath)
if err != nil {
log.Fatalf("create file error :%s", err.Error())
// ignore
}
_, err = io.Copy(dst, file)
if err != nil {
log.Fatalf("copy file error :%s", err.Error())
// ignore
}
log.Printf("upload success")
io.WriteString(w, "{\"status_code\": 200, \"data\": {\"url\": \""+(r.Header.Get("Image_Host")+r.Header.Get("Uri")+header.Filename)+"\"}}")
}
//调用os.MkdirAll递归创建文件夹
func createFile(filePath string) error {
if !isExist(filePath) {
err := os.MkdirAll(filePath, os.ModePerm)
return err
}
return nil
}
// 判断所给路径文件/文件夹是否存在(返回true是存在)
func isExist(path string) bool {
_, err := os.Stat(path) //os.Stat获取文件信息
if err != nil {
if os.IsExist(err) {
return true
}
return false
}
return true
}
上面的图床自用问题不大,如果多人多博客使用还需要完善以下几点
- 只有auth code鉴权,一个泄露就挂了
- 路径没有安全检测,如果泄露了auth code就有隐患
服务端建议放在docker中。