多线程提提速吧

2018-09-22  本文已影响12人  sixkery

爬虫用线程提速吧,用斗图网来做个对比。

普通爬虫,没用线程的例子:

import re,os,requests,time
from urllib import request
from lxml import etree
from fake_useragent import UserAgent

def get_url(url):
    ua = UserAgent().random
    headers = {'User-Agent':ua}
    r = requests.get(url,headers=headers)
    if r.status_code == 200:
        print('请求成功')
        return r.text

def parse(html):
    html_data = etree.HTML(html)
    # 这里获取的图片不包括 GIF 动图的形式,注意这种写法
    imgs = html_data.xpath('//div[@class="page-content text-center"]//img[@class!="gif"]')
    for img in imgs:
        image_url = img.get('data-backup')
        # 获取图片链接的后缀 单词是后缀的意思
        suffixs = os.path.splitext(image_url)[1]
        suffix = suffixs.replace(suffixs,'.jpg')
        # 获取图片标题及剔除标题特殊字符
        img_title = img.get('alt')
        img_title = re.sub('[?\?。,\.!!]','',img_title)

        filenamre = img_title + suffix
        request.urlretrieve(image_url,'images/'+filenamre) # 保存图片到文件夹 images 下
        print('保存图片成功')

def main():
    for i in range(1,2):
        print('第 %d 页' % i)
        url = 'https://www.doutula.com/photo/list/?page={}'.format(i)
        html = get_url(url)
        parse(html)

if __name__ == '__main__':
    start = time.time()
    main()
    end = time.time()
    print('共运行了%s秒' % (end - start))

这里获取一页68图片,看一下运行速度:


运行速度

生产者消费者模型

在这个例子中,定义两个队列,一个是获取页面的队列,一个是获取图片链接的队列。那么生产者就是这两个队列,消费者完成的任务就是下载图片到本地。
上述代码改造一下:
在main() 函数中,定义这两个队列:


def main():
    page_queue = Queue(100) # 创建下载页面的队列
    image_queue = Queue(1000) # 创建获取具体表情 url 的队列
    for i in range(1,10):
        print('第 %d 页' % i)
        url = 'https://www.doutula.com/photo/list/?page={}'.format(i)
        page_queue.put(url)

下载页面的队列的容量是100,put 方法将获取页面的url传入获取页面的队列中。

创建生产者模型:


# 创建生产者队列
class Procuder(threading.Thread):
    # 重写父类构造函数,继承父类所有方法,同时添加两个参数
    def __init__(self,page_queue,image_queue,*args,**kwargs):
        super(Procuder,self).__init__(*args,**kwargs)
        self.page_queue = page_queue
        self.image_queue = image_queue

    def run(self):
        while True:
            if self.page_queue.empty(): # 如果下载页面的队列为空,就结束循环
                break
            url = self.page_queue.get() # 获取页面url,交由解析图片url的方法解析图片url
            self.parse(url)

    def parse(self,url):
        ua = UserAgent().random
        headers = {'User-Agent':ua}
        r = requests.get(url,headers=headers)
        html_data = etree.HTML(r.text)
        # 这里获取的图片不包括 GIF 动图的形式,注意这种写法
        imgs = html_data.xpath('//div[@class="page-content text-center"]//img[@class!="gif"]')
        for img in imgs:
            image_url = img.get('data-backup')
            # 获取图片链接的后缀 单词是后缀的意思
            suffixs = os.path.splitext(image_url)[1]
            suffix = suffixs.replace(suffixs,'.jpg')
            # 获取图片标题及剔除标题特殊字符
            img_title = img.get('alt')
            img_title = re.sub('[?\?。,\.!!\*]','',img_title)
            filenamre = img_title + suffix
            self.image_queue.put((image_url,filenamre)) # 把图片的url传递给获取图片的队列

创建消费者模型

class Consumer(threading.Thread):
    # 重写父类构造函数,继承父类所有方法,同时添加两个参数
    def __init__(self,page_queue,image_queue,*args,**kwargs):
        super(Consumer,self).__init__(*args,**kwargs)
        self.page_queue = page_queue
        self.image_queue = image_queue

    def run(self):
        while True:
            # 判断两个队列是否都为空,是就结束循环,不要让队列一直在等待操作
            if self.page_queue.empty() and self.image_queue.empty():
                break
            image_url,filename = self.image_queue.get() # 获取具体表情的url队列中的图片url和文件名
            request.urlretrieve(image_url,'images/'+ filename) # 保存图片到文件夹 images 下
            print(filename + '保存图片成功')

主程序

def main():
    page_queue = Queue(100) # 创建下载页面的队列
    image_queue = Queue(1000) # 创建获取具体表情 url 的队列
    for i in range(1,10):
        print('第 %d 页' % i)
        url = 'https://www.doutula.com/photo/list/?page={}'.format(i)
        page_queue.put(url)

    # 分别创建五个生产者,五个消费者,开启线程
    for i in range(5):
        t = Procuder(page_queue,image_queue)
        t.start()

    for i in range(5):
        t = Consumer(page_queue,image_queue)
        t.start()


if __name__ == '__main__':
    main()

几百张图片几乎在两三秒就下载完成了。

上一篇下一篇

猜你喜欢

热点阅读