• 8、简单的多线程爬取网页数据 并通过xpath解析存到本地


    # Author:toloy
    # 导入队列包
    import queue
    # 导入线程包
    import threading
    # 导入json处理包
    import json
    # 导入xpath处理包
    from lxml import etree
    # 导入请求处理包
    import requests
    
    class ThreadCrawl(threading.Thread):
        '''
        定义爬取网页处理类,从页码队列中取出页面,拼接url,请求数据,并把数据存到数据队列中
        '''
        def __init__(self, threadName, pageQueue, dataQueue):
            '''
            构造函数
            :param threadName:当前线程名称
            :param pageQueue: 页面队列
            :param dataQueue: 数据队列
            '''
            super(ThreadCrawl, self).__init__()
            self.threadName = threadName
            self.pageQueue = pageQueue
            self.dataQueue = dataQueue
            self.headers = {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36"}
    
        def run(self):
            '''
            线程执行的run方法
            :return:
            '''
            while not self.pageQueue.empty():
                try:
                    pageNum = self.pageQueue.get(False)
                    url = "http://www.dfenqi.cn/Product/Category?category=4945805937081335060-0-0&pageIndex=" + str(pageNum)
                    content = requests.get(url,headers = self.headers).text
                    self.dataQueue.put(content)
                    print(self.threadName + '爬取数据')
                except:
                    pass
    
    # 解析线程是否结束的标识
    PARSE_THREAD_EXIST = False
    
    class ParseThread(threading.Thread):
        '''
        网页数据解析类
        '''
        def __init__(self,threadName,dataQueue,fileName):
            '''
            解析线程的构造函数
            :param threadName:当前线程名称
            :param dataQueue:数据队列
            :param fileName:文件名
            '''
            super(ParseThread,self).__init__()
            self.threadName = threadName
            self.dataQueue = dataQueue
            self.fileName = fileName
    
        def run(self):
            '''
            解析线程的执行run方法,从数据队列取出数据,解析数据,再存入到本地文件中
            :return:
            '''
            while not PARSE_THREAD_EXIST:
                try:
                    html = self.dataQueue.get(False)
                    print(self.threadName + '取到数据')
                    text = etree.HTML(html)
                    # 解析网页中的数据,此处可根据需要,定制解析方法或解析类来实现
                    titleList = text.xpath("//div[@class='liebiao']/ul/li/a/p/text()")
                    with open(self.fileName,'a',encoding='utf-8') as f:
                        for title in titleList:
                            f.write(title + "
    ")
                    print(self.threadName + '解析完成')
                except:
                    pass
    
    def main():
        '''
        调度方法,main入口执行方法
        :return:
        '''
        # 创建页码队列,用于存储页码
        pageQueue = queue.Queue(50)
        for i in range(1, 51):
            pageQueue.put(i)
        # 数据队列,用于存储爬取的数据供解析线程使用
        dataQueue = queue.Queue()
        # 将解析结果保存的文件名
        fileName = 'file.txt'
        # 爬取线程的名称列表
        cawlThreadNameList = ['线程一', '线程二']
        crawThreadlList = []
        for threadName in cawlThreadNameList:
            thread = ThreadCrawl(threadName, pageQueue, dataQueue)
            thread.start()
            crawThreadlList.append(thread)
    
        # 解析线程的名称列表
        parseThreadNameList = ['解析线程一','解析线程二']
        parseThreadList = []
        for threadName in parseThreadNameList:
            thread = ParseThread(threadName,dataQueue,fileName)
            thread.start()
            parseThreadList.append(thread)
        # 等待爬取线程处理结束
        for thread in crawThreadlList:
            thread.join()
        # 判断数据队列中是否处理完成了,当处理完成后,将退出解析线程标识为True
        if pageQueue.empty():
            global PARSE_THREAD_EXIST
            PARSE_THREAD_EXIST = True
        # 等待解析线程退出
        for thread in parseThreadList:
            thread.join()
    
    if __name__ == "__main__":
        main()
    
  • 相关阅读:
    安装 logstash
    ES 关于 Index、Type、Document
    java 获取 属性的注释(二)
    outlook 发件人 xxx 代替 xxx 的问题
    EDI 报文发送(拼箱实例)
    微服务拆分之道
    DDD 领域驱动设计之面向对象思想
    如何构建知识体系?
    架构思维:系统容量设计
    接口性能优化技巧
  • 原文地址:https://www.cnblogs.com/toloy/p/8625328.html
Copyright © 2020-2023  润新知