Featured image of post 云服务器简单实现Python自动运维

云服务器简单实现Python自动运维

某次上课无聊,突然想写个图片爬虫玩玩,顺便把爬取的图片做个随机图片API接口(之前说写也一直拖到现在…);因为部分知识领域只知道其存在,但从没有实战学习过,干脆从头到尾练手一次,于是有了这篇博文,记录一下过程。


实现目标:

利用云服务器自动后台运行 Python脚本,包含开启自启;脚本实现内容:爬虫自动爬取图片,临时保存到本地,再上传到搜狗图床,自动保存图片上传之后的地址,以Json形式保存到本地文件。

采集日志图片 ![采集日志.png](/usr/uploads/2018/11/3369392936.png)

采集结果图片 采集结果.png

Ps:这里的搜狗图床其实抓的搜狗图片搜索上传接口,我测试了百度(会改变图片分别率),360(不支持SSL且最大只能2M),所以选择了搜狗。至于为啥是JSON形式保存,这是方便后面用PHP写接口时,直接读取保存数组即可,方便调用。

环境要求:

个人使用的是百度云服务器,配置有点低… 机子配置:1H、2G、1M,操作系统:Centos7.2,运行环境:Python3.7

操作步骤

1.配置Python环境 注意:本步骤全是都在root超级用户权限下执行,非root用户注意添加 sudo

新购服务器,简单配置一下,升级所有包,升级软件和系统内核,非必须,需要一点时间,等一会儿吧。

1
yum -y update

Centos7.2默认安装了Python2.7版本,环境要求是3.7版本。 安装依赖包:

1
2
sudo yum -y groupinstall "Development tools"
sudo yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel libffi-devel

下载Python3.7安装包:

1
wget https://www.python.org/ftp/python/3.7.1/Python-3.7.1.tgz

解压安装包:

1
tar -xzvf Python-3.7.1.tgz

配置安装目录并安装:

1
2
cd python3
./configure --preix=/usr/python3 && make && make install

等待安装完成 检查安装是否完成:

1
2
3
python3 -V && pip3 -V
>>Python 3.7.1
>>pip 18.1 from /usr/python3/lib/python3.7/site-packages/pip (python 3.7)

这里的pip是默认安装,但默认版本不是18.1,这是后来升级的,更新命令:

1
pip3 install pip --upgrade

根据安装路径和环境变量创建软链接: 个人安装路径:/root/python3,环境变量:/root/sbin 创建命令:

1
2
ln -s /usr/python3 /usr/sbin/python3
ln -s /usr/python3/bin/pip3 /usr/sbin/pip3

Ps:如果你安装完成,但在没有创建软链接之前,敲入Python3 命令没有反应,可能是由于的工作路径不再环境变量中,进入python3安装路径的bin目录测试即可;至于如何配置环境变量,请另行百度。

所以到现在为止,Python3.7的环境已经全部安装完成!

2.后台运行Python脚本

1
nohup python3 /root/python/AutoPic.py > log.txt &

解释:把脚本运行挂到后台,且在退出之后持续运行,标准输出重定向到log.txt作为日志。AutoPic.py 这个是爬虫脚本,我会在文章最后附上代码。

之后可使用 jobs命令查看后台任务,如若已重连终端,需要使用以下命令才能查看。

1
ps -ef|grep python3

3.设置开机自动运行

1
cd /etc/rc.d && chmod +x rc.local && vi rc.local

打开Vi编辑,在该文件最后加上以下语句,切勿修改其它设置

1
nohup python3 /root/python/AutoPic.py > log.txt &

最后按 ESC 输入 :wq! 退出保存,OK,完工!

4.爬虫源码

按照自己的机子配置的,比如线程数,受限服务器宽带限制,并不是越大越好。 必须模块:requests,bs4;安装命令。

1
2
pip3 install requests
pip3 install bs4

爬虫源代码:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# -*- coding: utf-8 -*-

from requests import get
from requests import post
from bs4 import BeautifulSoup as bs
from urllib.parse import unquote as urldecode
import re,os,random,queue,threading,time,json

def randstr(length=0):
    km=''
    s='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
    if length == 0:
        length=32
    for x in range(length):
        i=random.randint(0,len(s)-1)
        km+=s[i]
    return(km)

def GetIndexUrl(Ptype,pages):
    #@ paras Ptype str 壁纸分类
    #@ paras Pages int 爬取页数
    #@ return list 爬取地址
    
    print('正在抓取图片地址(1)...')
    index_list=list()
    host='http://www.ivsky.com'
    index_url=host+'/bizhi/'+Ptype+'/index_'
    for x in range(pages):
        index_list.append(index_url+str(x)+'.html')
    return index_list

def GetIndex2Url(index_list):
    #@ paras index_list list URL列表
    
    print('正在抓取图片地址(2)...')
    URL=list()
    host='http://www.ivsky.com'
    for url in index_list:
        ret=get(url,timeout=5)
        ret.encoding='utf-8'
        html=ret.text
        soup=bs(html,'html.parser')
        for x in soup.find_all(name='div',attrs={"class":"il_img"}):
            URL.append(host+(x.a.get('href')))
    return URL

def GetImageUrl(IndexUrl):
    #@ paras index_list list URL列表
    
    print('正在处理图片地址(3)...')
    URL=list()
    for url in IndexUrl:
        html=get(url,timeout=5)
        soup2=bs(html.text,'html.parser')
        for x in soup2.find_all(name='div',attrs={"class":"il_img"}):
            u=x.img.get('src')
            URL.append(u.replace('/t/','/pic/'))
    print('返回图片真实地址(4)...')
    return URL

def SavePic(ImageUrl):
    #@ paras ImageUrl str 图片真实地址
    global q
    res=None
    Name=randstr(6)+'.jpg'
    FilePath=os.getcwd()+'/Temp/'+Name
    headers={'Referer':'http://www.ivsky.com/'}
    
    try:
        res=get(ImageUrl,headers=headers,timeout=5)
        if res.status_code == 200:
            JPGbyte=res.content
            with open(FilePath,'wb') as file:
                file.write(JPGbyte)
                file.close()
            return FilePath
        else:
            q.put(ImageUrl)
    except:
        q.put(ImageUrl)
        
        
def UpPic(FilePath):
    #@ paras FilePath str 文件路径
    #@ return tuple 0:bool,1:strinfo
    
    if not os.path.isfile(FilePath):
        return (False,'文件不存在')
    SGapi='https://pic.sogou.com/ris_upload'
    with open(FilePath,'rb') as jpg:
        files={'file':jpg}
        try:
            res=post(SGapi,files=files,allow_redirects=False,timeout=(3, 60))
        except:
            return (False,'文件上传失败__001')
        jpg.close()
        headers=dict(res.headers)
        if 'Location' not in headers:
            return (False,'文件上传失败__002')
        ret=re.search('query=(.*?)&',res.headers['Location'])
        PicUrl=urldecode(ret.group(1))
        return (True,PicUrl,FilePath)
    
def SaveJson(strlist,Path):
    #@ paras strlist list 保存数据
    #@ paras Path str 保存路径
    #@ return Bool True:success
    ret=json.dumps(strlist)
    try:
        with open(Path,'w') as File:
            File.write(ret)
            File.close()
        return True
    except:
        return False
    
def Run():
    global q,PicUrl
    while not q.empty() and Switch:
        ImgUrl=q.get()
        PicPath=SavePic(ImgUrl)
        ret=UpPic(PicPath)
        if ret[0]:
            PicUrl.append(ret[1])
            os.remove(ret[2])
        else:
            q.put(ImgUrl)
        break
    
if __name__ == '__main__':

    Num=5               #线程数
    Switch=True         #线程开关 
    PicUrl=list()       #图片地址
    Thread=list()       #线程列表
     
    #//获取所有图片真实地址
    IndexUrl=GetIndex2Url(GetIndexUrl('nvxing',50))
    ImgUrl=GetImageUrl(IndexUrl)
    
    #//建立缓存文件夹
    Path=os.getcwd()+'/Temp/'
    if not os.path.exists(Path):
        os.makedirs(Path)
    
    #//填充图片地址队列
    q=queue.Queue()
    for url in ImgUrl:
        q.put(url)
    
    #//创建线程
    for x in range(Num):
        t=threading.Thread(target=Run)
        t.setDaemon(False)
        t.start()
        Thread.append(t)
    
    while not q.empty():
        SaveJson(PicUrl,os.getcwd()+'/list.txt')
        try:
            for x in range(len(Thread)): #重启线程
                if not Thread[x].isAlive():
                    Thread.pop(x)
                    t=threading.Thread(target=Run)
                    t.setDaemon(False)
                    t.start()
                    Thread.append(t)
                else:
                    pass
            print('活:',len(Thread),'剩:',q.qsize())        
            time.sleep(3)
        except:
            Switch=False
            print('异常,结束所有线程,退出!')
            break
    else:
        SaveJson(PicUrl,os.getcwd()+'/list.txt')

5.总结

文章内容虽然不多,却因为菜整整写了两天,主要是爬虫脚本出现很神奇的BUG,一直无法复现,浪费了一整天时间;脚本目前已经放在了服务器正常运行,过两天再把采集的图片利用PHP单独做个API。

接下来会更新的博文:【CentOS实现每日定时自动采集图片】,【[PHP]利用采集简单实现随机图片API】

采集源站:http://www.ivsky.com/

最后:本次实践只是一种学习记录,博文也仅限用于交流学习,对于用于其它用途产生的后果自负。

参考文章: https://blog.csdn.net/qiushisoftware/article/details/79520869 https://blog.csdn.net/wzx104104104/article/details/70832747 https://www.cnblogs.com/zhanglong8681/p/8421512.html https://blog.csdn.net/elija940818/article/details/79238813

使用 Hugo 构建
主题 StackJimmy 设计