回顾多线程爬取数据
2020-01-14 19:03
399 查看
明确目的:将多线程爬虫涉及到的技术点回顾一下
首先,是基本流程,多线程爬虫架构图如下
首先,我们需要回顾一下队列和线程:
**
队列
**
用来存url,和 网页的响应内容,给线程提供数据线程数据
class Queue(object): """ enqueue(item) 往队列中添加一个item元素 dequeue() 从队列头部删除一个元素 is_empty() 判断一个队列是否为空 size() 返回队列的大小 """ def __init__(self): self.queue = [] def put(self, item): self.queue.append(item) def get(self): return self.queue.pop(0) def isempty(self): return self.queue == [] def size(self): return len(self.queue)
当然,这是手写的,(熟悉下方法的作用),这次我们直接从queue模块,导入对列类
这次我们主要用put()和get()方法,其中给get(block=False)队列将引发Empty异常.
from queue import Queue urlQueue = Queue() dataQueue = Queue() lock = threading.Lock() url = 'https://www.qiushibaike.com/text/page/{}/' for i in range(1, 15): urlQueue.put(url.format(i))
线程
线程操作系统能够进行运算调度的最小单位,进程中的实际运作单位
适用范围
1.服务器中的文件管理或通信控制
2.前后台处理
3.异步处理
- 爬取,解析
这里我们要异步爬取每个url对应的页面,并解析爬取到的数据:异步:访问资源时在空闲等待时同时访问其他资源
区别同步和异步
一个进程启动的多个不相干线程,它们相互之间关系为异步。
同步必须执行到底之后才能执行其他操作,而异步可以任意操作
(任务A执行到一个阶段,需要 任务B的某个结果,A任务会停下来等待)
- 数据持久化,处理高并发
将数据写到数据库,由于线程共享全局变量负责解析的线程会竞争同一资源,导致我们爬取的数据入库时出现异常
因此我们可以加锁实现线程的同步,
from threading import Lock lock = Lock()
同步解决了线程的安全问题,但是会降低效率,
-
负责爬取:
class SpiderThread(threading.Thread): def __init__(self, s_name, headers, urlQueue, dataQueue): super().__init__() self.name = s_name self.headers = headers self.urlQueue = urlQueue self.dataQueue = dataQueue def run(self): while True: try: url = self.urlQueue.get(block=False) print(self.name + '开始爬取数据') res = requests.get(url=url, headers=self.headers) print(self.name + '完成爬取数据') self.dataQueue.put(res.text) except: break
-
负责解析,数据持久化
class ParseThread(threading.Thread): def __init__(self, p_name, dataQueue, lock, items): super().__init__() self.name = p_name self.dataQueue = dataQueue self.lock = lock self.items = items def run(self): while True: try: html = self.dataQueue.get(block=False) print(self.name + '开始解析数据') self.parse(html) print(self.name + '解析数据完成') except: break def parse(self, html): soup = BeautifulSoup(html, 'lxml') a_list = soup.select('a > h2') for a in a_list: item = {'name': a.string.strip()} with self.lock: self.save(item) def save(self, item): pass
创建线程
def main() 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" } # 队列 urlQueue = Queue() dataQueue = Queue() lock = threading.Lock() url = 'https://www.qiushibaike.com/text/page/{}/' for i in range(1, 15): urlQueue.put(url.format(i)) # 爬取线程 s_name_list = ['甲', '乙', '丙'] s_list = [] for s_name in s_name_list: s = SpiderThread(s_name, headers, urlQueue, dataQueue) s.start() s_list.append(s) for s in s_list: s.join() # 解析线程 p_name_list = ['戊', '己', '庚'] p_list = [] for p_name in p_name_list: p = ParseThread(p_name, dataQueue, lock, items) p.start() p_list.append(p) for p in p_list: p.join()
- 点赞 1
- 收藏
- 分享
- 文章举报
相关文章推荐
- C# 多线程并发处理数据库数据,发送信号等待处理完统一插入.
- Javascript高级程序设计第3章回顾总结部分--数据类型
- Delphi中多线程用消息实现VCL数据同步显示
- VC++回顾----多线程
- Linux多线程实践(4) --线程特定数据
- 小白如何入门大数据,资深技术大牛带你回顾学习历程!
- 数据挖掘回顾十一:关联规则挖掘之 Apirori 算法
- 空气质量国控站点数据插值出全国3181个城市值,利用了多线程
- C#开发之多线程数据同步
- 多线程 批处理 数据导入工具 Java
- 多线程的那点事儿(之数据互斥)
- Delphi多线程编程之三同步读写全局数据
- 初学Java多线程:向线程传递数据的三种方法
- 多线程(三) 实现线程范围内模块之间共享数据及线程间数据独立(ThreadLocal)
- 多线程私有数据pthread_key_create
- 在vb.net中运用多线程实现远程数据收集
- c# ListBox 多线程更新数据
- 使用多线程实现UDP进行数据的收发
- 多线程一共就俩问题:1.线程安全(访问共享数据) 2.线程通信(wait(),notify())
- [原创]多线程下不重复读取SQL Server的数据