(4-详细方法 | 用什么方法对文档树进行搜索?)
-
BeautifulSoup
的文档搜索方法有很多,官方文档中重点介绍了两个方法:
find() 和 find_all()
- 下文中的实例,依旧是官网的例子:
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a rel="nofollow" href="http://example.com/elsie" class="sister" >Elsie</a>,
<a rel="nofollow" href="http://example.com/lacie" class="sister" >Lacie</a> and
<a rel="nofollow" href="http://example.com/tillie" class="sister" >Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')
1 过滤器
- 在介绍文档搜索方法之前,先了解下各种过滤器。
1.1 字符串
- 即在搜索方法中传如一个字符串参数;
-
BeautifulSoup
会查找与字符串完全匹配的内容; - 如查找
b
标签:
print(soup.find_all('b'))
- 输出为:
[<b>The Dormouse's story</b>]
1.2 正则表达式
- 传入正则表达式作为参数;
-
Beautiful Soup
会通过正则表达式的match()
来匹配内容; - 如找出所有以
b
开头的标签:
import re
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
- 输出为:
body
b
1.3 列表
- 传入列表参数;
-
Beautiful Soup
会将与列表中任一元素匹配的内容返回; - 如找到文档中所有
a
标签和b
标签:
print(soup.find_all(["a", "b"]))
- 输出为:
[<b>The Dormouse's story</b>,
<a rel="nofollow" class="sister" href="http://example.com/elsie" >Elsie</a>,
<a rel="nofollow" class="sister" href="http://example.com/lacie" >Lacie</a>,
<a rel="nofollow" class="sister" href="http://example.com/tillie" >Tillie</a>]
1.4 True
-
True
可以匹配任何值; - 如查找到所有的
tag
:
for tag in soup.find_all(True):
print(tag.name)
- 输出为:
html
head
title
body
p
b
p
a
a
a
p
1.5 可以自定义方法
- 如果没有合适过滤器,那么还可以定义一个方法;
- 方法只接受一个元素参数;
- 如果这个方法返回
True
表示当前元素匹配并且被找到,如果不是则反回False
;
2 find_all()
- 搜索当前
tag
的所有tag
子节点,并判断是否符合过滤器的条件。 - 比如:
print(soup.find_all("title"))
- 输出为:
[<title>The Dormouse's story</title>]
2.1 参数原型
find_all( name , attrs , recursive , string , **kwargs )
2.2 name参数
- 查找所有名字为
name
的tag
; - 如:
print(soup.find_all("title"))
,输出为:[<title>The Dormouse's story</title>]
。
2.3 keyword 参数
- 如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字
tag
的属性来搜索; - 如:
print(soup.find_all(id='link2'))
,输出为:
[<a rel="nofollow" class="sister" href="http://example.com/lacie" >Lacie</a>]
- 按照
CSS
搜索,可以通过class_
参数搜索有指定CSS
类名的tag
; - 如:
print(soup.find_all("a", class_="sister"))
,输出为:
[<a rel="nofollow" class="sister" href="http://example.com/lacie" >Lacie</a>]
[<a rel="nofollow" class="sister" href="http://example.com/elsie" >Elsie</a>, <a rel="nofollow" class="sister" href="http://example.com/lacie" >Lacie</a>, <a rel="nofollow" class="sister" href="http://example.com/tillie" >Tillie</a>]
2.4 string 参数
- 通过
string
参数可以搜文档中的字符串内容.
与name
参数的可选值一样; - 如:
print(soup.find_all(string="Elsie"))
,输出为:['Elsie']
;
2.5 limit 参数
- 可以使用
limit
参数限制搜索返回结果的数量,避免返回结果很大速度很慢; - 如:
soup.find_all("a", limit=2)
,输出为:
[<a rel="nofollow" class="sister" href="http://example.com/elsie" >Elsie</a>,
<a rel="nofollow" class="sister" href="http://example.com/lacie" >Lacie</a>]
2.6 recursive 参数
- 只搜索
tag
的直接子节点,可以使用参数recursive=False
; - 如:
<html>
<head>
<title>
The Dormouse's story
</title>
</head>
...
- 不使用
recursive
参数:
print(soup.html.find_all("title"))
- 输出为:
[<title>The Dormouse's story</title>]
- 使用
recursive
参数:
print(soup.html.find_all("title", recursive=False))
- 输出为:
[]
3 find()
-
find_all()
方法的返回结果是值包含一个元素的列表,而find()
方法直接返回结果; -
find_all()
方法没有找到目标是返回空列表,find()
方法找不到目标时,返回None
。 - 如:
print(soup.find("nosuchtag"))
,输出为:None
。 - 参数原型:
find( name , attrs , recursive , string , **kwargs )
4 find_parents()和find_parent()
- 参数原型:
find_parents( name , attrs , recursive , string , **kwargs )
find_parent( name , attrs , recursive , string , **kwargs )
-
find_parents() 和 find_parent()
用来搜索当前节点的父辈节点; -
find_all() 和 find()
只搜索当前节点的所有子节点,孙子节点等; - 如:
a_string = soup.find(string="Lacie")
print(a_string)
print(a_string.find_parents("a"))
- 输出为:
Lacie
[<a rel="nofollow" class="sister" href="http://example.com/lacie" >Lacie</a>]
5 find_next_siblings() 和 find_next_sibling()
- 参数原型:
find_next_siblings( name , attrs , recursive , string , **kwargs )
find_next_sibling( name , attrs , recursive , string , **kwargs )
- 这2个方法通过
.next_siblings
属性对当tag
的所有后面解析的兄弟tag
节点进行迭代; -
find_next_siblings()
方法返回所有符合条件的后面的兄弟节点; -
find_next_sibling()
只返回符合条件的后面的第一个tag
节点; - 如:
first_link = soup.a
print(first_link)
print(first_link.find_next_siblings("a"))
first_story_paragraph = soup.find("p", "story")
print(first_story_paragraph.find_next_sibling("p"))
- 输出为:
<a rel="nofollow" class="sister" href="http://example.com/elsie" >Elsie</a>
[<a rel="nofollow" class="sister" href="http://example.com/lacie" >Lacie</a>, <a rel="nofollow" class="sister" href="http://example.com/tillie" >Tillie</a>]
<p class="story">...</p>
6 find_previous_siblings() 和 find_previous_sibling()
- 参数原型:
find_previous_siblings( name , attrs , recursive , string , **kwargs )
find_previous_sibling( name , attrs , recursive , string , **kwargs )
- 这2个方法通过
.previous_siblings
属性对当前tag
的前面解析的兄弟tag
节点进行迭代; -
find_previous_siblings()
方法返回所有符合条件的前面的兄弟节点; -
find_previous_sibling()
方法返回第一个符合条件的前面的兄弟节点。
7 find_all_next() 和 find_next()
- 参数原型:
find_all_next( name , attrs , recursive , string , **kwargs )
find_next( name , attrs , recursive , string , **kwargs )
- 这2个方法通过
.next_elements
属性对当前tag的之后的tag
和字符串进行迭代; -
find_all_next()
方法返回所有符合条件的节点; -
find_next()
方法返回第一个符合条件的节点。
8 find_all_previous() 和 find_previous()
- 参数原型:
find_all_previous( name , attrs , recursive , string , **kwargs )
find_previous( name , attrs , recursive , string , **kwargs )
- 这2个方法通过
.previous_elements
属性对当前节点前面的tag
和字符串进行迭代; -
find_all_previous()
方法返回所有符合条件的节点; -
find_previous()
方法返回第一个符合条件的节点。
9 本文涉及的源码
# -*- coding:utf-8 -*-
# 作者:NoamaNelson
# 日期:2023/2/17
# 文件名称:bs04.py
# 作用:beautifulsoup的应用
# 博客:https://blog.csdn.net/NoamaNelson
from bs4 import BeautifulSoup
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a rel="nofollow" href="http://example.com/elsie" class="sister" >Elsie</a>,
<a rel="nofollow" href="http://example.com/lacie" class="sister" >Lacie</a> and
<a rel="nofollow" href="http://example.com/tillie" class="sister" >Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
soup = BeautifulSoup(html_doc, 'html.parser')
# ====== 过滤器 ======
# 字符串
print(soup.find_all('b'))
# 正则表达式
import re
for tag in soup.find_all(re.compile("^b")):
print(tag.name)
# 列表
print(soup.find_all(["a", "b"]))
# True
for tag in soup.find_all(True):
print(tag.name)
# ====== find_all() ======
print(soup.find_all("title"))
print(soup.find_all(id='link2'))
print(soup.find_all("a", class_="sister"))
print(soup.find_all(string="Elsie"))
print(soup.find_all("a", limit=2))
print(soup.html.find_all("title", recursive=False))
# ====== find() ======
print(soup.find("nosuchtag"))
a_string = soup.find(string="Lacie")
print(a_string)
print(a_string.find_parents("a"))
first_link = soup.a
print(first_link)
print(first_link.find_next_siblings("a"))
first_story_paragraph = soup.find("p", "story")
print(first_story_paragraph.find_next_sibling("p"))