zoukankan      html  css  js  c++  java
  • 使用线程、进程、协程爬虫爬豆瓣电影top 250

    线程:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2021/9/5 21:41
    # @Author : Lhtester
    # @Site : 
    # @File : 豆瓣电影.py
    # @Software: PyCharm
    """使用串行爬虫爬豆瓣电影top 250"""
    #导入模块
    import requests
    import time
    import random
    from lxml import etree
    from queue import Queue
    import threading
    
    class DouBanSpider:
        """爬虫类"""
        def __init__(self):
            self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36"}
            self.base_url = "https://movie.douban.com/top250"
            #声明队列
            self.dataQueue = Queue()
            self.num = 1
    
        def loadPage(self,url):
    
            '''向URL发起请求,获取响应内容'''
            #设置随机休眠
            time.sleep(random.random())
            return requests.get(url,headers=self.headers).content
        def parsePage(self,url):
            '''根据起始URL提取所有的URL'''
    
            #获取URL对应的响应内容
            content = self.loadPage(url)
            #Xpath 处理得到的对应element对象
            html = etree.HTML(content)
            #所有的电影节点
            node_list = html.xpath("//div[@class='info']")
    
            #遍历
            for node in node_list:
                #获取每部电影标题
                title = node.xpath(".//span[@class='title']/text()")[0]
                #每部电影的评分
                score = node.xpath(".//span[@class='rating_num']/text()")[0]
                #将数据存储到队列中
                self.dataQueue.put(score+"	"+title)
            #只有在第一个时获取所有URL组成的列表,其他页就不再获取
            if url == self.base_url:
                return [self.base_url + link for link in html.xpath("//div[@class='paginator']/a/@href")]
    
        def startWork(self):
            """爬虫入口"""
            #第一个页面的请求,需要返回所有页面链接,并提取第一个的电影信息
            link_list = self.parsePage(self.base_url)
    
            thread_list =[]
            #循环发送每个页面的请求,并获取所有的电影信息
            for link in link_list:
                # self.parsePage(link)
                #循环创建了9个线程,每个线程都执行一个任务
                thread = threading.Thread(target=self.parsePage,args=[link])
                thread.start()
                thread_list.append(thread)
    
            #父线程等待所有子线程 结束,自己在结束
            for thread in thread_list:
                thread.join()
    
            #循环get队列的数据,直到队列为空在退出
            while not self.dataQueue.empty():
                print(self.num)
                print(self.dataQueue.get())
                self.num+=1
    
    if __name__ == "__main__":
    
        #创建爬虫对象
        spider =DouBanSpider()
        #开始时间
        start_time = time.time()
        #开始爬虫
        spider.startWork()
        #结束时间
        stop_time = time.time()
        #result
        print("
    [LOG]:%f secondes..."%(stop_time-start_time))

    执行结果:

     多进程:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2021/9/5 21:41
    # @Author : Lhtester
    # @Site : 
    # @File : 豆瓣电影.py
    # @Software: PyCharm
    """使用串行爬虫爬豆瓣电影top 250"""
    #导入模块
    import requests
    import time
    import random
    from lxml import etree
    import multiprocessing
    from  multiprocessing import Queue
    
    class DouBanSpider:
        """爬虫类"""
        def __init__(self):
            self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36"}
            self.base_url = "https://movie.douban.com/top250"
            #声明队列
            self.dataQueue = Queue()
            self.num = 1
    
        def loadPage(self,url):
    
            '''向URL发起请求,获取响应内容'''
            #设置随机休眠
            time.sleep(random.random())
            return requests.get(url,headers=self.headers).content
        def parsePage(self,url):
            '''根据起始URL提取所有的URL'''
    
            #获取URL对应的响应内容
            content = self.loadPage(url)
            #Xpath 处理得到的对应element对象
            html = etree.HTML(content)
            #所有的电影节点
            node_list = html.xpath("//div[@class='info']")
    
            #遍历
            for node in node_list:
                #获取每部电影标题
                title = node.xpath(".//span[@class='title']/text()")[0]
                #每部电影的评分
                score = node.xpath(".//span[@class='rating_num']/text()")[0]
                #将数据存储到队列中
                self.dataQueue.put(score+"	"+title)
            #只有在第一个时获取所有URL组成的列表,其他页就不再获取
            if url == self.base_url:
                return [self.base_url + link for link in html.xpath("//div[@class='paginator']/a/@href")]
    
        def startWork(self):
            """爬虫入口"""
            #第一个页面的请求,需要返回所有页面链接,并提取第一个的电影信息
            link_list = self.parsePage(self.base_url)
    
            process_list =[]
            #循环发送每个页面的请求,并获取所有的电影信息
            for link in link_list:
                # self.parsePage(link)
                #循环创建了9个进程,每个线程都执行一个任务
                process = multiprocessing.Process(target=self.parsePage,args=[link])
                process.start()
                process_list.append(process)
    
            #父线程等待所有子线程 结束,自己在结束
            for process in process_list:
                process.join()
    
            #循环get队列的数据,直到队列为空在退出
            while not self.dataQueue.empty():
                print(self.num)
                print(self.dataQueue.get())
                self.num+=1
    
    if __name__ == "__main__":
    
        #创建爬虫对象
        spider =DouBanSpider()
        #开始时间
        start_time = time.time()
        #开始爬虫
        spider.startWork()
        #结束时间
        stop_time = time.time()
        #result
        print("
    [LOG]:%f secondes..."%(stop_time-start_time))

    结果:

    注释:因本地服务器只有一个CPU,运行时间比单一进程执行多线程慢了3倍

    协程:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @Time : 2021/9/5 21:41
    # @Author : Lhtester
    # @Site : 
    # @File : 豆瓣电影.py
    # @Software: PyCharm
    """使用串行爬虫爬豆瓣电影top 250"""
    #导入模块
    import gevent
    from  gevent import monkey
    #gevent 可以按同步的方式来写异步程序
    #monkey.patch_all()会在python程序执行时动态地将网络库(socket,select,thread)
    #替换掉,变成异步的库,让程序可以以异步的方式处理网络相关的任务
    monkey.patch_all()
    #为什么gevent、monkey、monkey.patch_all()要放在导入的最前面?
    import time
    import requests
    import random
    from lxml import etree
    from queue import Queue
    
    # import sys
    # sys.setrecursionlimit(10000)
    
    
    
    class DouBanSpider:
        """爬虫类"""
        def __init__(self):
            self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36"}
            self.base_url = "https://movie.douban.com/top250"
            #声明队列
            self.dataQueue = Queue()
            self.num = 1
    
        def loadPage(self,url):
    
            '''向URL发起请求,获取响应内容'''
            #设置随机休眠
            time.sleep(random.random())
            return requests.get(url,headers=self.headers).content
        def parsePage(self,url):
            '''根据起始URL提取所有的URL'''
    
            #获取URL对应的响应内容
            content = self.loadPage(url)
            #Xpath 处理得到的对应element对象
            html = etree.HTML(content)
            #所有的电影节点
            node_list = html.xpath("//div[@class='info']")
    
            #遍历
            for node in node_list:
                #获取每部电影标题
                title = node.xpath(".//span[@class='title']/text()")[0]
                #每部电影的评分
                score = node.xpath(".//span[@class='rating_num']/text()")[0]
                #将数据存储到队列中
                self.dataQueue.put(score+"	"+title)
            #只有在第一个时获取所有URL组成的列表,其他页就不再获取
            if url == self.base_url:
                return [self.base_url + link for link in html.xpath("//div[@class='paginator']/a/@href")]
    
        def startWork(self):
            """爬虫入口"""
            #第一个页面的请求,需要返回所有页面链接,并提取第一个的电影信息
            link_list = self.parsePage(self.base_url)
    
            #spawn创建协程任务,并加入任务队列中
            jobs=[gevent.spawn(self.parsePage,link) for link in link_list]
            #父线程阻塞,等待所有任务结束后继续执行
            gevent.joinall(jobs)
    
            #循环get队列的数据,直到队列为空在退出
            while not self.dataQueue.empty():
                print(self.num)
                print(self.dataQueue.get())
                self.num+=1
    
    if __name__ == "__main__":
    
        #创建爬虫对象
        spider =DouBanSpider()
        #开始时间
        start_time = time.time()
        #开始爬虫
        spider.startWork()
        #结束时间
        stop_time = time.time()
        #result
        print("
    [LOG]:%f secondes..."%(stop_time-start_time))

    结果:

    疑问:

    #为什么gevent、monkey、monkey.patch_all()要放在导入的最前面?不然会报错: MonkeyPatchWarning: Monkey-patching ssl after ssl has already been imported may lead to errors
  • 相关阅读:
    虚函数&纯虚函数&抽象类&虚继承
    指针的各式定义
    开源站点
    WCF、Net remoting、Web service概念及区别
    asp.net 分布式应用开发
    C++多重继承二义性解决
    ATL7窗口类详细剖析
    Code review
    GitHub 上100个最受欢迎的Java基础类库
    JAVA基本类库介绍
  • 原文地址:https://www.cnblogs.com/anhao-world/p/15322371.html
Copyright © 2011-2022 走看看