某次上课无聊,突然想写个图片爬虫玩玩,顺便把爬取的图片做个随机图片API接口(之前说写也一直拖到现在…);因为部分知识领域只知道其存在,但从没有实战学习过,干脆从头到尾练手一次,于是有了这篇博文,记录一下过程。
实现目标:
利用云服务器自动后台运行 Python脚本,包含开启自启;脚本实现内容:爬虫自动爬取图片,临时保存到本地,再上传到搜狗图床,自动保存图片上传之后的地址,以Json形式保存到本地文件。
采集日志图片
采集结果图片

Ps:这里的搜狗图床其实抓的搜狗图片搜索上传接口,我测试了百度(会改变图片分别率),360(不支持SSL且最大只能2M),所以选择了搜狗。至于为啥是JSON形式保存,这是方便后面用PHP写接口时,直接读取保存数组即可,方便调用。
环境要求:
个人使用的是百度云服务器,配置有点低…
机子配置:1H、2G、1M,操作系统:Centos7.2,运行环境:Python3.7
操作步骤
1.配置Python环境
注意:本步骤全是都在root超级用户权限下执行,非root用户注意添加 sudo
新购服务器,简单配置一下,升级所有包,升级软件和系统内核,非必须,需要一点时间,等一会儿吧。
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命令查看后台任务,如若已重连终端,需要使用以下命令才能查看。
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