您的位置:首页 > 其它

回顾多线程爬取数据

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.异步处理

  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
  • 收藏
  • 分享
  • 文章举报
沙威探长 发布了15 篇原创文章 · 获赞 4 · 访问量 861 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: