html_doc = """
<html><head><title>The Dormouse's storytitle>head>
<body>
<p class="title"><b>The Dormouse's storyb>p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsiea>,
<a href="http://example.com/lacie" class="sister" id="link2">Laciea> and
<a href="http://example.com/tillie" class="sister" id="link3">Tilliea>;
and they lived at the bottom of a well.p>
<p class="story">...p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc)
print(soup.prettify())
几个简单的浏览结构化的方法
soup.标签:找出第一个该类标签
print(soup.title)
# <title>The Dormouse's storytitle>
soup.标签.name:获取tag的name属性值
print(soup.title.name)
# title
soup.title.text 和 soup.title.string 的区别:
print(soup.title.text)
print(type(soup.title.text))
print(soup.title.string)
print(type(soup.title.string))
# The Dormouse's story
#
# The Dormouse's story
#
find_all() 和 find():前者返回符合条件的标签列表,后者返回一个bs4的tag对象
tag标签属性值的操作
获取属性值:获取文档中第一个p标签的所有class属性,返回list,转换的文档是XML格式,那么tag中不包含多值属性
print(soup.p.get('class'))
print(soup.p.attrs['class'])
print(soup.p['class'])
# ['title']
# ['title']
# ['title']
添加、修改属性、删除属性:
soup.b['class'] = 'content'
print(soup.b)
#The Dormouse's story
soup.b['class'] = 'text'
print(soup.b)
#The Dormouse's story
del soup.b['class']
print(soup.b)
#The Dormouse's story
子节点
.contents 属性可以将tag的直接子节点以列表的方式输出
print(soup.head.contents)
# [The Dormouse's story ]
.children 生成器,可以对tag的直接子节点进行循环
for j in soup.head.children:
print(j)
#The Dormouse's story
for i in soup.title.children:
print(i)
#The Dormouse's story
.descendants 属性可以对所有tag的子孙节点进行递归循环
for k in soup.head.descendants:
print(k)
# The Dormouse's story
# The Dormouse's story
.string 和 .strings \ stripped_strings:tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点;tag中包含多个字符串 [2] ,可以使用 .strings 来循环获取;输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容;
父节点
.parent:
<head>标签是<title>标签的父节点;
文档title的字符串也有父节点:<title>标签;
文档的顶层节点比如<html>的父节点是 BeautifulSoup 对象;
BeautifulSoup 对象的 .parent 是None;
.parents:通过元素的 .parents 属性可以递归得到元素的所有父辈节点,下面的例子使用了 .parents 方法遍历了\<\a>标签到根节点的所有节点.
for parent in soup.a.parents:
print(parent.name)
#p
#body
#html
#[document]
兄弟节点
.next_sibling 和 .previous_sibling:\<\b>标签有 .next_sibling 属性,但是没有 .previous_sibling 属性,因为\<\b>标签在同级节点中是第一个.同理,\<\c>标签有 .previous_sibling 属性,却没有 .next_sibling 属性:
sibling_soup = BeautifulSoup('text1 text2')
在html_doc文档中,第一个\<\a>标签的.next_sibling结果不是第二个标签,而是’,’
搜索文档树
soup.find_all('b') 找出所有的标签
– 正则表达式
soup.find_all(re.compile("^b")) 找出所有以b开头的标签,例子中和都能被找到
soup.find_all(re.comile("t")) 找出所有标签中包含't'的标签
– 列表
soup.find_all(["a", "b"]) 找到文档中所有<a>标签和标签
– True
soup.find_all(True) True:可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点
– 方法
以下方法找出包含 class 属性却不包含 id 属性的标签:
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
print(soup.find_all(has_class_but_no_id))
# [<p class="title content"><b>The Dormouse's storyb>p>, <p class="story">Once upon a # time there were three little sisters; and their names were
# <a class="sister" href="http://example.com/elsie" id="link1">Elsiea>,
# <a class="sister" href="http://example.com/lacie" id="link2">Laciea> and
# <a class="sister" href="http://example.com/tillie" id="link3">Tilliea>;
# and they lived at the bottom of a well.p>, <p class="story">...p>]
-- find_all( name , attrs , recursive , text , **kwargs )
soup.find_all("p", "title")
# [<p class="title"><b>The Dormouse's storyb>p>]
soup.find_all(href=re.compile("elsie"), id='link1')
# [<a class="sister" href="http://example.com/elsie" id="link1">threea>]
– 特殊属性的搜索
data_soup = BeautifulSoup('data-foo="value">foo!')
data_soup.find_all(data-foo="value")
# SyntaxError: keyword can't be an expression
data_soup.find_all(attrs={"data-foo": "value"})
# [foo!]
– 按CSS搜索
class 在Python中是保留字,使用 class 做参数会导致语法错误.从Beautiful Soup的4.1.1版本开始,可以通过 class_ 参数搜索有指定CSS类名的tag:
print(soup.find_all("a", class_="sister"))
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsiea>,
# <a class="sister" href="http://example.com/lacie" id="link2">Laciea>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tilliea>]
– text参数
class 在Python中是保留字,使用 class 做参数会导致语法错误.从Beautiful Soup的4.1.1版本开始,可以通过 class_ 参数搜索有指定CSS类名的tag:
print(soup.find_all(text="Elsie"))
# ['Elsie']
– limit参数
soup.find_all("a", limit=2)
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsiea>,
# <a class="sister" href="http://example.com/lacie" id="link2">Laciea>]
– recursive 参数
调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False :
soup.html.find_all("title")
# [The Dormouse's story ]
soup.html.find_all("title", recursive=False)
# []
Beautiful Soup中还有10个用于搜索的API.它们中的五个用的是与 find_all() 相同的搜索参数,另外5个与 find() 方法的搜索参数类似.区别仅是它们搜索文档的不同部分.记住: find_all() 和 find() 只搜索当前节点的所有子节点,孙子节点等. find_parents() 和 find_parent() 用来搜索当前节点的父辈节点,搜索方法与普通tag的搜索方法相同,搜索文档搜索文档包含的内容. 我们从一个文档中的一个叶子节点开始.
CSS选择器
Beautiful Soup支持大部分的CSS选择器,在 Tag 或 BeautifulSoup 对象的 .select() 方法中传入字符串参数,即可使用CSS选择器的语法找到tag:
– 通过tag标签逐层查找:
soup.select("html head title")
# [The Dormouse's story ]
– 找到某个tag标签下的直接子标签:
soup.select("head > title")
# [The Dormouse's story ]
soup.select("p > a")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsiea>,
# <a class="sister" href="http://example.com/lacie" id="link2">Laciea>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tilliea>]
soup.select("p > a:nth-of-type(2)")
# [<a class="sister" href="http://example.com/lacie" id="link2">Laciea>]
soup.select("p > #link1")
# [class="sister" href="http://example.com/elsie" id="link1">Elsie]
soup.select("body > a")
# []
– 找到兄弟节点标签:(所有兄弟和直系兄弟)
soup.select("#link1 ~ .sister")
# [<a class="sister" href="http://example.com/lacie" id="link2">Laciea>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tilliea>]
soup.select("#link1 + .sister")
# [<a class="sister" href="http://example.com/lacie" id="link2">Laciea>]
– 通过CSS的类名查找:
soup.select(".sister")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsiea>,
# <a class="sister" href="http://example.com/lacie" id="link2">Laciea>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tilliea>]
soup.select("[class~=sister]")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsiea>,
# <a class="sister" href="http://example.com/lacie" id="link2">Laciea>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tilliea>]
– 通过tag的id查找:
soup.select("#link1")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsiea>]
soup.select("a#link2")
# [<a class="sister" href="http://example.com/lacie" id="link2">Laciea>]
– 通过是否存在某个属性来查找:
soup.select('a[href]')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsiea>,
# <a class="sister" href="http://example.com/lacie" id="link2">Laciea>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tilliea>]
– 通过属性的值来查找:
soup.select('a[href="http://example.com/elsie"]')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsiea>]
soup.select('a[href^="http://example.com/"]')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsiea>,
# <a class="sister" href="http://example.com/lacie" id="link2">Laciea>,
# <a class="sister" href="http://example.com/tillie" id="link3">Tilliea>]
soup.select('a[href$="tillie"]')
# [<a class="sister" href="http://example.com/tillie" id="link3">Tilliea>]
soup.select('a[href*=".com/el"]')
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsiea>]