网页源代码抓取工具( 安装BeautifulSoup库的使用规则介绍及重点知识介绍库)
优采云 发布时间: 2022-03-18 10:11网页源代码抓取工具(
安装BeautifulSoup库的使用规则介绍及重点知识介绍库)
BeautifulSoup 库
虽然 XPath 比正则表达式使用起来更方便,但并不是最方便,只是更方便。我们的 BeautifulSoup 库可以让您更轻松地抓取您想要的内容。
安装 BeautifulSoup 库
在使用之前,还是老规矩先安装 BeautifulSoup 库。说明如下:
pip install beautifulsoup4
其中文开发文件:
https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
BeautifulSoup 库简介
BeautifulSoup 库是一个强大的 Python 语言 XML 和 HTML 解析库。它提供了一些简单的函数来处理导航、搜索、修改解析树等。
BeautifulSoup 库还可以自动将输入文档转换为 Unicode 编码,将输出文档自动转换为 UTF-8 编码。
所以在使用BeautifulSoup库的过程中,开发时不需要考虑编码问题,除非你解析的文档没有指定编码方式,开发时需要进行编码处理。
接下来详细介绍一下 BeautifulSoup 库的使用规则。
选择翻译
下面,我们来详细介绍一下 BeautifulSoup 库的关键知识。
首先,BeautifulSoup 库中的一个重要概念是解释器的选择。因为它的底层依赖都是这些解释器,所以我们有必要去了解它们。博主特意列了一张表:
口译员
如何使用
优势
缺点
Python 标准库
BeautifulSoup(code,'html.parser')
Python内置标准库,执行速度适中,容错能力强
Python2.7.3 和 Python3.2.2 之前的版本容错性差
lxml HTML解析器
BeautifulSoup(代码,'lxml')
解析速度快,容错能力强
需要安装C语言库
lxml XML解析器
BeautifulSoup(代码,'xml')
快速解析,唯一支持XML的解析器
需要安装C语言库
html5lib
BeautifulSoup(代码,'html5lib')
最佳容错性,以浏览器的方式解析文档,生成HTML5格式的文档
解析很慢
从上表可以看出,爬虫我们一般使用lxml HTML解析器。它不仅速度快,而且兼容性强。只是安装C语言库的一个缺点(不能叫缺点,应该叫麻烦)。
基本用法
使用BeautifulSoup库需要像其他库一样导入,但是虽然安装了beautifulsoup4,但是导入的名字不是beautifulsoup4,而是bs4。用法如下:
from bs4 import BeautifulSoup
soup = BeautifulSoup('Hello World', 'lxml')
print(soup.h1.string)
运行后,输出文本如下:
节点选择器
基本用法很简单,这里就不赘述了。下面开始详细学习BeautifulSoup库的所有重要知识点,第一个就是节点选择器。
所谓节点选择器,就是直接通过节点名称来选择节点,然后使用字符串属性来获取节点中的文本,是最快的获取方式。
例如,在基本用法中,我们使用 h1 直接获取 h1 节点,然后通过 h1.string 获取其文本。但是这种用法有一个明显的缺点,就是不适合复杂的关卡。
因此,我们需要在使用节点选择器之前收缩文档。比如一个文档很大,但是我们获取的内容只是在id为blog的div中,那么非常适合我们先获取这个div,然后在div里面使用节点选择器。
HTML 示例代码:
我是一个测试页面
在下面的示例中,我们仍然使用这段 HTML 代码来解释节点选择器。
获取节点名称属性内容
这里先教大家如何获取节点的name属性和内容。示例如下:
from bs4 import BeautifulSoup
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
soup = BeautifulSoup(html, 'lxml')
# 获取节点的名称
print(soup.title.name)
# 获取节点的属性
print(soup.meta.attrs)
print(soup.meta.attrs['charset'])
# 获取节点的内容(如果文档有多个相同属性,默认获取第一个)
print(soup.a.string)
# 也可以一层一层的套下去
print(soup.body.ul.li.a.string)
运行后效果如下:
这里注释的代码很详细,这里不再赘述。
获取所有子节点
一般来说,一个节点的子节点可能有很多个,通过上述方法只能得到第一个。如果要获取一个标签的所有子节点,有两种方法。我们先来看代码:
from bs4 import BeautifulSoup
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
soup = BeautifulSoup(html, 'lxml')
# 获取直接子节点
print("获取直接子节点")
contents = soup.head.contents
print(contents)
for content in contents:
print(content)
children = soup.head.children
print(children)
for child in children:
print(child)
运行后效果如下:
如上代码所示,我们有两种方式获取所有子节点,一种是通过contents属性,另一种是通过children属性,两种遍历的结果是一样的。
但是需要特别注意,这里要获取所有的子节点,它会将换行符一起计算,所以在控制台输出中会看到很多空行。因此,在实际爬虫中,遍历时必须删除这些空行。
获取所有后代节点
由于可以得到直接的子节点,所以也可以得到所有的后代节点。BeautifulSoup 库为我们提供了 descendants 属性来获取后代节点。示例如下:
from bs4 import BeautifulSoup
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
soup = BeautifulSoup(html, 'lxml')
# 获取ul的所有子孙节点
print('获取ul的所有子孙节点')
lis = soup.body.ul.descendants
print(lis)
for li in lis:
print(li)
运行后效果如下:
同样,后代在获取后代节点时也会计算换行符。重要的是要注意,descendants 属性将文本内容本身计为后代节点。
父节点和兄弟节点
同样,在实际的爬虫程序中,我们有时需要反向搜索父节点,或者搜索兄弟节点。
BeautifulSoup库为我们提供了parent属性获取父节点,next_sibling属性获取当前节点的下一个兄弟节点,previous_sibling属性获取上一个兄弟节点。
示例代码如下:
from bs4 import BeautifulSoup
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
soup = BeautifulSoup(html, 'lxml')
# 获取第一个a标签的父亲节点的class属性
print(soup.a.parent['class'])
li1 = soup.li
li3 = li1.next_sibling.next_sibling.next_sibling.next_sibling
li2 = li3.previous_sibling.previous_sibling
print(li1)
print(li2)
print(li3)
for sibling in li3.previous_siblings:
print(sibling)
运行后效果如下:
前面说过,节点选择器也会把换行符'\n'算作一个节点,所以第一个li需要传递两个next_sibling才能得到下一个li节点。上一个也是如此。其实还有一种更简单的方法可以避免这些换行符被计算在内,就是在获取网页源代码的时候,简单的去掉换行符和空格即可。
方法选择器
对于节点选择器,博主介绍过可以用更少的文本内容来完成。但是,爬虫实际抓取到的url数据量很大,不适合开始使用节点选择器。所以,我们不得不考虑通过方法选择器进行处理的第一步。
find_all() 方法
find_all()方法主要用于根据节点名称、属性、文本内容等选择所有满足要求的节点,其完整定义如下:
def find_all(self, name=None, attrs={}, recursive=True, text=None,
limit=None, **kwargs):
范围
意义
姓名
指定节点名称
属性
指定属性名和值,比如找到value="text"的节点,attrs={"value":"text"}
递归的
Boolean 类型,值为 True 查找后代节点,值为 False 为直接子节点,默认为 True
文本
指定要查找的文本
限制
因为find_all返回的是一个列表,可以长也可以短,limit类似于数据库语法,限制了获取的次数。不设置全部返回
【实战】还是测试上面的HTML,我们得到name=a,attr={"class":"aaa"},文本等于text="Python section" section的节点。
示例代码如下所示:
from bs4 import BeautifulSoup
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
soup = BeautifulSoup(html.strip(), 'lxml')
a_list = soup.find_all(name='a', attrs={"class": 'aaa'}, text='Python板块')
for a in a_list:
print(a)
运行后效果如下:
查找()方法
find() 和 find_all() 的区别只有一个 all,但结果有 2 点不同:
1.find() 只查找第一个满足条件的节点,而 find_all() 查找所有满足条件的节点 2.find() 方法返回 bs4.element.Tag 对象,并且 find_all() 返回一个 bs4.element.ResultSet 对象
接下来,我们在上面的 HTML 中查找 a 标签,看看返回的结果有什么不同。示例如下:
from bs4 import BeautifulSoup
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
soup = BeautifulSoup(html.strip(), 'lxml')
a_list = soup.find_all(name='a')
print("find_all()方法")
for a in a_list:
print(a)
print("find()方法")
a = soup.find(name='a')
print(a)
运行后效果如下:
CSS 选择器
首先,我们来了解一下 CSS 选择器的规则:
1..classname:选择样式名为classname的节点,即class属性值为classname的节点2.#idname:选择id属性为idname的节点3.nodename :用nodename选择节点名node
一般来说,在 BeautifulSoup 库中,我们使用函数 select() 来操作 CSS 选择器。一个例子如下:
from bs4 import BeautifulSoup
with open('demo.html', 'r', encoding='utf-8') as f:
html = f.read()
soup = BeautifulSoup(html.strip(), 'lxml')
li = soup.select('.li1')
print(li)
在这里,我们选择类等于 li1 的节点。运行后效果如下:
嵌套选择节点
因为,我们需要实现嵌套 CSS 选择器的使用,但是上面的 HTML 并不适合。在这里,我们稍作修改,改一下