创建 BeautifulSoup 对象

从字符串创建:

  1. soup = bs4.BeautifulSoup(字符串,解析器)

从 文件 创建:

  1. soup = bs4.BeautifulSoup(open('index.html', 'r'), 'html.parser')

  1. with open('index.html', 'r') as file:
  2. soup = bs4.BeautifulSoup(file)

常用解析器及其优缺点

解析器 使用方法 优势 劣势
Python 标准库 BeautifulSoup(markup, "html.parser") Python 的内置标准库;执行速度适中;容错能力强 Python 2.7.3 or 3.2.2)前 的版本中容错能力差
lxml HTML 解析器 BeautifulSoup(markup, "lxml") 速度快;容错能力强 需要安装C语言库
lxml XML 解析器 BeautifulSoup(markup, ["lxml", "xml"])
BeautifulSoup(markup, "xml")
速度快;唯一支持XML的解析器 需要安装 C 语言库
html5lib BeautifulSoup(markup, "html5lib") 最好的容错性;不依赖外部扩展;生成 HTML5 格式的文档 速度慢

bs4 中的四种对象

bs4 中有四种对象:TagNavigableStringBeautifulSoupComment

  • Tag:通俗来讲就是 HTML 中的标签

  • NavigableString:标签中间的字符内容,其子标签为 None。该对象也可以当做特殊的 Tag 对象

  • BeautifulSoup:用 BeautifulSoup 函数处理 HTML / XML 代码后生成的对象,使用时可以当做特殊的 Tag 对象,其 .name 属性为 [document].attrs 属性为 None

  • CommentTag.string 会将注释内容也显示出来,且去掉了注释符号,所以区分 标签内容 和 注释内容 只能通过判断它们的类型,注释内容的类型为 Comment

Tag 的方法和属性

基本属性:

  • Tag.tag:该 Tag 的子标签

  • Tag.name:标签名

  • Tag.attrs:以字典形式存储的标签属性(多值属性会用列表处理)
    可以用三种方法获取某个标签属性:

    • Tag['class']
    • Tag.get('class')
    • Tag.attrs['class']

前两种是 Tag 对象自带用法,最后一种是字典的用法。

标签的属性可以被添加、删除或修改,操作方法与字典是一样的。如:

  • Tag['class'] = 'red'
  • Tag.get('class') = 'red'
  • Tag.attrs['class'] = 'red'
  • Tag.string:标签中间的文本内容,该文本内容是 NavigableString 对象
    • 如果一个标签里面没有标签了,那么 .string 就会返回标签里面的内容。
    • 如果标签里面只有唯一的一个标签,那么 .string 也会返回最里面的内容。
    • 如果 Tag 中包含多个子节点,无法确定 .string 方法应该调用哪个子节点的内容, 输出结果则为 None

遍历文档树

节点内容

Tag.strings:如果一个标签中包含多个子节点,可以使用 .strings 生成器获取所有内容

  1. for string in Tag.strings:
  2. print(repr(string))

Tag.stripped_strings.strings 产生的内容可能包含很多 空格和空行,使用该方法可以去除多余空白

  1. for string in Tag.stripped_strings:
  2. print(repr(string))

子节点

  • Tag.contents:以 列表形式 返回当前 Tag 的 直接子节点
  • Tag.children:以 list 生成器对象的形式返回当前 Tag 的 直接子节点
  • Tag.descendants:返回一个包含当前 Tag 所有子孙节点的对象(遍历方式为深度优先)

父节点

  • Tag.parent:输出 直接父节点
  • Tag.parents:输出 包含所有父节点的可迭代对象,迭代时会 从里到外 输出所有父节点

兄弟节点(同级节点)

  • Tag.next_sibling:输出下一个兄弟节点
  • Tag.previous_sibling:输出上一个兄弟节点
  • Tag.next_siblings:返回 包含所有后面的兄弟节点 的可迭代对象,迭代时要先用 repr 转化
  • Tag.previous_siblings:返回 包含所有前面的兄弟节点 的可迭代对象,迭代时要先用 repr 转化

前后节点(不分级别)

  • Tag.next_element:输出下一个节点
  • Tag.previous_element:输出上一个节点
  • Tag.next_elements:返回 包含所有后面的节点 的可迭代对象,迭代时要先用 repr 转化
  • Tag.previous_elements:返回 包含所有前面的节点 的可迭代对象,迭代时要先用 repr 转化

搜索文档树

主要使用 find()find_all()select() 这三个方法。

select() 方法以 css 选择器为参数,返回匹配到的所有元素。

find_all() 返回一个可迭代对象,对象中的每个元素都是一个 Tag 对象。
find() 的用法与 find_all() 相同,只不过 find() 只返回搜索到的第一个元素。

下面以 find_all() 为例,介绍 find_all()find() 的参数。

name 参数(查找标签)

传字符串(查找指定标签):

  1. soup.find_all('a')

传正则表达式(查找符合条件的标签):

  1. for tag in soup.find_all(re.compile("^b")):
  2. print(tag.name) # output: body b

:::info Beautiful Soup 会通过正则表达式的 match() 来匹配内容 :::

传列表(查找多个指定的标签名):

  1. soup.find_all(["a", "p"]) # 查找所有 a 和 p 标签

TrueTrue 可以匹配任何值):

  1. soup.find_all(True)

传函数名(自定义查找标准):

  1. def has_class_but_no_id(tag): # 参数是要遍历的每个节点
  2. return tag.has_attr('class') and not tag.has_attr('id')
  3. soup.find_all(has_class_but_no_id) # 函数名后不加括号

:::warning 注:函数只接受一个元素作为参数。 :::

keyword 参数(查找标签属性)

可以将属性名当做关键字参数来搜索,如:

  1. soup.find_all(href="http://www.baidu.com/")

会返回文档中 href 属性的值是 "http://www.baidu.com/" 的标签,构成列表。

可以将属性值设为 True,会返回拥有该属性的所有标签,例如:

  1. soup.find_all(href=True)

会返回文档中拥有 href 属性的所有标签,因为 True 匹配任何值。

使用多个 keyword 参数可以同时过滤 Tag 的多个属性:

  1. soup.find_all(href=re.compile("elsie"), id='link1')
  2. # 匹配结果:[<a class="sister" href="http://example.com/elsie" id="link1">three</a>]

:::warning 注:因为 class 是 Python 中的关键字,所以以 class 作为 keyword 参数时,要写成 class_ :::

text 参数(查找标签内容)

通过 text 参数可以搜索文档中的字符串内容。

name 参数的可选值一样, text 参数接受 字符串正则表达式列表**True**

其他参数

limit 参数:限制查找结果个数。如:

  1. soup.find_all("a", limit=2)

recursive 参数:默认为 True,此时查找当前 Tag 的所有子节点。若设为 False,则只查找直接子节点。
例如:

  1. soup.html.find_all("title", recursive=False)

其他方法

  • Tag.prettify():格式化输出内容。

  • Tag.get_attribute_list('class'):以 列表 形式获取指定属性的值。如果它是多值属性,那么列表中存在多个字符串,否则列表中就只有一个字符串。