Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.
本文为Beautiful Soup属性方法总结,更多例子请查阅官方文档
$ pip install beautifulsoup4
#debian或Ubuntu下可以
$ apt-get install Python-bs4
加载BeautifulSoup库
>>> from bs4 import BeautifulSoup
>>> a = Beautiful('') #创建BeautifulSoup对象
Beautiful Soup会自动选择一个解析器来解析文档,也可以通过参数来制定使用哪种解析器
第一次使用BeautifulSoup构造函数如果没有指定解析器,会出现提示,无需担心,后续调用就不会出现该提示
BeartifulSoup第一个参数为被解析的文档字符串或文件句柄,第二个参数来表示选择什么解析器,
如果第二个参数为空,则根据当前系统安装的库自动选择解析器,lxml,html5lib,python标准库
>>> BeautifulSoup(markup, "html.parser")
>>> BeautifulSoup(markup, "lxml")
>>> BeautifulSoup(markup, "lxml-xml") #使用lxml库解析xml文档
>>> BeautifulSoup(markup, "xml")
>>> BeautifulSoup(markup, "html5lib")
推荐使用lxml作为解析器,速度快,容错能力强,效率高
安装lxml
$ pip install lxml
安装html5lib
$ pip install html5lib
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag , NavigableString , BeautifulSoup , Comment .
BeautifulSoup对象表示一个文档的全部内容,大部分时候,可以把它当作 Tag 对象,它支持遍历文档树和搜索文档树中描述的大部分的方法.
它的name属性返回字符串'[document]'
BeautifulSoup没有标签属性,所以无法使用字典索引或attrs属性
字符串通常被包含在tag对象内,而这些字符串使用NavigableSoup类用来包装
标签与标签之间的字符串同样会被作为文档的节点,包装为NavigableSoup对象
NabigableSoup对象支持遍历和搜索的大部分属性方法 但是不能包含其他对象,所以不支持.contents,.strings或find()等针对子节点的方法
在tag中包含的NavigableSoup对象可以通过replace_with()方法来替换字符串
可以通过unicode()函数将NaviableSoup对象转会成Unicode字符串,通常在BeautifulSoup之外使用时进行转换
Comment对象是一个特殊类型的NavigableString对象,包含文档中的注释
Beautiful Soup还定义了一些其他类型CData , ProcessingInstruction , Declaration , Doctype用于处理XML文档,这些类也都是NavigableString类的子类
tag.name 获取标签名字,可以更改该属性
tag[attr_name] 获取该标签的attr_name属性,可以更改和添加attr_name属性的值
tag.attrs 获取该标签的所有属性,返回一个字典
如果属性为多值属性,则返回一个列表,但是如果该属性在html中没有被定义为多值属性,则返回字符串,
对于xml,tag不包含多值属性,返回的都是字符串
子节点
tag.tag_name 使用tag的名称tag_name属性来获取相应第一个匹配的后代节点tag对象
>>> a = bs(' body元素后代节点第一个p
body子节点第一个
')
>>> a.body.p
body元素后代节点第一个p
tag.contents 将tag的子节点以列表的方式输出
>>> a = bs(' sdfd
')
>>> a.body.contents
['',sdfd
, ]
注意空白符同样会作为子节点输出
tag.children 生成器属性,可以对tag的子节点进行循环
tag.descendants 生成器属性,可以对所有tag的后代节点进行递归循环
tag.string 如果tag只有一个NavigableString类型子节点,则string属性可以得到子节点
如果tag仅有一个子节点,那么输出和该子节点的输出一样
如果tag包含多个子节点,tag就不确定.string方法由谁来调用
tag.strings 如果tag中包含多个字符串,可以使用.strings来循环获取
tag.stripped_strings 输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容
段首和段末的空白会被删除
父节点
tag.parent 获取tag元素的父节点
tag.parents 生成器属性,递归获取所有父辈节点,最后返回None
兄弟节点
tag.next_sibling 查询下一个同级节点,同级最后一个节点没有该属性
tag.previous_sibling 查询上一个同级节点,同级第一个节点没有该属性
tag.netx_siblings 生成器属性可以对当前节点的兄弟节点迭代输出
tag.previous_siblings
实际兄弟节点也许并不是下一个标签元素,而是文本节点NavigableString节点或者注释Comment对象
HTML解析器会根据标签的打开关闭和字符串来解析文档
The Dormouse's story
The Dormouse's story
针对上面的字段HTML解析器会打开html标签,打开head标签,打开title标签,添加字符串,关闭title标签,关闭head标签,打开p标签...
tag.next_element 根据解析过程返回下一个被解析的对象(字符串或tag),结果可能于.next_sibling相同,但通常不一样
next_element属性会先返回后代节点,然后返回兄弟节点
>>> a = BeautifulSoup('xixi
sdfd
')
>>> a.div.next_sibling
sdfd
>>> a.div.next_element
xixi
tag.previous_element 根据解析过程返回上一个被解析对象
tag.next_elements 生成器属性
tag.previous_elements
搜索过滤器,用于搜索方法的参数来过滤搜索结果
字符串
正则表达式 如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的match()来匹配内容.
列表 将与列表中任一元素匹配的内容返回
True 可以匹配任何值
方法 定义一个方法,方法只接受一个元素参数,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False
>>> def has_class(tag):
... return tag.has_attr('class')
...
>>> a = bs('xixi
sdfd
')
>>> a.find(has_class)
xixi
tag.find_all(name, attrs, recursive, text ,limit, **kwargs)
搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件
name 参数可以查找所有名字为name的tag,字符串对象会被自动忽略掉
text 参数用于搜索文档中字符串内容,可以和其他参数混合使用来过滤
soup.find_all("a", text="Elsie")
# [Elsie]
recursive 参数设为False,表示只搜索tag的直接子节点
**kwargs 关键字参数
如果指定的名字参数不是搜索内置的参数名,搜索时会把该参数作为name参数的属性,参数的值可以是任何类型的过滤器
对于标签的class属性,可以使用class_参数,因为class为Python的保留字
对于多值属性可以使用字符串过滤器来全值完全匹配
>>> css_soup.find_all("p", class_="body strikeout")
attrs 参数定义一个字典参数作为name参数的属性搜索,可以搜索包含特殊属性的tag
limit 参数会限制返回的数量,否则如果文档很大的话搜索会很慢
tag.find (name, attrs, recursive, text , **kwargs)
等同于.find_all(...,limit=1),不过带有limit=1参数的find_all()方法返回的值是一个包含一个元素的列表,而find()方法返回单个tag对象
当find_all()方法找不到目标时返回空列表,find()方法找不到目标,返回None
tag.find_parents(...)
tag.find_parent(...)
用来搜索当前节点的父辈节点,这两个方法实际是对.parents属性的迭代
tag.find_next_siblings(...)
tag.find_next_sibling(...)
通过.next_siblings属性对当前tag之后的所有兄弟节点进行迭代
tag.find_previous_siblings(...)
tag.find_previous_sibling(...)
通过.previous_siblings属性对当前tag之前的所有兄弟节点进行迭代
tag.find_all_next(...)
tag.find_next(...)
通过.next_elements属性对当前tag之后的tag和字符串进行迭代
tag.find_all_previous(...)
tag.find_previous(...)
通过.previous_elements属性对当前节点前面的tag和字符串进行迭代
CSS选择器
.select()
传入字符串参数可以使用CSS选择器的语法找到对应tag
>>> soup.select("body a")
>>> soup.select("head > title")
>>> soup.select(".sister")
>>> soup.select("#link1")
>>> soup.select('a[href$="tillie"]')
如果仅仅因为想要查找文档中的标签而将整片文档进行解析,实在是浪费内存和时间
可以使用SoupStrainer类定义某段内容,这样搜索文档时,就不必先解析全部文档了
创建一个SoupStrainer对象并作为parse_only参数传递给BeautifulSoup()构造方法
SoupStrainer类接受与搜索方法相同的参数
SoupStrainer(name, attrs,recursive,text,**kwargs)
>>> from bs4 import SoupStrainer
>>> only_a_tags = SoupStrainer("a")
>>> only_tags_with_id_link2 = SoupStrainer(id="link2")
>>> def is_short_string(string):
... return len(string) < 10
...
>>> only_short_strings = SoupStrainer(text=is_short_string)
>>> BeautifulSoup(html_doc, "html.parser", parse_only=only_a_tags)
tag.name 更改name属性可以重命名tag
tag[attr_name] 添加删除更改tag的属性值
tag.string 给string属性赋值相当于替代使用当前内容替代原来内容
beautifulsoup.new_string(string, class_name)
BeautifulSoup对象方法,创建一个NavigableString对象
可传入NavigableString的任何子类作为第二个参数,构建相应对象,比如Comment
beautifulsoup.new_tag(name, **kwargs)
BeautifulSoup对象方法,创建一个Tag对象,第一个参数为标签的名字,其他关键字参数为标签属性
tag.append() 向tag中添加内容
tag.insert() 与列表的insert方法类似,在指定位置插入内容
>>> markup = 'I linked to example.com'
>>> soup = BeautifulSoup(markup)
>>>soup.a.tag.insert(1, "but did not endorse ")
# I linked to but did not endorse example.com
tag.insert_before() 在当前tag或文本节点前插入元素
tag.insert_after() 在当前tag或文本节点后插入元素
>>> soup = BeautifulSoup("stop")
>>> tag = soup.new_tag("i")
>>> tag.string = "Don't"
>>> soup.b.string.insert_before(tag)
>>> soup.b
Don'tstop
tag.clear() 移除当前tag中的内容
tag.extract() 将当前tag移除文档树,并作为方法结果返回,返回的依然是Tag对象
tag.decompose() 将当前节点移除文档树并完全销毁
tag.replace_with() 移除文档树中的某段内容,并用新tag或文本节点替代它
tag.wrap() 对指定的tag元素进行包装,并返回包装后的结果
>>> soup = BeautifulSoup("I wish I was bold.
")
>>> soup.p.string.wrap(soup.new_tag("b"))
I wish I was bold.
tag.unwrap() 移除tag的当前tag.name标签,该方法常被用来进行标记的解包
>>> bs = BeautifulSoup('I linked to example.com')
>>> bs.i.unwrap()
>>> bs
I linked to example.com
tag.prettify() 将文档树格式化后以Unicode编码输出,每个XML/HTML标签都独占一行
>>> a = Beautiful('\nxixi
sdfd
\n')
>>> a.prettify()
'\n \n \n \n xixi\n
\n \n \n sdfd\n
\n \n'
如果只想得到结果字符串,不重视格式,那么可以对一个 BeautifulSoup 对象或 Tag 对象使用Python的 unicode() 或 str() 函数
>>> a
xixi
sdfd
tag .get_text() 获取到tag中包含的所有文本内容包括子孙tag中的内容,并将结果作为Unicode字符串返回
>>> a = bs('\nxixi
\nsdfd
')
>>> a.get_text()
'\nxixi\nsdfd'
>>> a.get_text('|') #使用参数来指定文本之间的分隔符
'\nxixi|\nsdfd'
>>> a.get_text('|',strip=True) #使用strip参数去除文本内容中的前后空白符
'xixi|sdfd'
.orginal_encoding属性记录了自动识别的编码
BeautifulSoup构造方法时可传入from_encoding参数指定编码方式
soup = BeautifulSoup(markup, from_encoding="iso-8859-8")
#####未完待续####