Python 初识多进程概念 —— Queue 进程通信(斗图啦)。
2020-04-27 07:33
369 查看
初学进程通信概念,以斗图啦为例加深印象。
基本思路
构建一个Producer类获取每张图片的地址
class Producer(threading.Thread): def __init__(self,page_queue,image_queue,image_name,*args,**kwargs): #page_queue:存放图片页数的一个队列;image_queue:存放图片地址的一个队列;image_name:存放每张图片的一个队列. super(Producer,self).__init__(*args,**kwargs) # super 我暂时将其理解为 是调用Producer所继承父类的一个方法,之后将类Producer的对象转换为类threading.Thread的一个对象 self.page_queue = page_queue self.img_queue = image_queue self.img_name = image_name self.headers = { "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" } def run(self): #run()方法,与start()都是启动进程的一个方法,但是start()可以启动多个进程,而run()方法不是启动一个新的线程,可以理解为只是主线程中一个执行何种操作的一个入口。 while True: if self.page_queue.empty(): break # 当每页都提取完数据后,也就是说存放页数的队列为空的时候,结束Producer url = self.page_queue.get() self.parse_page(url) def parse_page(self,url): try: request = urllib.request.Request(url, headers=self.headers) html = urllib.request.urlopen(request).read() data = etree.HTML(html) image_url = data.xpath("//img//@data-original") image_name = data.xpath("//p[@style = 'display: none']/text()") # 分别筛选出图片的地址以及名字 for i in range(len(image_url)): self.img_queue.put(image_url[i]) self.img_name.put(image_name[i]) except: pass
构建一个Consumer类下载每张图片
class Consumer(threading.Thread): def __init__(self,page_queue,image_queue,image_name,*args,**kwargs): super(Consumer,self).__init__(*args,**kwargs) self.page_queue = page_queue self.image_queue = image_queue self.img_name = image_name def run(self): while True: response = requests.get(self.image_queue.get()) if self.image_queue.empty(): break with open("D:/斗图/"+self.img_name.get()+".jpg","wb") as f: f.write(response.content)
完整程序
from lxml import etree import urllib.request import requests import threading from queue import Queue import os class Producer(threading.Thread): def __init__(self,page_queue,image_queue,image_name,*args,**kwargs): super(Producer,self).__init__(*args,**kwargs) self.page_queue = page_queue self.img_queue = image_queue self.img_name = image_name self.headers = { "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36" } def run(self): while True: if self.page_queue.empty(): break url = self.page_queue.get() self.parse_page(url) def parse_page(self,url): try: request = urllib.request.Request(url, headers=self.headers) html = urllib.request.urlopen(request).read() data = etree.HTML(html) image_url = data.xpath("//img//@data-original") image_name = data.xpath("//p[@style = 'display: none']/text()") for i in range(len(image_url)): self.img_queue.put(image_url[i]) self.img_name.put(image_name[i]) except: pass class Consumer(threading.Thread): def __init__(self,page_queue,image_queue,image_name,*args,**kwargs): super(Consumer,self).__init__(*args,**kwargs) self.page_queue = page_queue self.image_queue = image_queue self.img_name = image_name def run(self): while True: response = requests.get(self.image_queue.get()) if self.image_queue.empty(): break with open("D:/斗图/"+self.img_name.get()+".jpg","wb") as f: f.write(response.content) if __name__=="__main__": page_queue = Queue(100) # 存放页数,队列容量不需要那么大 image_queue = Queue(500) # image_name = Queue(500) s1 = eval(input("爬几页的图?")) if not os.path.exists("D:/斗图/"): os.mkdir("D:/斗图/") # os.mkdir 创建一个相对路径下的文件夹 # 如果要在一个自己指定的未知创建文件夹,只需将os.mkdir() 替换为 os.makedirs()即可 for x in range(1,s1): url = 'http://www.doutula.com/photo/list/?page=%d'%x page_queue.put(url) for x in range(5): t = Producer(page_queue,image_queue,image_name) t.start() for x in range(5): t = Consumer(page_queue,image_queue,image_name) t.start()
遇到的未解决问题
- [Errno 2] No such file or directory: ‘D:/斗图/牛///.jpg’
- [Errno 2] No such file or directory: ‘D:/斗图/嘿嘿/IN.jpg’
诸如此类的问题,需要在命名每一张图片时将 名字中含有类似 x/x.jpg 之间的若干个 / 删除,用到replace(’/’,’’),但是在1000张图片中只有很少量个此类的情况,如果每次都需要判断名字中是否含有 / 将增长下载时间。 - image_queue = Queue(500)
image_name = Queue(500)
在程序中规定了图片以及图片名字的容量为500,程序我运行了好多次进行比较,大概就是:
如果设一次性下载图片的数量在500之内,用的时间 t_1
设一次性下载图片的数量为1000,用的时间为 t_2
在测试中 t_2 大于 t_1 ,查的资料后,除与进程数有关外,还与队列的大小有关,如果将:
image_queue = Queue(500)
image_name = Queue(500)
调整为:
image_queue = Queue(1000)
image_name = Queue(1000)
则需要的时间 t_3 将小于 t_2。当数据的数量大于队列的容量时,超出容量的数据只能等待队列有空时,才能继续入列。除了增大队列容量外我还没有具体的方法。
- 点赞
- 收藏
- 分享
- 文章举报
相关文章推荐
- 11.python并发入门(part1 初识进程与线程,并发,并行,同步,异步)
- python使用Queue在多个子进程间交换数据的方法
- 41. Python Queue 多进程的消息队列 PIPE
- python进程的通信:queue、进程池中的Queue
- Python 进程通信,队列(multiprocessing.Queue()),单向通信
- Python多任务(五)-----4种进程间的通信(数据交换)Queue对象、管道Pipe、共享内存Value和Array、Manager对象 详解
- Python 进程操作之进程间通过队列共享数据,队列Queue简单示例
- 多线程&多进程解析:Python、os、sys、Queue、multiprocessing、threading
- python3中进程与线程的概念
- python进程的通信:queue、进程池中的Queue
- python中的进程、线程(threading、multiprocessing、Queue、subprocess)
- Python 进程,管道( multiprocessing.Pipe() ),进程通信(双向通信)
- Python多进程编程-进程间协作(Queue、Lock、Semaphore、Event、Pipe)
- Python-进程-进程通信Queue
- Python中的多进程创建和传值(克隆)Queue方法
- Python之网络编程 进程初识
- python多线程与多进程的概念与区别
- Python进阶(2)_进程与线程的概念
- python queue和多线程的爬虫 与 JoinableQueue和多进程的爬虫
- Python多线程/进程:os、sys、Queue、multiprocessing、threading