[python] 溜了,溜了,七牛雲圖片資源批量下載 && 自建圖床伺服器
故事背景:
七牛雲最近一波測試域名操作真是把我坑死了!這簡直和百度贈送你2T網盤,之後再限速一樣騷操作。於是,痛定思痛自己買個雲主機、自己搭圖床應用!
1、七牛圖片批量下載到本地
1.1 曲折嘗試
當測試連結不能用的時候,我想依次用到下面幾個方法嘗試download圖片:
- 用七牛之前的傳圖工具qshell,看看有啥辦法(行不通)
- 找七牛圖片資源處看看有沒有批量打包下載(NO)
- 自己寫個前端爬蟲將圖片爬下來(沒下載連結...)
- 繫結一個自己的域名(需要實名認證+域名備案)
...
最後發現一個神器:qfetch,是根據七牛雲端儲存API實現的一個簡易命令列輔助工具。覆蓋七牛雲端儲存開發者網站包含的大部分甚至更高階的功能。開發者在對七牛雲端儲存 API 有基本瞭解的情況下,此工具將會非常適用。
1.2 qfetch基本操作
-按照如下指令,輸入自己七牛雲的賬號和密碼登入:
./qrstcl login <your username> <your password>
由於我之前所有圖片是在七牛雲物件儲存中的bucket中,執行如下程式碼檢視目前我建立的所有bucket:
./qrsctl buckets
我裡面只有一個buckets:beautifulzzzz
可以用下列命令檢視該buckets下的所有資源:(注意最後是兩個英文單引號)
./qrsctl listprefix beautifulzzzz ''
得到資源列表後,可以呼叫下列命令下載一個資源:
qrsctl get <Bucket> <Key> <DestFile> 比如./qrsctl get beautifulzzzz 1.jpg ./1.jpg可以將picture中的1.jpg下載到本地機器當前路徑下的1.jpg
1.3 自動化指令碼
綜上幾步,可以寫一個自動化指令碼:
qiniuyun (master) ✗ cat download.sh #!/bin/bash imgs=`./qrsctl listprefix beautifulzzzz ''` i=0 echo $imgs | tr " " "\n" | while read line do if(($i>0)) then echo $line path=`dirname $line` echo $path if [ ! -d "$path" ];then mkdir -p $path fi ./qrsctl get beautifulzzzz $line ./$line fi i=$(($i+1)) done
注:該指令碼相對於 chensonglu 分享的《七牛雲測試域名失效導致圖片外鏈失效的解決辦法》,增加了多級目錄檔案下載功能。
2、python 圖床伺服器搭建
2.1 python3環境搭建
安裝python:
sudo apt-get install python2.7-dev python3-dev
wget https://bootstrap.pypa.io/get-pip.py
sudo python get-pip.py
安裝python虛擬環境virtualenv virtualenvwrapper:(用虛擬開發環境可以為每個工程提供獨立的python開發環境、獨立的包、獨立的版本,每個獨立的環境會在~/.virtualenvs/下形成資源包~)
sudo pip install virtualenv virtualenvwrapper
sudo rm -rf ~/.cache/pip
之後在~/.profile檔案最後新增下面幾行:
# virtualenv and virtualenvwrapper
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
之後如果想用python虛擬環境,在每次開啟一個新的terminal就要執行一次source ~/.profile
$ source ~/.profile
接下來我們生成一個python虛擬環境來用於python_pic_server的開發提供環境:(這裡不講python2,強烈建議用python3)
mkvirtualenv python_pic_server -p python3
注:再次說明python虛擬環境是完全獨立的,也就是說在python_pic_server的環境下安裝的python包,步適用於全域性;在全域性安裝的包,不適合python_pic_server。
如何驗證你如何將python_pic_server環境生成好了呢?——新開一個terminal,執行下列命令:
$ source ~/.profile
$ workon python_pic_server
如果terminal前面的文字變成了(python_pic_server)表明成功建立了名為python_pic_server的python虛擬環境,在接下來的操作中都要保持在python_pic_server環境中!
2.2 安裝Sanic
sanic 是一個比較新的,但是發展比較快的框架。其特徵是速度非常快。據他們官方網站自己說,sanic 是最快的 python 框架。
Sanic is a Flask-like Python 3.5+ web server that’s written to go fast. It’s based on the work done by the amazing folks at magicstack, and was inspired by this article.
在python_pic_server中安裝sanic:
pip install sanic
2.3 寫圖床伺服器程式
在/root/App/python_pic_server目錄下建立run.py:
(python_pic_server) ➜ python_pic_server cat run.py
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
from sanic import Sanic
from sanic.log import logger
from sanic.response import json, text, file
import os, sys
import hashlib
import base64
app = Sanic()
# 圖片儲存目錄
baseDir = sys.path[0] + '/image/'
# 校驗 Token 寫死就成,反正自己用的嘛
token = 'SheIsABeautifulGirl'
# 允許的域名列表
allowHost = [
'127.0.0.1:8000',
'localhost',
'pic.phage.com'
]
# 成功返回方法
def ok(data):
if type(data) == list:
return json({"data": {"list": data}, "status": 0})
else:
return json({"data": data, "status": 0})
# 失敗返回方法
def fail(data):
return json({"data": data, "status": 1})
# 獲取圖片字尾名
def getSuffix(filename):
tempArr = filename.split('.')
suffix = tempArr[-1]
fileType = ['jpg', 'jpeg', 'gif', 'png']
if len(tempArr) < 2:
return 'error name'
elif suffix not in fileType:
return 'error type'
else:
return suffix
# 檢查請求地址是否授權
def checkHost(host):
for i in allowHost:
if i in host:
return True
return False
# 上傳圖片檔案介面
@app.route('/api/v1/upimg', methods=['POST'])
async def upimg(request):
# 判斷使用者是否具有上傳許可權
if request.headers.get('token') != token:
return fail('您沒有使用本服務的許可權')
image = request.files.get('file').body
# 判斷檔案是否支援
imageName = request.files.get('file').name
imageSuffix = getSuffix(imageName)
if 'error' in imageSuffix:
return fail(imageSuffix)
# 組織圖片儲存路徑
m1 = hashlib.md5()
m1.update(image)
md5Name = m1.hexdigest()
# 用 md5 的前兩位來建資料夾,防止單個資料夾下圖片過多,又或者根目錄下建立太多的資料夾
saveDir = baseDir + md5Name[0:2] + '/'
savePath = saveDir + md5Name[2:] + '.' + imageSuffix
resPath = '/' + md5Name[0:2] + '/' + md5Name[2:] + '.' + imageSuffix
# 如果資料夾不存在,就建立資料夾
if not os.path.exists(saveDir):
os.makedirs(saveDir)
# 將檔案寫入到硬碟
tempFile = open(savePath, 'wb')
tempFile.write(image)
tempFile.close()
# 給客戶端返回結果
return ok({"path": resPath})
# 請求圖片介面
@app.route('/', methods=['GET'])
async def img(request):
# 判斷是否為網站請求,否則就加上自定義的字串(允許本地訪問)
host = request.headers.get('host') or 'no_host'
# 判斷請求介面是否帶引數,否則加上自定義字串(沒有這個資料夾,返回404)
args = request.args.get('path') or 'no_file'
# 拼接檔案地址
path = baseDir + args
#logger.info(request.headers)
#logger.info(path)
#logger.info(host)
# 如果不在允許列表,則展示 401 圖片
if not checkHost(host):
path = baseDir + '/cb/fea262f9b861c6fce14d3c3c8ba9a1.png'
# 如果檔案不存在,則展示 404 圖片
if not os.path.exists(path):
path = baseDir + '/b4/dcd9ad1068ae6aa41ce486fa7f2739.png'
# 返回檔案
logger.info(path)
return await file(path)
# 啟動服務
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8000)
2.4 nginx配置
vim /etc/nginx/nginx.conf 編輯配置檔案,在http模組的最後新增:
server {
listen 3000;
server_name tuchuang.beautifulzzzz.com;
location / {
proxy_pass http://127.0.0.1:8000;
}
}
修改好之後relaod一下nginx:
nginx -s reload
這樣訪問 tuchuang.beautifulzzzz.com:3000 就相當於訪問本機的8000埠,正好是我們的圖床伺服器埠!
注:別忘了在你購買域名的地方設定一下A解析!我沒備案,因此就用了3000埠。
2.5 執行圖床並使用
將第1步下載的七牛雲圖片放在image目錄下,然後將run.py設定為可執行,並執行:
chmod +x run.py
./run.py
注:想在後臺執行可以用:nohup ./run.py &
此時,訪問圖片可以通過 (/image/20180926/flygame.png)
http://tuchuang.beautifulzzzz.com:3000/?path=/20180926/flygame.png
上傳圖片可以通過:
curl http://tuchuang.beautifulzzzz.com:3000/api/v1/upimg -F "[email protected]" -H "token: SheIsABeautifulGirl" -v
3、shell指令碼批量替換某資料夾下檔案中的域名字串
現在,準備寫一個批處理指令碼進行善後。我首先想到的是用下面命令直接搞定:
sed -i "s/A/B/g" `grep -rl A`
可是發現grep出來的檔案目錄中帶有空格,這樣這條命令就處理不到!
於是自己寫了一個迴圈查詢替換的批處理指令碼:
doc (master) ✗ cat change.sh
#!/bin/bash
#bash change.sh "odff1d90v.bkt.cloudd
#n.com" "tuchuang.beautifulzzzz.com:3000\/?path="
#bash change.sh "sed src string" "sed dst string"
IFS=$'\n'
if [ "$1" = "" ] && [ "$2" = "" ];then
echo "params 2"
exit
fi
for element in `grep -rl "$1"`
do
#echo $element
cmd="s/$1/$2/g"
echo $cmd
sed -i $cmd $element
done
注:這裡IFS=$'\n'是為了讓FOR迴圈的時候以換行作為分割
使用的時候只要將該檔案放置在對應的ROOT目錄中,執行:
bash change.sh "odff1d90v.bkt.clouddn.com" "tuchuang.beautifulzzzz.com:3000\/?path="
注:change.sh的兩個引數就是sed的被替換物件和替換物件,注意轉譯符!
LINKS
@beautifulzzzz
智慧硬體、物聯網,熱愛技術,關注產品
部落格:http://blog.beautifulzzzz.com
園友交流群:414948975