文章目录
前言
前面学习到了使用正则表达式来实现一个基本的爬虫进行数据的爬取,但是这个正则表达式使用起来还是比较的繁琐,毕竟要写符号啊啥的都太多了,一不留神就容易搞错了,然后导致匹配失败,然后怼着那一坨找半天也不知道到底哪错了,就很烦!由于我们在使用爬虫的时候大多数都是用来爬取网页源代码中的信息,而对于一个HTML网页来说,他其中的逻辑结构还是比较明确的,每一个标签,每一个属性都有其自有的层次关系,我们就可以通过这种关系来获取到我们想要的文本或者属性信息。基于这样一种思想,我们python中提供了功能强大的解析库给我们使用,这些解析库包括lxml、BeautifulSoup、pyquery等,有了他们,我们提取HTML文本信息的时候就方便多了。
XPath的使用
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。
虽说是用来搜索XML语言的,但是他同样适用于HTML文档的搜索。
XPath常用匹配规则
图源菜鸟教程
这里我们写一个XPath规则://title[@lang=‘eng’]
他代表选择所有名称为title,同时属性lang的值为eng的标签。
由于XPath很多的节点匹配跟HTML语言里面的标签之间的关系有关,所以大家还是应该先学习一下HTML的知识,然后理解起来就非常的简单了。
Beautiful Soup的使用
Beautiful Soup跟XPath比较的类似,同样是借助网页的结构和属性等特性来解析网页。
节点选择器
选择元素
注:此处包括后文所说的节点指的就是HTML中的标签
直接调用节点的名称就可以选择节点元素,然后调用string属性就可以得到节点内的文本信息了,这种选择的方式非常快,如果节点之间的层次清晰就非常适合用这种方式来解析。
from bs4 import BeautifulSoup
html = '''
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>BeautifulSoup的使用</title>
</head>
<body>
<h1>我的第一个标题。</h1>
<p>我的第一个段落。</p>
</body>
</html>
'''
soup = BeautifulSoup(html, 'lxml')
print(soup.title)
print(soup.title.string)
运行结果:
< title>BeautifulSoup的使用< /title>
BeautifulSoup的使用
使用对象.节点的形式就能输出整个节点,然后.string就能输出该节点的文本信息。当有多个节点时,只会选择到第一个匹配的节点,后面的其他相同节点都会忽略。
提取信息
上面演示了使用调用string来获取文本的值,那么该如何获取节点属性的值?如何获取节点名?
1.获取名称
可以利用name属性获取节点的名称。
print(soup.title.name)
运行结果:
title
2.获取属性
每个节点可能有多个属性,比如class、id等,选择这个节点之后,可以调用attrs获取所有属性。
from bs4 import BeautifulSoup
html = '''
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>BeautifulSoup的使用</title>
</head>
<body>
<h1 class="title" name="dromouse">我的第一个标题。</h1>
<p>我的第一个段落。</p>
</body>
</html>
'''
soup = BeautifulSoup(html, 'lxml')
print(soup.h1.attrs)
print(soup.h1.attrs['name'])
运行结果:
{‘class’: [‘title’], ‘name’: ‘dromouse’}
dromouse
我们可以看到,attrs的返回结果是字典形式,他把选择的所有属性和属性值组成一个字典,然后如果我们想要获取字典中的某一个属性值的话就可以通过中括号加属性名就可以。当某个属性有较多的属性值时,返回的属性值就是一个列表,单个属性值就是字符串。
3.获取内容
前面其实已经提到过,使用string获取节点元素的文本内容。
嵌套选择
当一个节点中包含另外一个节点时,我们就可以嵌套的通过.来选择节点。来看一个例子,还是上面的HTML文本。
print(soup.head.title.string)
运行结果:
BeautifulSoup的使用
我们既可以直接找到title这个节点,也可以嵌套的找到head节点里面的title节点。
关联选择
在做选择的时候,有时候不能做到一步就选到想要的节点元素,这时候往往需要先选中某一个节点元素,然后以他为基准再选择他的子节点、父节点、兄弟节点等等。
1.子节点和子孙节点
选取节点元素之后,如果想要直接获取他的直接子节点,可以调用contents属性,他会以一个列表的形式统一返回所有的东西,既包括文本也包括节点。需要注意的是,列表中的每个元素都是该节点的直接子节点。
print(soup.head.contents)
运行结果:
[’\n’, < meta charset=“utf-8”/>, ‘\n’, < title>BeautifulSoup的使用< /title>, ‘\n’]
同样,我们也可以调用children属性得到相应的结果。
print(soup.head.children)
for i, child in enumerate(soup.head.children):
print(i, child)
运行结果:
< list_iterator object at 0x0000025D5E3C9C88>
0
1 < meta charset=“utf-8”/>
2
3 < itle>BeautifulSoup的使用< /title>
4
还是上面的HTML文本,这里调用了children属性来选择,返回结果是生成器类型,接下来我们用for循环输出相应的内容。
如果想要输出所有子孙节点的话,可以调用descendants属性,用法和children一样。
2.父节点和祖先节点
如果想要获取某个节点元素的父节点,可以调用parent属性。
print(soup.title.parent)
运行结果:
< head>
< meta charset=“utf-8”/>
< title>BeautifulSoup的使用< /title>
< /head>
这里返回了title节点的父节点head节点的所有信息,当然这里输出的是直接父节点,如果想再向外寻找父节点的祖先节点的话可以调用parents属性。
print(type(soup.title.parents))
print(list(enumerate(soup.title.parents)))
运行结果:
<class 'generator'>
[(0, <head>
<meta charset="utf-8"/>
<title>BeautifulSoup的使用</title>
</head>), (1, <html>