Beautiful Soup之find()和find_all()的基本使用_soup.find_all-程序员宅基地

技术标签: 爬虫  python  

1.HTML文本

这里以官方文档提供的html代码来演示Beautiful Soup中find_all()和find()的基本使用。

<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 href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>

2.find_all()

find_all()方法的参数列表如下:

find_all( name , attrs , recursive , string , **kwargs )

find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件.这里有几个例子:

from bs4 import BeautifulSoup
import re


html = '''
<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 href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
'''


soup = BeautifulSoup(html, 'html.parser')

print(soup.find_all("title"))
# [<title>The Dormouse's story</title>]

print(soup.find_all("p", "title"))
# [<p class="title"><b>The Dormouse's story</b></p>]

print(soup.find_all("a"))
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

print(soup.find_all(id="link2"))
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]


print(soup.find(string=re.compile("sisters")))
# u'Once upon a time there were three little sisters; and their names were\n'

有几个方法很相似,还有几个方法是新的,参数中的 string 和 id 是什么含义? 为什么 find_all(“p”, “title”) 返回的是CSS Class为”title”的p标签? 我们来仔细看一下 find_all() 的参数

2.1 name参数

name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉.

简单的用法如下:

soup.find_all("title")
# [<title>The Dormouse's story</title>]

重申: 搜索 name 参数的值可以使任一类型的 过滤器 ,字符窜,正则表达式,列表,方法或是 True

2.2 keyword 参数

如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索,如果包含一个名字为 id 的参数,Beautiful Soup会搜索每个tag的”id”属性.

soup.find_all(id='link2')
# [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

如果传入 href 参数,Beautiful Soup会搜索每个tag的”href”属性:

soup.find_all(href=re.compile("elsie"))
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

搜索指定名字的属性时可以使用的参数值包括 字符串 , 正则表达式 , 列表, True .
下面的例子在文档树中查找所有包含 id 属性的tag,无论 id 的值是什么:

soup.find_all(id=True)
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

使用多个指定名字的参数可以同时过滤tag的多个属性:

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

有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:

data_soup = BeautifulSoup('<div data-foo="value">foo!</div>')
data_soup.find_all(data-foo="value")
# SyntaxError: keyword can't be an expression

但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag:

data_soup.find_all(attrs={
    "data-foo": "value"})
# [<div data-foo="value">foo!</div>]

2.3 按CSS搜索

按照CSS类名搜索tag的功能非常实用,但标识CSS类名的关键字 class 在Python中是保留字,使用 class 做参数会导致语法错误.从Beautiful Soup的4.1.1版本开始,可以通过 class_ 参数搜索有指定CSS类名的tag:

soup.find_all("a", class_="sister")
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

class_ 参数同样接受不同类型的 过滤器 ,字符串,正则表达式,方法或 True :

soup.find_all(class_=re.compile("itl"))
# [<p class="title"><b>The Dormouse's story</b></p>]

def has_six_characters(css_class):
    return css_class is not None and len(css_class) == 6

soup.find_all(class_=has_six_characters)
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

tag的 class 属性是 多值属性 .按照CSS类名搜索tag时,可以分别搜索tag中的每个CSS类名:

css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.find_all("p", class_="strikeout")
# [<p class="body strikeout"></p>]

css_soup.find_all("p", class_="body")
# [<p class="body strikeout"></p>]

搜索 class 属性时也可以通过CSS值完全匹配:

css_soup.find_all("p", class_="body strikeout")
# [<p class="body strikeout"></p>]

完全匹配 class 的值时,如果CSS类名的顺序与实际不符,将搜索不到结果:

soup.find_all("a", attrs={
    "class": "sister"})
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
#  <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

2.4 string 参数

通过 string 参数可以搜搜文档中的字符串内容.与 name 参数的可选值一样, string 参数接受 字符串 , 正则表达式 , 列表, True . 看例子:

soup.find_all(string="Elsie")
# [u'Elsie']

soup.find_all(string=["Tillie", "Elsie", "Lacie"])
# [u'Elsie', u'Lacie', u'Tillie']

soup.find_all(string=re.compile("Dormouse"))
[u"The Dormouse's story", u"The Dormouse's story"]

def is_the_only_string_within_a_tag(s):
    ""Return True if this string is the only child of its parent tag.""
    return (s == s.parent.string)

soup.find_all(string=is_the_only_string_within_a_tag)
# [u"The Dormouse's story", u"The Dormouse's story", u'Elsie', u'Lacie', u'Tillie', u'...']

虽然 string 参数用于搜索字符串,还可以与其它参数混合使用来过滤tag.Beautiful Soup会找到 .string 方法与 string 参数值相符的tag.下面代码用来搜索内容里面包含“Elsie”的标签:

soup.find_all("a", string="Elsie")
# [<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>]

2.5 limit 参数

find_all() 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果.

文档树中有3个tag符合搜索条件,但结果只返回了2个,因为我们限制了返回数量:

soup.find_all("a", limit=2)
# [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
#  <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

2.6 recursive 参数

调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False .

一段简单的文档:

<html>
 <head>
  <title>
   The Dormouse's story
  </title>
 </head>
...

是否使用 recursive 参数的搜索结果:

soup.html.find_all("title")
# [<title>The Dormouse's story</title>]

soup.html.find_all("title", recursive=False)
# []

这是文档片段:

<html>
        <head>
        <title>
        The Dormouse's story
    </title>
        </head>
        ...
标签在 标签下, 但并不是直接子节点, 标签才是直接子节点. 在允许查询所有后代节点时 Beautiful Soup 能够查找到 <title> 标签. 但是使用了 recursive=False 参数之后,只能查找直接子节点,这样就查不到 <title> 标签了.

Beautiful Soup 提供了多种DOM树搜索方法. 这些方法都使用了类似的参数定义. 比如这些方法: find_all(): name, attrs, text, limit. 但是只有 find_all() 和 find() 支持 recursive 参数.

2.7 像调用 find_all() 一样调用tag

find_all() 几乎是Beautiful Soup中最常用的搜索方法,所以我们定义了它的简写方法. BeautifulSoup 对象和 tag 对象可以被当作一个方法来使用,这个方法的执行结果与调用这个对象的 find_all() 方法相同,下面两行代码是等价的:

soup.find_all("a")
soup("a")

这两行代码也是等价的:

soup.title.find_all(string=True)
soup.title(string=True)

3.find()

find( name , attrs , recursive , string , **kwargs )

find_all() 方法将返回文档中符合条件的所有tag,尽管有时候我们只想得到一个结果.比如文档中只有一个标签,那么使用 find_all() 方法来查找标签就不太合适, 使用 find_all 方法并设置 limit=1 参数不如直接使用 find() 方法.下面两行代码是等价的:

soup.find_all('title', limit=1)
# [<title>The Dormouse's story</title>]

soup.find('title')
# <title>The Dormouse's story</title>

唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回结果.

find_all() 方法没有找到目标是返回空列表, find() 方法找不到目标时,返回 None .

print(soup.find("nosuchtag"))
# None

soup.head.title 是 tag的名字 方法的简写.这个简写的原理就是多次调用当前tag的 find() 方法:

soup.head.title
# <title>The Dormouse's story</title>

soup.find("head").find("title")
# <title>The Dormouse's story</title>

4.参考文档

https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/#find-all

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xuebiaojun/article/details/119654841

智能推荐

GD32F130 官方Demo编译问题 (续一)_gd32 编译 ret-程序员宅基地

文章浏览阅读1.6k次,点赞4次,收藏8次。根治 GD32 官方 Demo 编译出错问题简介原厂 Demo :GD32F1x0_Demo_Suites_V3.0.0调试IC:GD32F130C6T6调试工具:CMSIS - DAP编译环境:Keil 5.23解决问题(把工程拷到另一台电脑出现错误) 这次解决的问题是上篇留下的隐患,其实出错原因和原厂的 Demo 出错原因,一毛一样。 上篇解决错误是下载 CMSIS 4.3.0 文件,将 CMSIS 4.3.0 文件中的core_cmInst..._gd32 编译 ret

Java基础1语法准备_下列说法错误的是( ) a 32位的操作系统只能安装32位版的jdk,64位的操作系统只能安-程序员宅基地

文章浏览阅读497次。77集程序底层执行初识Java1.1计算机语言发展史以及未来计算机语言经历了三代:第一代是机器语言,第二代是汇编语言,第三代是高级语言。·第一代语言:机器语言(相当于人类的原始阶段)机器语言通常由数字串组成(最终被简化成01),对于人类来说,机器语言过于繁琐。使用机器语言,人类无法编出复杂的程序。如下为一段典型的机器码: 1. 0000,0000,00000001000..._下列说法错误的是( ) a 32位的操作系统只能安装32位版的jdk,64位的操作系统只能安

正则表达式系列之 —— 模式(Patterns)和修饰符(flags)-程序员宅基地

文章浏览阅读892次。本号是《现代 JavaScript 教程》[1]官方微信公众号模式和修饰符正则表达式是提供了一种在文本中进行搜索和替换的强大的方式的模式。在 JavaScript 中,我们可以通过 RegExp[2] 对象使用它们,也可以与字符串方法结合使用。正则表达式正则表达式(可叫作 "regexp",或 "reg")包扩 模式 和可选的 修饰符。有两种创建正则表达式对象的语法。较长..._pattern flags

Using Hadoop Encryption Zone_can't be moved into an encryption zone-程序员宅基地

文章浏览阅读1.2k次。BackgroundEncryption can be done at different layers in a traditional data management software/hardware stack. Choosing to encrypt at a given layer comes with different advantages and disadvantages.Ap_can't be moved into an encryption zone

Ubuntu18.04 下PCL的卸载与安装_虚拟机安装pcl库-程序员宅基地

Ubuntu18.04下PCL的卸载与安装。包括卸载问题PCL1.7,编译安装PCL1.8.1,并总结成功安装方法。

软件:AutoDWG DWG2PDF Converter 2023 Crack_crackdwg-程序员宅基地

文章浏览阅读1k次。AutoDWG DWG 到 PDF 转换器,比以往任何时候都更快!主要特征:批处理模式下的多文件转换;转换特定布局或图层;保留 TTF,True Type 字体,以便在 PDF 中搜索;打印、剪贴板复制和修改的权限支持;线宽可控,支持CTB文件导入;支持OLE实体;支持 PDF 自定义水印(仅限专业版)。支持命令行(仅限服务器)。支持AutoCAD 2023~R14。_crackdwg

随便推点

R语言在生态环境领域中的应用_r语言及其在生态学中的应用-程序员宅基地

文章浏览阅读282次。为此,本课程以鱼类、昆虫、水文、地形等多样化的生态环境数据为例,在R语言的基本操作介绍基础上,利用vegan、ade4、adespatial、stats、cluster、dendextend等多个程序包分析数据的分布、相关性、回归、聚类、排序、空间结构和群落多样性等内容,解读其结果及生态学意义,并将数据分析和作图展现集成于一体,引导读者能够系统运用R语言在生态环境领域进行多方位分析与探索。(单连接、完全连接、平均聚合聚类(UPGMA)、Ward最小方差聚类等)1、不同变量之间的相关性分析。_r语言及其在生态学中的应用

Siebel系统中配置LDAP认证_change siebel login page-程序员宅基地

文章浏览阅读1.2k次。1. 打开浏览器,输入Siebel系统访问地址,使用SADMIN用户登录2. 点击场地图>管理 - 服务器配置(S)>配置信息配置,查询LDAP Security Adapter3. 在配置信息参数页面,修改如下参数:Siebel Ldap配置参数1参数值2Application U_change siebel login page

【Android Audio 入门 五】--- AudioSW介绍_analog volume-程序员宅基地

文章浏览阅读3.5k次,点赞9次,收藏34次。【Android Audio 入门 五】--- AudioSW介绍五、AudioSW介绍5.1 Audio SW 的作用5.2 Android Audio SW Architecture5.3 Voice Audio SW Architecture5.4 Audio Mixer五、AudioSW介绍5.1 Audio SW 的作用简单来说, Audio SW 只要做好两件事:管理好整..._analog volume

妙算2G Ubuntu18 整机流程记录-程序员宅基地

文章浏览阅读132次。妙算整机重要流程梳理_妙算2g ubuntu18

AttributeError: 'numpy.ndarray' object has no attribute 'value_counts'-程序员宅基地

文章浏览阅读5.6w次,点赞16次,收藏34次。《python机器学习及实践》第二章第一个代码运行报错: AttributeError: 'numpy.ndarray' object has no attribute 'value_counts' # coding: utf-8# In[1]:# 导入pandas与numpy工具包。import pandas as pdimport numpy as np# 创建特征列表_attributeerror: 'numpy.ndarray' object has no attribute 'value_counts

jsonp访问成功返回数据时走error不走success的解决方法_jsonp callback 有返回值,但是进入error-程序员宅基地

文章浏览阅读5.8k次,点赞2次,收藏3次。原因:用jsonp跨域访问, 会注册callback, 生产一个随机的callback,正确的jsonp格式应该是 callback({"id" : "1","name" : "小王"}); 所以我们需要定义callback,前台指定回调函数jsonpCallback:"successCallback",后台指定返回的json格式:String result = "s_jsonp callback 有返回值,但是进入error

推荐文章

热门文章

相关标签