import queue
Queue 类是 Python 标准库中线程安全的队列实现,提供了一个适用于多线程编程的先进先出的数据结构——队列,用于生产者和消费者线程之间的信息传递。
队列是线程间最常用的交换数据的形式。为什么使用队列(Queue),而不使用 Python 原生的列表(List)或字典(Dict)类型呢?原因是 List、Dict等数据存储类型都是非线程安全的。在多线程中,为了防止共享资源的数据不同步,对资源加锁是个重要的环节。
Queue 类实现了所有的锁逻辑,能够满足多线程的需求,所以在满足使用条件的情况下,建议使用队列。
一、Queue 类数据存储和管理的常用方法
① queue.Queue(maxsize)
用于创建队列,maxsize 规定了队列的长度。一旦达到上限,再添加数据会导致阻塞,直到队列中的数据被消耗掉。如果 maxsize 小于或者等于0,表示队列大小没有限制。maxsize 默认值为0。
② empty()
如果队列为空,返回 True,否则返回 False。
③ full()
如果队列已满则返回 True,否则返回 False。
④ qsize()
返回队列的大小。
⑤ get(block=True, timeout=None)
从队头获取并删除第一个元素。它有两个可选参数:
默认值为 True,即当队列为空时,阻塞当前线程;当值为 False 时,即当队列为空时,不阻塞线程,而是抛出 Empty 异常。
设置阻塞的最大时长,默认为 None。
当 block 值为 True 时,timeout 为 None,则表示无限期阻塞线程,直到队列中有一个可用元素;timeout 为正数,表示阻塞的最大等待时长,如果超出时长队列中还没有元素,则抛出 Empty异常。
当 block 值为 False 时,忽略 timeout 参数。
⑥ put(item, block=True, timeout=None)
在队尾添加一个元素。put() 有3个参数:
必需的参数,表示添加元素的值。
可选参数,默认值为 True,表示当队列已满时阻塞当前线程。如果取值为 False,则当队列已满时抛出 Full 异常。
可选参数,默认为 None。
当 block 参数值为 True 时,timeout 表示阻塞的时长;当 timeout 为 None 时,表示无限期阻塞线程,直到队列中空出一个数据单元;如果 timeout 为正数,则表示阻塞的最大等待时长,如果超出最大时长还没有可用数据单元出现,则引发 Full 异常。
如果 block 参数为 False,则忽略 timeout 参数。
⑦ get_nowait()
立即取出一个元素,不等待,相当于 get(False)
⑧ put_nowait()
立即放入一个元素,不等待,相当于 put(item, False)
⑨ task_done()
在完成一项工作之后,task_done() 函数向任务已经完成的队列发送一个信号。
⑩ join()
阻塞当前线程,直到队列中的所有元素都已被处理。
二、补充前一节,使用 bs4 库解析网页数据
① 通过 bs4 库的 CSS 选择器搜索 <tr class="even"> 和 <tr class="odd"> 标签,并保存到列表中。
② 遍历列表取出每一个 td 标签中的文本,以及 href 属性的值,将每个标签对应的含义与文本内容一一对应地保存到字典中,并且将这些字典都保存到列表中。
在 spider.py 文件中导入 BeautifulSoup 类
from bs4 import BeautifulSoup
创建一个 BeautifulSoup 类的对象,并通过 CSS 选择器获取所有的 tr 标签。为了能够更精准地描述 tr 标签,需要在标签的后面加上其特有的属性:
tr[class="even"]
tr[class="odd"]
在 parse_page() 方法中,创建一个 BeautifulSoup 对象,分别调用 select() 方法,以字符串的形式传入上述两条语句,搜索到全部标签:
def parse_page(self, html):
# 创建 BeautifulSoup 解析工具,使用 lxml 解析器进行解析
html = BeautifulSoup(html, 'lxml')
# 通过 CSS 选择器搜索 tr 节点
result = html.select('tr[class="even"]')
result2 = html.select('tr[class="odd"]')
result += result2
通过 for ... in 循环遍历 result 列表,使用 CSS 选择器获取上述这些子元素的文本,并将这些元素的含义与文本以字典的形式保存到列表中。
items = []
for site in result:
item = {}
# 职位名称
name = site.select('td a')[0].get_text()
# 详情链接
detailLink = site.select('td a')[0].attrs['href']
# 职位类别
catalog = site.select('td')[1].get_text()
# 招聘人数
recruitNumber = site.select('td')[2].get_text()
# 工作地点
workLocation = site.select('td')[3].get_text()
# 发布时间
publishTime = site.select('td')[4].get_text()
item["职位名称"] = name
item["详情链接"] = self.base_url + detailLink
item["职位类别"] = catelog
item["招聘人数"] = recruitNumber
item["工作地点"] = workLocation
item["发布时间"] = publishTime
items.append(item)
return items
③ 将数据保存到文件中
在 Spider 类中,定义一个将数据保存到文件的方法 save_file()。在该方法中,创建一个名为 tencent.txt 的文件,并将数据写入到该文件中。
def save_file(self, items):
file = open('tencent.txt', "wb+")
file.write(str(items).encode())
file.close()