BeautifulSoup是用来从HTML or XML中提取数据的Python lib,处理高效,并且支持多种解析器。利用它不用编写正则表达式,就能方便抓取网页信息。参考
解析器
注意:同一篇文档被不同的解析器可能解析成不同结构的树型文档。参考
一、安装
pip install beautifulsoup4
二、四大对象
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:Tag,NavigableString,BeautifulSoup,Comment.
Tag标签
主要有两个属性:name和attributes,has_attr()方法
name属性
name就是获得标签自己的名字(感觉没啥用)。
attributes属性
可以通过attrs来获得该标签的所有属性。返回字典。
soup.p.attrs
可以通过['']的形式来获得、修改、删除每一个属性的值
print(p['class']) #或者p.get('class')
p['class'] = 'hello'
del p['class']
注:对于html文档,有些属性是有多个属性值的,通过属性来取属性值时,返回的是list形式的属性值,例如:class等。但是对于XML文档,返回的是一整个字符串。
#html
css_soup=BeautifulSoup('<p class="body strikeout"/>')
css_soup.p['class']
# ["body", "strikeout"]#xml
xml_soup=BeautifulSoup('<p class="body strikeout"/>','xml')
xml_soup.p['class']#"body strikeout"
has_attr()方法
返回True或者False
NavigableString标签
字符串常被包含在tag内.Beautiful Soup用NavigableString类来包装tag中的字符串:通过string来获得。
p.string
tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用replace_with()方法:
p.string.replace_with("hello world!")
BeautifulSoup对象
表示的是一个文档的全部内容.大部分时候,可以把它当作Tag对象,但是,BeautifulSoup对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性。
printsoup.name
# [document]
printsoup.attrs
#{} 空字典
comment注释对象
Comment对象是一个特殊类型的NavigableString对象:
markup="<p><!--hello--><\p>"
soup=BeautifulSoup(markup)print(soup.p.string)
#hello
print(type(soup.p.string))
#<'class bs4.element.Comment'>
我们知道p标签的内容是注释,但是如果我们利用 .string 来输出它的内容,我们发现它已经把注释符号去掉了,所以这可能会给我们带来不必要的麻烦。因此在使用前可以先判断:
ift ype(soup.a.string)==bs4.element.Comment:
print soup.a.string
Beautiful Soup中定义的其它类型都可能会出现在XML的文档中:CData, ProcessingInstruction,Declaration,Doctype.与Comment对象类似,这些类都是NavigableString的子类。
三、节点的定位
1.直接标签名--找到第一个
通过直接“.标签名”的方式来获取。
注意:1)这种方式只能获取到第一个标签噢。2)可以多次调用噢。也就是.标签名.标签名...3)不一定非要一级一级的标签来找哦,可以直接找孙子节点哦
soup.body.p.a
soup.body.a #直接定位到孙子噢
2.通过CSS选择器定位
通过css选择器的select()来定位,返回list噢
1)通过标签名找所有节点
soup.select("p") #返回标签名为p的所有节点的list
2)通过类名查找所有节点,类名前面加“.”噢
soup.select(".sister") #返回class属性值为sister的所有节点的list
3)通过id查找所有节点,id前面加“#”噢
soup.select("#hello") #返回id为hello的所有节点的list
4)通过属性查找所有节点
soup.select('a[href="http://example.com/elsie"]') #返回属性href为。。。的所有a的list
注意:属性用[]括起来,且与标签中间没有空格,注意与5的区别
5)混合方式查找所有节点
混合查找中,空格表示的是“递进”的意思哦,即和写 class 文件时,标签名与类名、id名进行的组合原理是一样的
soup.select("p #.sister") #返回p的子节点中,class属性为sister的所有节点的list
3.find_all( name , attrs , recursive , text , **kwargs )--寻找符合条件的Tag节点噢
搜索当前tag的所有tag子节点,注意,只查找Tag节点噢。参考:http://cuiqingcai.com/1319.html#crayon-594dac2620deb589249952
还有类似的find开头的函数,其实都是在之前的属性上,添加了一些过滤条件而已。
4.NavigableString节点的获得
1)获得单个--属性.string
通过父节点的".string"属性,就可以获得NavigableString节点噢
doc = "<html><title>hello</title></html>"
soup.title.string #hello
soup.html.string #hello
注意:
a. 如果一个标签里面只有NavigableString节点了,那么 .string 就会返回标签里面的内容。如果标签里面只有唯一的一个标签了,那么 .string 也会返回最里面的内容。
b. 如果一个标签里有多个子标签,那么.string就会返回None。
2)获得多个--strings属性
通过.strings属性可以获得某个节点下所有的NavigableString节点(也就是字符串啦,名字高大上一点喽)。但是它会包含很多的空白符噢。返回的是generator噢
3)获得多个--stripped_string属性(去除空白符)
就是比strings返回的结果少了空白符啦,其他没啥区别哟
5.枚举所有子节点
1)枚举直接子节点
a.属性contents,返回列表
b.属性children,返回生成器(generator),可以通过for来获得。
soup.body.contents
for item in soup.body.children:
print(item)
注意:string没有这两个属性,强行获得会报错
2)枚举所有子节点
a.属性descendants----以深度搜索的方式返回generator
6.获得父节点
1)直接父节点
属性parent
soup.p.parent #body
2)所有父节点
属性parents,返回generator
7.获得兄弟节点
1)相邻兄弟节点
属性.next_sibling 和 .previous_sibling
<a>tim</a>
<a>lucy</a>
soup.a.next_sibling #'\n'
<a>tim</a><a>lucy</a>
soup.a.next_sibling #'<a>lucy</a>'
注意:NavigableString节点和其他标签节点也是兄弟关系噢
2)所有相邻节点
.next_siblings 和 .previous_siblings属性
8.解析过程中的相邻节点
1)直接相邻节点
HTML解析器会按照节点出现,将字符串转换成一些列的事件。Beautiful Soup提供了重现解析器初始化过程的方法。属性:.next_element 和 .previous_element
<p>hello<a>world</a></p>
soup.p.next_element #hello
soup.p.next_element.next_element #<a>world</a>
2)所有相邻节点
属性.next_elements 和 .previous_elements
四、其他
prettify():格式化输出html和xml,还能自动补全。
网友评论