之前写了一个下载表情包的爬虫,爬取下载图片的效率不高,用多线程之后效率提高了很多。
这个网站是静态的,图片嵌在<a>标签下的<img>中,可以通过请求<img>标签中的data-original或是src属性的url值来获取相应的图片内容,然后保存到本地。
用到了3个队列来作为容器存储数据,队列的使用可以保持线程间的数据同步。用BeautifulSoup来解析返回的Html文档内容,用三个线程来分布完成整个过程:获取网页线程,解析网页线程,保存图片线程。
整体流程:
构造url -->将url放进url队列中 --> 启动获取网页线程 --> 将返回的html文档放进文档数据队列中 --> 结束获取网页线程后启动网页解析线程 --> 将解析出来的图片url放进图片url队列 --> 结束网页解析线程开启图片下载线程 -->线程结束 -->下载完成
这里还遇到了一个常见的坑,运行时with open(path,'wb') as f:这句代码报错,是一个较常见的变量名跟函数名重复的错误,由于粗心大意,半天没发现写在for循环的变量用了open。
下载了10页表情试了一下,好使,而且之前要好几分钟现在一分钟不到就跑完了。
代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : MultiThreadSpider.py
# @Author: Small-orange
# @Date : 2020-1-8
# @Desc : 多线程爬虫
import requests
import threading
from queue import Queue
from threading import Thread
from fake_useragent import UserAgent
from bs4import BeautifulSoup
import re
import time
#获取网页
class GetHtml(Thread):
def __init__(self):
super(GetHtml,self).__init__()
# self.url = url
print('--GetHtml--')
def run(self):
ua = UserAgent()
headers = {'User-Agent': ua.chrome}
#url_queue中有url时进行爬取
while url_queue.empty() ==False:
r = requests.get(url_queue.get(),headers=headers)
time.sleep(2)
if r.status_code ==200:
data_queue.put(r.text)
#解析网页
class ParserData(Thread):
def __init__(self):
super(ParserData,self).__init__()
print('--ParserData--')
def run(self):
while data_queue.empty() ==False:
soup = BeautifulSoup(data_queue.get(),'html.parser')
divlist = soup.find_all('div','tagbqppdiv')
for divin divlist:
imgTag = div.find('img')
imgattrs = imgTag.attrs
imgurl = imgattrs.get('data-original')
imgurl_queue.put(imgurl)
#保存图片
class SaveImg(Thread):
def __init__(self):
super(SaveImg,self).__init__()
print('--SaveImg--')
def run(self):
ua = UserAgent()
headers = {'User-Agent': ua.chrome}
while imgurl_queue.empty() ==False:
num = imgurl_queue.qsize()
url = imgurl_queue.get()
extname = re.search(r'(\.gif|\.jpeg|\.png|\.jpg|\.bmp)$',url)#扩展名
#保存路径
path ='D://images//{}{}'.format(str(num),extname.group(0))
r = requests.get(url,headers=headers)
if r.status_code ==200:
with open(path,'wb')as img:
img.write(r.content)
if __name__ =='__main__':
#url容器
url_queue = Queue()
#解析数据容器
data_queue = Queue()
#图片url容器
imgurl_queue = Queue()
url ='https://www.fabiaoqing.com/biaoqing/lists/page/{}.html'
for numin range(1,11):
new_url = url.format(num)
url_queue.put(new_url)
#开启获取网页线程
get_list = []
for iin range(3):
get_html = GetHtml()
get_html.start()
get_list.append(get_html)
#关闭获取网页线程
for getin get_list:
get.join()
# 开启解析网页线程
parser_list = []
for iin range(3):
parser_html = ParserData()
parser_html.start()
parser_list.append(parser_html)
# 关闭解析网页线程
for parserin parser_list:
parser.join()
#开启图片下载线程
save_list = []
for iin range(3):
saveImg = SaveImg()
saveImg.start()
save_list.append(saveImg)
#关闭下载线程
for imgin save_list:
img.join()
print('下载完成')