多线程爬虫入库

多线程爬虫入库

每日星语:

“你知道年轻的时候穷最大的问题是什么吗?”

“什么”

### “以为所有得不到的一切都是穷的错。眼睛盯着遥远的地方,却看不到身边一朵花的美丽”

  1. 整体思路

    > 队列保存变化的参数,即之前构建的类似页码的东西。
    
    > 一个类实现:三个线程进行数据采集,依次从队列中获取参数,拼接url,请求到的网	页源码保存到新队列。
    
    > 一个类实现 :1.  三个线程进行数据处理,依次从队列中获取源码,xpath定位元素	取出文本,构建字典。2. 定义函数数据入库,pymongon数据插入数据即可
    
    主程序 mian 分为 两 部分
    
    - 实例化队列,我们有两组线程在工作,初始队列一个,线程间通信需要一个,一共两个
    
    - 实例化线程,通过遍历实例化线程类,创建俩组三线程。
    
    调用主程序
    
  2. 具体部署,和相关知识点罗列

    细节决定成败,必须搞清楚每一步的意义是什么,而不是说这里就应该这么写,没有那么多理所应当。

    #####具体部署:

    • 定义第一个类:

      • 定义类:需要继承threading.Thread父类

      • 类属性:想清楚传那些熟悉

        1. 参数队列要传进来

        2. 子类重写初始化属性

          先继承父类属性---->然后写自己要加的属性

      • 定义方法:

        重写run方法

        ​ 通过无限循环获取队列中的参数,实现请求多页面,

        ​ 这个队列是被三个线程去访问的。

    • 定义第二个类:

      ​ 需要考虑的和第一个类思路是一样的,这里有一个互斥锁的加入

      ​ 就是在处理数据的时候加入,因为写入数据库的字段都一样,避免数据量过大

      ​ 出错,导致数据错乱。

    • 主程序代码

      • 实例队列对象

        page_Queue = Queue() 构建参数

        data_Queue = Queue() 负责两个主线程间的通信

      • 实例互斥锁对象

        lock = Lock()

      • 构建两个主线程,一个线程负责采集数据,一个线程处理数据并入库

      • 当然都是用for循环来构建的,记得线程类需要传入那些属性

    • 调用主程序

    #####相关知识点:

    • 重写父类同名方法需要注意:

      class ParseTread(threading.Thread):
          def __init__(self, threadName, dataQueue, lock):
              # 先把父类的方法继承下来
              super(ParseTread, self).__init__()
              # 然后定义自己的方法
              self.threadName = threadName
              self.dataQueue = dataQueue
              self.lock = lock
      
    • 首先明白什么是进程什么是线程,线程和进程的区别?

      线程(有时候称为轻量级进程)与进程类似,不过它们是在同一个进程下执行的,并共享相同的上下文。可以将它们认为是在一个主进程或“主线程”中并行运行的一些“迷你进程”。

      这里讲的很清楚https://www.cnblogs.com/chbo/p/7043660.html

    • 我们的子线程为什么要设置join(),其实设置了守护线程才是join()出现的时机

      如果是为了避免数据的恶性竞争的话,互斥锁是接这个的小能手。

    • 为什么要设置守护线程

      如果给线程设置守护线程,那么后台线程执行完毕就会杀死这些线程。大致的作用就是当你退出进程,后台线程关闭那么这些子线程也要同时关闭。

    • join()的作用,和其存在的意义

      join()的功能是设置阻塞,之所以要设置join()就是有选择的设置守护线程,因为我们有的线程需要同步主线程结束而结束,而有的线程需要执行完毕菜行。设置了守护线程的子线程都会随着主线的结束而结束。

      我们这里设置的join()是没有意义的,因为并没有设置守护线程,因此没必要设置阻塞。

    import requests
    from urllib import request
    from chaojiying import Chaojiying_Client
    from lxml import etree
    import re, threading
    from threading import Lock
    from queue import Queue
    import pymongo
    import time
    
    
    class CrawlThread(threading.Thread):
        def __init__(self, threadName, page_Queue, data_Queue):
            super(CrawlThread, self).__init__()
            self.threadName = threadName
            self.pageQueue = page_Queue
            self.dataQueue = data_Queue
            self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36",}
    
        def run(self):
            url1 = 'http://www.ziroom.com/z/nl/z3.html?p=%s'
            while True:
                try:
                    # 如果队列为空 block 为 True 那么进入阻塞状态
                    # 如果队列为控 block 为 false 那么会抛出异常
                    p = self.pageQueue.get(block=False)
                    print('%s开始工作...' % self.threadName)
                    response = requests.get(url=url1 % p, headers=self.headers)
                    content = response.text
                    self.dataQueue.put(content)
                    # print(self.dataQueue.qsize())
                    print('%s工作结束...' % self.threadName)
                except:
                    break
    
                    
    class ParseTread(threading.Thread):
        def __init__(self, threadName, dataQueue, lock):
            super(ParseTread, self).__init__()
            self.threadName = threadName
            self.dataQueue = dataQueue
            self.lock = lock
    
        def run(self):
            while True:
                try:
                    html = self.dataQueue.get(block=False)
                    print('%s开始处理数据........' % self.threadName)
                    self.get_price_list(html)
                    print('%s数据处理完毕........' % self.threadName)
                except Exception as e:
                    print(e)
                    # print('出错了')
                    break
    
        def get_price_list(self, html):
            # 正则匹配图片地址,超级鹰打码,获取列表两个参数 code 下标列表
            price_image = re.findall(r'"image":"(.*?)"', html)[0]
            index_list = re.findall(r'"offset":(.*?)};', html)[0]
            index_list = eval(index_list)
            # print(index_list)
            price_image_link = 'http:' + price_image
            # print(price_image_link)
            request.urlretrieve(price_image_link, './im.jpg')
            # 超级鹰打码,获取到图片中的数字
            chaojiying = Chaojiying_Client('ipython', '123456789', '96001')
            im = open('im.jpg', 'rb').read()
            code = chaojiying.PostPic(im, 4111)['pic_str']
            price_list = []
            for j in index_list:
                # print(j)
                str1 = ''
                for i in j:
                    str1 += code[int(i)]
                # print(code)
                # print(str1)
                price_list.append(int(str1))
            self.get_detail_list(html, price_list)
    
        def get_detail_list(self, html, price_list):
            html = etree.HTML(html)
            data_list = html.xpath('//ul[@id="houseList"]/li')
            a = 0
            for i in data_list:
                item = {}
                title = i.xpath('.//h3/a[@class="t1"]/text()')[0]
                size_detail = i.xpath('.//div[@class="detail"]/p')[0].xpath('.//span/text()')
                position = i.xpath('.//div[@class="detail"]/p')[1].xpath('.//span/text()')[0]
                item = {'标题': title, '面积': size_detail, '位置': position, '价格': price_list[a]}
                a += 1
                with self.lock:
                    self.save(item)
    
        def save(self, item):
            conn = pymongo.MongoClient("localhost",27017)
            db = conn.qiubai
            table = db.qiubai
            table.insert(item)
           
    def main(n):
        page_Queue = Queue()
        data_Queue = Queue()
        lock = Lock()
        for i in range(1,n+1):
            page_Queue.put(i)
    
        crawlList = {'长征1号', '长征2号', '长征3号'}
        TreadCrawl = []
        for var in crawlList:
            c = CrawlThread(var, page_Queue, data_Queue)
            c.start()
            TreadCrawl.append(c)
        for var in TreadCrawl:
            var.join()
        parseList = ['嫦娥1号', '嫦娥2号', '嫦娥3号']
        TreadParse = []
        for var in parseList:
            p = ParseTread(var, data_Queue, lock)
            p.start()
            TreadParse.append(p)
        for var in TreadParse:
            var.join()
    
    if __name__ == '__main__':
        main(10)
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仙女肖消乐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值