• [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 " " "
    " | 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
    

    sanic用法比较简单,具体可以参考:[6].sanic getting started page


    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 "file=@a.png" -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=$'
    '
    
    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=$' '是为了让FOR循环的时候以换行作为分割

    使用的时候只要将该文件放置在对应的ROOT目录中,执行:

    bash change.sh "odff1d90v.bkt.clouddn.com" "tuchuang.beautifulzzzz.com:3000/?path="
    

    注:change.sh的两个参数就是sed的被替换对象和替换对象,注意转译符!


    [1].七牛云测试域名失效导致图片外链失效的解决办法
    [2].命令行辅助工具(qrsctl)
    [3].Linux shell 之 提取文件名和目录名的一些方法
    [4].逐行处理文本文件-一点心青-cnblog
    [5].shell中的特殊变量IFS- __Cheny-csdn
    [6].sanic getting started page
    [7].Python3 初学实践案例(14)打造一个私人图床服务器-FungLeo-csdn
    [8].Python 打造自己的图床升级篇 - PIL 为图片添加水印-FungLeo-csdn
    [9].nohup和&后台运行,进程查看及终止-弥尘-cnblog


    @beautifulzzzz
    智能硬件、物联网,热爱技术,关注产品
    博客:http://blog.beautifulzzzz.com
    园友交流群:414948975
    
  • 相关阅读:
    next_permitation
    POJ 1979 Red and Black
    POJ 2386 Lake Counting
    BFS简单迷宫
    部分和问题
    图论复习--二分图判断
    danci1
    danci
    jquery事件重复绑定解决办法
    danci
  • 原文地址:https://www.cnblogs.com/zjutlitao/p/9975527.html
Copyright © 2020-2023  润新知