Wang's blog Wang's blog
首页
  • 前端文章

    • HTML教程
    • CSS
    • JavaScript
  • 前端框架

    • Vue
    • React
    • VuePress
    • Electron
  • 后端技术

    • Npm
    • Node
    • TypeScript
  • 编程规范

    • 规范
  • 我的笔记
  • Git
  • GitHub
  • VSCode
  • Mac工具
  • 数据库
  • Google
  • 服务器
  • Python爬虫
  • 前端教程
更多
收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Wang Mings

跟随大神,成为大神!
首页
  • 前端文章

    • HTML教程
    • CSS
    • JavaScript
  • 前端框架

    • Vue
    • React
    • VuePress
    • Electron
  • 后端技术

    • Npm
    • Node
    • TypeScript
  • 编程规范

    • 规范
  • 我的笔记
  • Git
  • GitHub
  • VSCode
  • Mac工具
  • 数据库
  • Google
  • 服务器
  • Python爬虫
  • 前端教程
更多
收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Python爬虫

    • 爬虫的基础知识

    • 请求的发送方法

    • 数据提取方法

    • 高性能爬虫

      • 单线程爬虫
      • 多线程爬虫
      • 多进程爬虫
        • 线程池爬虫
        • 协程池爬虫
        • 小结
      • selenium

      • 反爬以及解决方案

      • MONGODB数据库

      • scrapy框架

      • scrapy_redis

      • 爬虫的部署

      • 爬虫框架开发分析

      • 框架雏形实现

      • 框架功能完善

      • 框架功能升级

      • 项目实战

      • pywin32介绍

    • 前端教程

    • 教程
    • Python爬虫
    • 高性能爬虫
    wangmings
    2022-07-19
    目录

    多进程爬虫

    # 多进程爬虫

    # 学习目标
    1. 掌握 multiprocessing模块的使用
    2. 了解 JoinableQueue的使用

    在一个进程中无论开多少个线程都只能运行在一个CPU的核心之上,这是python的特点,不能说是缺点!

    如果我们想利用计算机的多核心优势,就可以用多进程的方式实现,思路和多线程相似,只是对应的api不相同。

    # 1 回顾多进程程的方法使用

    from multiprocessing import Process  #导入模块
    t1 = Process(targe=func,args=(,)) #使用一个进程来执行一个函数
    t1.daemon = True  #设置为守护进程
    t1.start() #此时线程才会启动 
    
    1
    2
    3
    4

    # 2 多进程中队列的使用

    多进程中使用普通的队列模块会发生阻塞,对应的需要使用multiprocessing提供的JoinableQueue模块,其使用过程和在线程中使用的queue方法相同

    # 3 具体实现

    具体的实现如下:

    import requests
    from lxml import etree
    from multiprocessing import Process
    from multiprocessing import JoinableQueue as Queue
    
    class QiubaiSpider:
        def __init__(self):
            self.url_temp = "https://www.qiushibaike.com/8hr/page/{}/"
            self.headers = {"User-Agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) \
            AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"}
            self.url_queue = Queue()  #保存url
            self.html_queue = Queue() #保存html字符串
            self.content_queue = Queue() #保存提取到的数据
    
        def get_url_list(self):
            for i in range(1,14):
                self.url_queue.put(self.url_temp.format(i))
    
        def parse_url(self):
            while True:
                url = self.url_queue.get()
                html_str =  requests.get(url,headers=self.headers).content.decode()
                self.html_queue.put(html_str)
                self.url_queue.task_done()
    
        def get_content_list(self):
            while True:
                html_str = self.html_queue.get()
                html = etree.HTML(html_str)
                div_list = html.xpath("//div[@id='content-left']/div")
                content_list = []
                for div in div_list:
                    content = {}
                    content["content"]=div.xpath(".//div[@class='content']/span/text()")
                    content_list.append(content)
                self.content_queue.put(content_list)
                self.html_queue.task_done()
    
        def save_content_list(self):
            while True:
                content_list = self.content_queue.get()
                for content in content_list:
                    print(content) # 此处对数据进行保存操作
                self.content_queue.task_done()
    
        def run(self):
            process_list = []
            #1. url_list
            t_url = Process(target=self.get_url_list)
            process_list.append(t_url)
            #2. 遍历,发送请求
            for i in range(5):#创建5个子进程
                t_parse = Process(target=self.parse_url)
                process_list.append(t_parse)
            #3. 提取数据
            t_content = Process(target=self.get_content_list)
            process_list.append(t_content)
            #4. 保存
            t_save = Process(target=self.save_content_list)
            process_list.append(t_save)
    
            for t in process_list:
                t.daemon=True #把进线程设置为守护线程,主进程技术,子进程结束
                t.start()
    
            for q in [self.url_queue,self.html_queue,self.content_queue]:
                q.join()  #让主进程阻塞
    
            print("主进程结束")
    
    if __name__ == '__main__':
        qiubai = QiubaiSpider()
        qiubai.run() 
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73

    上述多进程实现的代码中,multiprocessing提供的JoinableQueue可以创建可连接的共享进程队列。和普通的Queue对象一样,队列允许项目的使用者通知生产者项目已经被成功处理。通知进程是使用共享的信号和条件变量来实现的。 对应的该队列能够和普通队列一样能够调用task_done和join方法


    # 小结

    1. multiprocessing导包:from multiprocessing import Process
    2. 创建进程: Process(target=self.get_url_list)
    3. 添加入队列: put
    4. 从队列获取:get
    5. 守护线程:t.daemon=True
    6. 主线程阻塞: q.join()
    7. 跨进程通讯可以使用from multiprocessing import JoinableQueue as Queue
    编辑 (opens new window)
    多线程爬虫
    线程池爬虫

    ← 多线程爬虫 线程池爬虫→

    最近更新
    01
    theme-vdoing-blog博客静态编译问题
    09-16
    02
    搜索引擎
    07-19
    03
    友情链接
    07-19
    更多文章>
    Theme by Vdoing | Copyright © 2019-2022 Evan Xu | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式