多线程爬虫入库
每日星语:
“你知道年轻的时候穷最大的问题是什么吗?”
“什么”
### “以为所有得不到的一切都是穷的错。眼睛盯着遥远的地方,却看不到身边一朵花的美丽”
-
整体思路
> 队列保存变化的参数,即之前构建的类似页码的东西。 > 一个类实现:三个线程进行数据采集,依次从队列中获取参数,拼接url,请求到的网 页源码保存到新队列。 > 一个类实现 :1. 三个线程进行数据处理,依次从队列中获取源码,xpath定位元素 取出文本,构建字典。2. 定义函数数据入库,pymongon数据插入数据即可
主程序 mian 分为 两 部分 - 实例化队列,我们有两组线程在工作,初始队列一个,线程间通信需要一个,一共两个 - 实例化线程,通过遍历实例化线程类,创建俩组三线程。
调用主程序
-
具体部署,和相关知识点罗列
细节决定成败,必须搞清楚每一步的意义是什么,而不是说这里就应该这么写,没有那么多理所应当。
#####具体部署:
-
定义第一个类:
-
定义类:需要继承threading.Thread父类
-
类属性:想清楚传那些熟悉
-
参数队列要传进来
-
子类重写初始化属性
先继承父类属性---->然后写自己要加的属性
-
-
定义方法:
重写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
-
首先明白什么是进程什么是线程,线程和进程的区别?
线程(有时候称为轻量级进程)与进程类似,不过它们是在同一个进程下执行的,并共享相同的上下文。可以将它们认为是在一个主进程或“主线程”中并行运行的一些“迷你进程”。
-
我们的子线程为什么要设置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)
-