上篇博客说了正则表达式,但是正则学起来比较费劲,写的时候也不好写,这次说下Beautiful Soup怎么用,这个模块是用来解析html的,它操作很简单,用起来比较方便,比正则学习起来简单多了。
这是第三方模块需要安装
1
2
3
|
pip install beautifulsoup4
pip install lxml
|
Beautiful Soup对象
Beautiful将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
Tag
标签,通过html的标签取到内容, 比如说a标签,如果有多个的话,取的是第一个。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
html = """
<html><head><title>BestTest</title></head>
<body>
<div>
<p class="content">最专业的软件测试培训
<a href="http://www.besttest.cn" class="link" id="link1"><!--首页--></a>,
<a href="http://www.besttest.cn/page/3.html" class="link" id="link2">BestTest性能测试</a> and
<a href="http://www.besttest.cn/page/47.html" class="link" id="link3">BestTest自动化测试</a>;
课程详情请点击上面的链接.</p>
<p class="content">.这是广告植入.</p>
<p class="title">BestTest is best</p>
</div>
</body>
</html>
"""
obj = BeautifulSoup(html,‘lxml‘)#后面是指定使用lxml解析,lxml解析速度比较快,容错高。
print(obj.prettify()) #格式化输出html
print(obj.title) #取title这个标签里面的内容
print(obj.p)
#tag有两个属性,一个是name,一个是attr
# name ,name这个属性就是标签的名字,比如说a标签就是打印的name就是a
# attrs,attrs这个是这个tag的属性,比如说上面a标签的属性有 class、href、id ,他是一个字典
#既然attrs是一个字典,那就能通过key来取值
print(obj.a.name) #a标签的name,也就是a
print(obj.a.attrs) #a标签的属性,也就是class href id这些,以及对应的值是什么
print(obj.a.attrs[‘href‘]) #取到a标签的href熟悉,也就是,http://www.besttest.cn
print(obj.a.attrs.get(‘href‘)) #因为attrs是一个字典,所以也可以用.get方法取值和上面的中括号取值一样
|
NavigableString
也就是内容,获取到一个标签里面的内容,文字,比如说上面title标签里面内容获取到,也就是besttest直接用tag.string即可。
1
2
3
|
print(obj.title.string) #BestTest
print(obj.a.string) #首页
print(type(obj.title.string)) # <class ‘bs4.element.NavigableString‘> NavigableString的类型
|
Beautifulobj
Beautifulobj对象就是代表整个html,比如说上面的obj就是Beautifulobj对象,通过它来操作各个标签
1
|
print(type(obj)) #Beautifulobj对象
|
Comment
Comment 对象是一个特殊类型的 NavigableString对象, 其实输出的内容仍然不包括注释符号,但是如果不好好处理它,可能会对我们的文本处理造成意想不到的麻烦。例如上面的一个a标签里面,首页是被注释了的。
1
2
3
|
print(obj.a.string) #首页,不包括 <!-- -->注释的
print(type(obj.a.string)) # <class ‘bs4.element.Comment‘> Comment类型
#这其实是注释的内容,咱们用string取出来的时候是不带注释符号的所以这里要注意一下
|
重点操作
上面的都是通过某个标签获取到的,如果想直接获取到某些标签,获取包含某些属性的就要用其他的方法了。
搜索标签
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
# find_all方法 find_all( name , attrs , recursive , text , **kwargs )
#find_all方法用来搜索当前所有的tag,判断是否符合过滤条件,如果符合的话,返回符合条件的列表
print(obj.find_all(‘p‘))#找到所有p标签
print(obj.find_all([‘a‘,‘p‘]))#找到所有a和p标签
#指定属性
print(obj.find_all(id=‘link1‘)) #找到id为link1的
print(obj.find_all(id=[‘link1‘,‘link2‘])) #找到id为link1和link2的
#因为class在python里面是关键字,如果要找class属性的,不能直接写class,要写class_
print(obj.find_all(class_=‘link‘)) #class为link的,
print(obj.find_all(class_=[‘link‘,‘content‘]))#class为link和conent的
print(obj.find_all(attrs={‘class‘:‘link‘,‘id‘:‘link1‘})) #多个属性也可以直接写成一个字典,把属性名写成key,值写成value
print(obj.find_all(‘p‘,class_=‘content‘)) #从p标签里面找到class为conent的
print(type(obj.find(class_=‘link‘)))#find方法和findall方法的区别是,findall会返回所有的标签,放到一个list里面
#find方法返回的是一个标签,找到多个的话,取第一个。其他用法都是一样的
|
css选择器
css选择器就是通过css获取元素的方式来获取html的标签,如果对css比较熟悉的人用起来就很方便了,在css选择器中 "." 代表选择的class,"#"代表选择的id。
1
2
3
4
5
6
7
8
9
10
11
|
print(‘p‘,obj.select(‘p‘)) #通过标签选择
print(obj.select(‘a‘)) #通过标签选择
print(obj.select(‘.content‘))#通过类名选择
print(obj.select(‘#link1‘))#通过id选择
print(obj.select(‘p .link‘))#组合查找,找p标签下面class为title的
print(obj.select(‘p #link1‘))#组合查找,找p标签下面id为link1的
print(obj.select(‘a#link1‘))#组合查找,找a标签里面id为link1的,和不加空格的区别是,在同级别找的
print(obj.select(‘p > a‘))#标签组合查找,找到p标签下面的a标签
print(obj.select(‘a[class=link]‘))#属性查找,找到a标签下面class为link的
print(obj.select(‘p a[href=http://www.besttest.cn/page/47.html]‘))#组合使用,从p标签下面的a标签找到href为http://www.besttest.cn/page/47.html的
|
节点内容
节点就是怎么获取html的各个节点,比如说和div同级的其他div,div下面的子标签等等。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
# contents tag 的 .contents 属性可以将tag的子节点以列表的方式输出
#children children和contents一样,也是获取子节点,只不过children不是列表,而是一个生成器
print(obj.div.contents) #获取到div下面的所有tag
print(obj.div.children) #这个是一个生成器,打印出来是一个生成器对象,想获取的话,就要循环了
for chil in obj.div.children:
print(chil)
# 通过contents以及children都是获取子节点,如果想要获取子孙节点可以通过descendants
# print(obj.descendants)同时这种获取的结果也是一个迭代器
#
# 父节点和祖先节点
#
# 通过obj.a.parent就可以获取父节点的信息
#
# 通过obj.a.parents可以获取祖先节点,这个方法返回的结果是一个列表,会分别将a标签的父节点的信息存放到列表中,以及父节点的父节点也放到列表中,并且最后还会讲整个文档放到列表中,所有列表的最后一个元素以及倒数第二个元素都是存的整个文档的信息
#
# 兄弟节点
#
# obj.a.next_siblings 获取后面的兄弟节点
# obj.a.previous_siblings 获取前面的兄弟节点
# obj.a.next_sibling 获取下一个兄弟标签
# obj.a.previous_sinbling 获取上一个兄弟标签
|
总结
主要说了怎么获取到html里面的各种标签、元素,修改和删除没有写,因为爬虫一般用不到修改,获取数据就够了。find_all()和css选择器都很常用,如果对css比较熟悉的话,建议使用css选择器。标签搜索和css选择器这里非常的常用。