版权声明:本文为博主原创文章,未经博主允许不得转载。
关于本文:
现在关于python多线程爬虫的文章并不少见,但是很多代码冗长,逻辑混乱,也有很多代码在博主实际测试之后发现已经无法使用,都不太适合新接触爬虫的同志们学习,所以我在这里贴一个我写的用python多线程爬虫爬斗图网表情包的程序,希望能对大家有帮助。
使用模块:
本文的编程环境是windows7,python版本为python2,工具使用anaconda2自带的Spyder。
使用模块及功能:
requests………网页url获取
threading…….线程
lxml……………..网页结构分析
bs4
Queue………….多线程处理
下面对代码分块讲解:
1.
引用以及多线程队列的声明
import requests
import threading
from lxml import etree
from bs4 import BeautifulSoup
from Queue import Queue
out_queue=Queue()
2.
先看主函数:
def main():
start_url='https://www.doutula.com/article/list/?page='
for j in range(1,5):
start_html=get_html(start_url+str(j))
b=get_img_html(start_html)
for i in b:
get_img(i)
if __name__=='__main__':
main()
start_url是我们要用到的网址,for j in range(1,5)表示用斗图网的第一页爬到第四页(如果想问为什么是第四页需要先学习一下range的用法)
3.
既然是从网络上爬取数据,那肯定要获得网络的url,代码中的url1为从主函数传入的斗图网网址。header为网络验证,在进行爬虫时有部分网站可能会用到header验证,如果没有就无法访问网页。response中则储存了我们得到的网页源代码(这里还需要对网页构架的知识有所了解,在浏览器中按F12进入开发者模式即可看到网页源代码)
def get_html(url1):
header={'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36 Core/1.47.516.400 QQBrowser/9.4.8186.400'}
request=requests.get(url=url1,headers=header)
response=request.content
return response
4.
得到网页源代码之后,接下来我们要做的就是查找我们需要的图片的超链接是在源代码中的那个地方保存的,通过对网页的解析:
可以看到每一系列的图片都是存在class名为list-group-item random_list的a标签中,使用BeautifulSoup库对这一系列图片的超链接进行提取。
def get_img_html(html1):
y=[]
soup=BeautifulSoup(html1,'lxml')
for hrefs in soup.find_all('a',class_='list-group-item random_list'):
y.append(hrefs.get('href'))
return y
5.
得到一系列图片存储的超链接后,点开超链接,在用同样的方法对单张图片的超链接进行分析提取,并存入我们事先声明的多线程队列out_queue中,然后根据每个系列图片的张数启动对应个数的线程,每个线程分别同时对队列out_queue中的一个url进行访问,这样就实现了高效率的多线程爬图,然后再保存到本地即可。
def get_img(html2):
html=get_html(html2)
soup=etree.HTML(html)
items=soup.xpath('//div[@class="artile_des"]')
for item in items:
imgurl_list=item.xpath('table/tbody/tr/td/a/img/@onerror')
out_queue.put(item.xpath('table/tbody/tr/td/a/img/@onerror'))
for a in range(0,imgurl_list.__len__()):
threadD = threadDownload(out_queue,a)
threadD.start()
class threadDownload(threading.Thread):
def __init__(self,que,no):
threading.Thread.__init__(self)
self.que = que
self.no = no
def run(self):
while True:
if not self.que.empty():
save_img(self.que.get()[0])
else:
x=1
def save_img(img_url):
global x
x+=1
img_url1 =img_url.split('=')[-1][1:-2].replace('jp','jpg').replace('pn','png').replace('gi','gif')
print u'正在下载'+'http:'+img_url1
img_content=requests.get('http:'+img_url1).content
with open('doutu/%s.jpg'% x,'wb') as f:
f.write(img_content)
完成程序如下:
import requests
import threading
from lxml import etree
from bs4 import BeautifulSoup
from Queue import Queue
out_queue=Queue()
def get_html(url1):
#url='https://www.doutula.com/article/list/?page=1'
header={'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36 Core/1.47.516.400 QQBrowser/9.4.8186.400'}
request=requests.get(url=url1,headers=header)
response=request.content
return response
class threadDownload(threading.Thread):
def __init__(self,que,no):
threading.Thread.__init__(self)
self.que = que
self.no = no
def run(self):
while True:
if not self.que.empty():
save_img(self.que.get()[0])
else:
break
def get_img_html(html1):
y=[]
soup=BeautifulSoup(html1,'lxml')
for hrefs in soup.find_all('a',class_='list-group-item random_list'):
y.append(hrefs.get('href'))
return y
def get_img(html2):
html=get_html(html2)
soup=etree.HTML(html)
items=soup.xpath('//div[@class="artile_des"]')
for item in items:
imgurl_list=item.xpath('table/tbody/tr/td/a/img/@onerror')
out_queue.put(item.xpath('table/tbody/tr/td/a/img/@onerror'))
for a in range(0,imgurl_list.__len__()):
threadD = threadDownload(out_queue,a)
threadD.start()
x=1
def save_img(img_url):
global x
x+=1
img_url1 =img_url.split('=')[-1][1:-2].replace('jp','jpg').replace('pn','png').replace('gi','gif')
print u'正在下载'+'http:'+img_url1
img_content=requests.get('http:'+img_url1).content
with open('doutu/%s.jpg'% x,'wb') as f:
f.write(img_content)
def main():
start_url='https://www.doutula.com/article/list/?page='
for j in range(1,5):
start_html=get_html(start_url+str(j))
b=get_img_html(start_html)
for i in b:
get_img(i)
if __name__=='__main__':
main()
执行结果:
因为是多线程,所以下载也快,300多张也就10几秒,当然在各位实验的时候由于网速不同或许会有所差异。
本篇是使用多线程对一般网站进行爬取,大家使用代码对其他比如百度,花瓣进行爬图时,由于这些网站有反爬机制,所以使用时还需要对代码进行修改才会成功。