回顾多线程爬取数据

明确目的:将多线程爬虫涉及到的技术点回顾一下
首先,是基本流程,多线程爬虫架构图如下
在这里插入图片描述

首先,我们需要回顾一下队列线程:

**

队列

**
用来存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.异步处理

  1. 爬取,解析

这里我们要异步爬取每个url对应的页面,并解析爬取到的数据:异步:访问资源时在空闲等待时同时访问其他资源

区别同步和异步
一个进程启动的多个不相干线程,它们相互之间关系为异步。
同步必须执行到底之后才能执行其他操作,而异步可以任意操作
(任务A执行到一个阶段,需要 任务B的某个结果,A任务会停下来等待)

  1. 数据持久化,处理高并发

将数据写到数据库,由于线程共享全局变量负责解析的线程会竞争同一资源,导致我们爬取的数据入库时出现异常
因此我们可以加锁实现线程的同步,

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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值