python queue队列实战

目录

概念:Queue是python标准库中的线程安全的队列(FIFO)实现,提供了一个适用于多线程编程的先进先出的数据结构,即队列,用来在生产者和消费者线程之间的信息传递

Python多线程主要是为了提高程序在IO方面的优势,在爬虫的过程中显得尤为重要。正常的爬虫请求直接封装多线程,但是爬虫请求的过程中,对于url的请求需要通过队列来实现。

queue实战生产者消费者

1、首先先导入Queue、threading

2、定义生产者生产(生产初始url)

3、定义消费者(解析数据)

4、在定义一个消费者(下载数据)

5、主方法

6、完整代码


概念:Queue是python标准库中的线程安全的队列(FIFO)实现,提供了一个适用于多线程编程的先进先出的数据结构,即队列,用来在生产者和消费者线程之间的信息传递

Python多线程主要是为了提高程序在IO方面的优势,在爬虫的过程中显得尤为重要。正常的爬虫请求直接封装多线程,但是爬虫请求的过程中,对于url的请求需要通过队列来实现。

queue实战生产者消费者

1、首先先导入Queue、threading

from queue import Queue
import threading

2、定义生产者生产(生产初始url)

# 定义生产者
class BiAnProducer(threading.Thread):
    def __init__(self, url_queue, respone_queue):
        # 初始化父类
        threading.Thread.__init__(self)
        # 初始化url队列
        self.url_queue = url_queue
        # 初始化响应数据队列
        self.respone_queue = respone_queue

    # 运行线程的方法 run
    def run(self) -> None:
        # 死循环一直把队列的数据取完为止
        while True:
            # 判断队列是否为空 为空的话跳出循环
            if self.url_queue.empty():
                break
            try:
                url = self.url_queue.get()
                response = requests.get(url=url, headers=headers)
                response.encoding = response.apparent_encoding
                self.respone_queue.put(response.text)
            except:
                pass

3、定义消费者(解析数据)

# 定义消费者
class BiAnConsumer(threading.Thread):
    def __init__(self,respone_queue, img_url_queue, img_title_queue):
        threading.Thread.__init__(self)
        self.respone_queue = respone_queue
        self.img_url_queue = img_url_queue
        self.img_title_queue = img_title_queue

    def run(self) -> None:
        # 死循环一直把队列的数据取完为止
        while True:
            # 判断队列是否为空 为空的话跳出循环
            if self.respone_queue.empty():
                break
            try:
                # 从队列中取出响应数据
                response = self.respone_queue.get()
                # 调用解析数据方法
                self.parse_data(response)
            except:
                pass
    
    # 解析数据方法
    def parse_data(self, response):
        tree = etree.HTML(response)
        title = tree.xpath('//*[@id="main"]/div[3]/ul/li/a/img/@alt')
        img_url = tree.xpath('//*[@id="main"]/div[3]/ul/li/a/img/@src')
        for titles, img_urls in zip(title, img_url):
            p_img_url = 'https://pic.netbian.com' + img_urls
            self.img_url_queue.put(p_img_url)
            self.img_title_queue.put(titles)

4、在定义一个消费者(下载数据)

# 再来一个消费者
class BiAnDownload(threading.Thread):
    def __init__(self, img_url_queue, img_title_queue):
        threading.Thread.__init__(self)
        # 初始化图片url队列
        self.img_url_queue = img_url_queue
        # 初始化标题队列
        self.img_title_queue = img_title_queue

    def run(self) -> None:
        while True:
            if self.img_url_queue.empty() and self.img_title_queue.empty():
                break
            try:
                # 从队列中取出图片url
                img_url = self.img_url_queue.get()
                # 从队列中取出图片标题
                title = self.img_title_queue.get()
                content = requests.get(url=img_url, headers=headers).content
                # 调用下载方法
                self.download(content, title)
            except:
                pass

    # 下载方法            
    def download(self, content, title):
        f_path = path + '/' + title + '.jpg'
        try:
            with open(f_path, 'wb') as f:
                f.write(content)
                f.close
        except Exception as e:
            print('ERROR', e)

5、主方法

if __name__ =="__main__":
    start = time.time()
    # 创建初始url队列
    url_queue = Queue()
    # 创建容纳响应数据的队列
    response_queue = Queue()
    # 创建需要下载的url队列
    img_url_queue = Queue()
    # 创建标题队列
    img_title_queue = Queue()

    # 控制url个数
    url = 'https://pic.netbian.com/index_{}.html'
    for page in range(1, 11):
        new_url = url.format(page)
        url_queue.put(new_url)

    # 创建一个列表去控制爬虫线程
    crawl_list = []
    for i in range(0, 5):
        crawl = BiAnProducer(url_queue, response_queue)
        crawl_list.append(crawl)
        crawl.start()   # 启动
        
    for i in crawl_list:
        i.join()    # join就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程在终止

    # 创建一个列表去控制解析线程
    parse_list = []
    for i in range(0, 5):
        parse = BiAnConsumer(response_queue, img_url_queue, img_title_queue)
        parse_list.append(parse)
        parse.start()
        
    for i in parse_list:
        i.join()

    # 创建一个列表去控制下载线程
    down_list = []
    # 开启五个线程
    for i in range(0, 5):
        download = BiAnDownload(img_url_queue, img_title_queue)
        down_list.append(download)
        download.start()

    for i in down_list:
        i.join()
    
    end = time.time()
    print('总耗时:', end - start)

6、完整代码


import requests
from lxml import etree
from fake_useragent import UserAgent
import threading
from queue import Queue
import os
import time

# 创建文件夹
path = r'D:\壁纸\高清无码'
isExists=os.path.exists(path)
if not isExists:
    os.mkdir(path)

# 请求头
headers = {'User-Agent': UserAgent().random}

# 定义生产者
class BiAnProducer(threading.Thread):
    def __init__(self, url_queue, respone_queue):
        # 初始化父类
        threading.Thread.__init__(self)
        # 初始化url队列
        self.url_queue = url_queue
        # 初始化响应数据队列
        self.respone_queue = respone_queue

    # 运行线程的方法 run
    def run(self) -> None:
        # 死循环一直把队列的数据取完为止
        while True:
            # 判断队列是否为空 为空的话跳出循环
            if self.url_queue.empty():
                break
            try:
                url = self.url_queue.get()
                response = requests.get(url=url, headers=headers)
                response.encoding = response.apparent_encoding
                self.respone_queue.put(response.text)
            except:
                pass

# 定义消费者
class BiAnConsumer(threading.Thread):
    def __init__(self,respone_queue, img_url_queue, img_title_queue):
        threading.Thread.__init__(self)
        self.respone_queue = respone_queue
        self.img_url_queue = img_url_queue
        self.img_title_queue = img_title_queue

    def run(self) -> None:
        # 死循环一直把队列的数据取完为止
        while True:
            # 判断队列是否为空 为空的话跳出循环
            if self.respone_queue.empty():
                break
            try:
                # 从队列中取出响应数据
                response = self.respone_queue.get()
                # 调用解析数据方法
                self.parse_data(response)
            except:
                pass
    
    # 解析数据方法
    def parse_data(self, response):
        tree = etree.HTML(response)
        title = tree.xpath('//*[@id="main"]/div[3]/ul/li/a/img/@alt')
        img_url = tree.xpath('//*[@id="main"]/div[3]/ul/li/a/img/@src')
        for titles, img_urls in zip(title, img_url):
            p_img_url = 'https://pic.netbian.com' + img_urls
            self.img_url_queue.put(p_img_url)
            self.img_title_queue.put(titles)

# 再来一个消费者
class BiAnDownload(threading.Thread):
    def __init__(self, img_url_queue, img_title_queue):
        threading.Thread.__init__(self)
        # 初始化图片url队列
        self.img_url_queue = img_url_queue
        # 初始化标题队列
        self.img_title_queue = img_title_queue

    def run(self) -> None:
        while True:
            if self.img_url_queue.empty() and self.img_title_queue.empty():
                break
            try:
                # 从队列中取出图片url
                img_url = self.img_url_queue.get()
                # 从队列中取出图片标题
                title = self.img_title_queue.get()
                content = requests.get(url=img_url, headers=headers).content
                # 调用下载方法
                self.download(content, title)
            except:
                pass

    # 下载方法            
    def download(self, content, title):
        f_path = path + '/' + title + '.jpg'
        try:
            with open(f_path, 'wb') as f:
                f.write(content)
                f.close
        except Exception as e:
            print('ERROR', e)

        
if __name__ =="__main__":
    start = time.time()
    # 创建初始url队列
    url_queue = Queue()
    # 创建容纳响应数据的队列
    response_queue = Queue()
    # 创建需要下载的url队列
    img_url_queue = Queue()
    # 创建标题队列
    img_title_queue = Queue()

    # 控制url个数
    url = 'https://pic.netbian.com/index_{}.html'
    for page in range(1, 11):
        new_url = url.format(page)
        url_queue.put(new_url)

    # 创建一个列表去控制爬虫线程
    crawl_list = []
    for i in range(0, 5):
        crawl = BiAnProducer(url_queue, response_queue)
        crawl_list.append(crawl)
        crawl.start()   # 启动
        
    for i in crawl_list:
        i.join()    # join就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程在终止

    # 创建一个列表去控制解析线程
    parse_list = []
    for i in range(0, 5):
        parse = BiAnConsumer(response_queue, img_url_queue, img_title_queue)
        parse_list.append(parse)
        parse.start()
        
    for i in parse_list:
        i.join()

    # 创建一个列表去控制下载线程
    down_list = []
    # 开启五个线程
    for i in range(0, 5):
        download = BiAnDownload(img_url_queue, img_title_queue)
        down_list.append(download)
        download.start()

    for i in down_list:
        i.join()
    
    end = time.time()
    print('总耗时:', end - start)

为了避免中招 我只下载了10页数据一共花了7秒6(我的网速是比较慢的)

 下载下来的一部分数据

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿里多多酱a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值