zoukankan      html  css  js  c++  java
  • 爬虫--多线程编程-提高效率--泛见(犯贱)志趣图标题和链接爬取

    #还需要调试 从头调试
    
    
    import threading
    import time
    from queue import Queue
    import requests
    from lxml import etree
    import json
    
    #创建一个列表用来存放采集线程
    g_crawl_list = []
    #创建一个列表用来存放解析线程
    g_parse_list = []
    
    
    #创建采集线程对象  采集线程对象需要用到两个队列 页码的队列 存页面源码的队列
    class CrawlThread(threading.Thread):
        def __init__(self,name,page_queue,data_queue):
            super().__init__()
            self.name = name
            self.page_queue = page_queue
            self.data_queue = data_queue
            self.url = "http://www.ifanjian.net/latest-{}"
            self.headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36'
    }
        #启动采集线程后开始运行的函数
        def run(self):
            print('%s-----线程启动'% self.name)
            #线程要一直跑 要是不这样的话 他只能跑你创建的个数页
            while 1:
                #判断采集线程何时退出  要爬取的页数队列空了就结束了
                if self.page_queue.empty():
                    break
                #从队列中取出页码
                page = self.page_queue.get()
                # print(page)
                # exit()
                #拼接url 发送请求
                url = self.url.format(page)
                # print(url)
                # exit()
                r = requests.get(url=url,headers = self.headers)
                # print(r.text)
                # exit()
                #将响应内容存放到data_queue队列中
                self.data_queue.put(r.text)
            print('%s-----线程结束'% self.name)
    
    
    
    #创建解析线程对象   解析线程只需要页面源码这个队列 解析出的东西存入别的列表 最后输出
    class ParserThread(threading.Thread):
        def __init__(self,name,data_queue,fp,lock):
            super().__init__()
            self.name = name
            self.data_queue = data_queue
            self.fp = fp
            self.lock = lock
        def run(self):
            print('%s-----线程启动'% self.name)
            while 1:
                # if self.data_queue.empty():
                #     break
                #从data_queue中取出一页数据
                data = self.data_queue.get()
                # print(data)
                # exit()
                #解析内容即可
                self.parse_content(data)
            print('%s-----线程结束'% self.name)
        def parse_content(self,data):
            tree = etree.HTML(data)
            #先查找所有的li再从li里面找自己的标题和url
            li_list = tree.xpath('//ul[@class = "cont-list"]/li')
            # print(li_list)
            # print(len(li_list))
            # exit()
            ##建立一个空列表存数据
            #items = []
            for oli in li_list:
                #获取图片标题
                title = oli.xpath('.//h2/a/text()')[0]
                # print(title)
                # exit()
                #获取图片url
                image_url = oli.xpath('.//div[contains(@class,"cont-list-main")]/p/img[@class= "lazy"]/@data-src')
                # print(image_url)
                # exit()
                #存放到一个字典中
                item = {
                    '标题':title,
                    '链接':image_url
                }
                # print(item)
                # exit()
                #写到文件中  但是需要先上锁
                self.lock.acquire()
                self.fp.write(str(item)+'
    ')
                self.lock.release()
    
    
    #创建采集线程  就是实例化采集线程对象的函数
    def create_crawl_thread(page_queue,data_queue):
        crawl_name = ['采集线程一号','采集线程二号','采集线程三号']
        for name in crawl_name:
            tcrawl = CrawlThread(name,page_queue,data_queue)
            #每次线程工作完一次把结果存放到采集列表
            g_crawl_list.append(tcrawl)
    
    
    #创建解析线程  就是实例化解析线程对象的函数
    def create_parse_thread(data_queue,fp,lock):
        parse_name = ['解析线程一号','解析线程二号','解析线程三号']
        for name in parse_name:
            tparse = ParserThread(name,data_queue,fp,lock)
            #每次线程工作完一次把结果存放到解析列表
            g_parse_list.append(tparse)
    
    #创建队列函数
    def create_queue():
        #创建页码队列
        page_queue = Queue()
        #这里添加爬取页数  目前是1到5页
        for page in range(1,20):
            page_queue.put(page)
        #创建队列内容
        data_queue = Queue()
        return page_queue,data_queue
    
    #主函数
    def main():
        #创建队列函数
        page_queue,data_queue = create_queue()
        #打开文件
        fp = open('fanjianzhi.txt','a',encoding='utf8')
        #创建锁
        lock = threading.Lock()
        #创建采集线程
        create_crawl_thread(page_queue,data_queue)
        #一开始解析队列为空 所以需要等待一会
        time.sleep(10)
        #创建解析线程 解析线程存档时会用到fp 将其作为参数传入
        create_parse_thread(data_queue,fp,lock)
        #启动所有采集线程
        for tcrawl in g_crawl_list:
            tcrawl.start()
        #启动所有解析线程
        for tparse in g_parse_list:
            tparse.start()
        #主线程等待两个子线程结束
        for tcrawl in g_crawl_list:
            tcrawl.join()
        for tparse in g_parse_list:
            tparse.join()
        #在这里关闭文件
        fp.close()
        print("主线程子线程全部结束")
    
    
    
    if __name__ == '__main__':
        main()

     这线程玩起来确实比常规爬取写起来要困难,但是据说效率高,而且也是爬虫正规化的必由之路,没办法,也得学

    作者:求知鱼

    -------------------------------------------

    个性签名:你有一个苹果,我有一个苹果,我们交换一下,一人还是只有一个苹果;你有一种思想,我有一种思想,我们交换一下,一个人就有两种思想。

    如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!

    独学而无友,则孤陋而寡闻,开源、分享、白嫖!

  • 相关阅读:
    C++学生成绩管理系统
    蓝桥杯算法训练 最大最小公倍数
    蓝桥杯基础练习 完美的代价
    vim编辑器的使用技巧
    C语言中static关键字的用法
    在linux环境下编译运行OpenCV程序的两种方法
    Linux中gcc编译器的用法
    浅谈Java中的hashcode方法
    读CopyOnWriteArrayList有感
    徐汉彬:Web系统大规模并发——电商秒杀与抢购(技术实现)
  • 原文地址:https://www.cnblogs.com/Qiuzhiyu/p/12184526.html
Copyright © 2011-2022 走看看