资讯专栏INFORMATION COLUMN

BeautifulSoup 使用指北 - 0x03_搜索解析树

xfee / 3503人阅读

摘要:参考概述中定义了许多搜索解析树的方法,但这些方法都非常类似,它们大多采用与相同的参数和,但是仅有和支持参数。本节会以作为示例过滤器过滤器用于在解析树中筛选目标节点,被用作搜索方法的实参。如果函数返回,则保留该节点,否则抛弃该节点。

GitHub@orca-j35,所有笔记均托管于 python_notes 仓库。
欢迎任何形式的转载,但请务必注明出处。
参考: https://www.crummy.com/softwa...
概述

BeautifulSoup 中定义了许多搜索解析树的方法,但这些方法都非常类似,它们大多采用与 find_all() 相同的参数: nameattrsstringlimit 和 **kwargs,但是仅有 find()find_all() 支持 recursive 参数。

这里着重介绍 find()find_all(),其它"搜索方法"也这两个类似。

Three sisters

本节会以 "three sister" 作为示例:

html_doc = """


    The Dormouse"s story


    

The Dormouse"s story

Once upon a time there were three little sisters; and their names were Elsie, Lacie and Tillie; and they lived at the bottom of a well.

...

""" from pprint import pprint from bs4 import BeautifulSoup import re soup = BeautifulSoup(html_doc, "html.parser")
过滤器

过滤器(filter)用于在解析树中筛选目标节点,被用作"搜索方法"的实参。

字符串

字符串可用作过滤器,BeautifulSoup 可利用字符串来筛选节点,并保留符合条件节点:

使用字符串筛选 tag 时,会保留与字符串同名 tag 节点,且总会过滤掉 HTML 文本节点

使用字符串筛选 HTML 属性时,会保留属性值与字符串相同的 tag 节点,且总会过滤掉 HTML 文本节点

使用字符串筛选 HTML 文本时,会保留与字符串相同的文本节点

str 字符串类似,我们还可将 bytes 对象用作过滤器,区别在于 BeautifulSoup 会假定编码模式为 UTF-8。

示例:

soup = BeautifulSoup(html_doc, "html.parser")
# 查找名为b的tag节点
print([f"{type(i)}::{i.name}" for i in soup.find_all("b")])
print([f"{type(i)}::{i.name}" for i in soup.find_all(b"b")])
# 查找id值为link1的tag节点
print([f"{type(i)}::{i.name}" for i in soup.find_all(id="link1")])
# 查找文本值为Elsie的文本节点
print([f"{type(i)}::{i.name}" for i in soup.find_all(text="Elsie")])

输出:

["::b"]
["::b"]
["::a"]
["::None"]
正则表达式

正则表达式对象可用作过滤器,BeautifulSoup 会利用正则表达式对象的 search() 方法来筛选节点,并保留符合条件节点:

使用正则表达式对象筛选 tag 时,会利用正则表达式的 search() 方法来筛选 tag 节点的名称,并保留符合条件的 tag 节点。因为文本节点的 .name 属性值为 None,因此总会过滤掉 HTML 文本节点

使用正则表达式对象筛选 HTML 属性时,会利用正则表达式的 search() 方法来筛选指定属性的值,并保留符合条件的 tag 节点。因为文本节点不包含任何 HTML 属性,因此总会过滤掉 HTML 文本节点

使用正则表达式对象筛选 HTML 文本时,会利用正则表达式的 search() 方法来筛选文本节点,并保留符合条件的文本节点。

示例:

import re

soup = BeautifulSoup(html_doc, "html.parser")
# 查找名称中包含字母b的节点
print([f"{type(i)}::{i.name}" for i in soup.find_all(re.compile(r"b"))])
# 查找class值以t开头的tag
print(
    [f"{type(i)}::{i.name}" for i in soup.find_all(class_=re.compile(r"^t"))])
# 查找文本值以E开头的文本节点
print([f"{type(i)}::{i.name}" for i in soup.find_all(text=re.compile(r"^E"))])

输出:

["::body", "::b"]
["::p"]
["::None"]
列表

列表 list 可用作过滤器,列表中的项可以是:

字符串

正则表达式对象

可调用对象,详见 函数

BeautifulSoup 会利用列表中的项来筛选节点,并保留符合条件节点:

使用列表筛选 tag 时,若 tag 名与列表中的某一项匹配,则会保留该 tag 节点,且总会过滤掉 HTML 文本节点

使用列表筛选 HTML 属性时,若属性值与列表中的某一项匹配,则会保留该 tag 节点,且总会过滤掉 HTML 文本节点

使用列表筛选 HTML 文本时,若文本与列表中的某一项匹配,则会保留该文本节点

示例

import re
def func(tag):
    return tag.get("id") == "link1"

soup = BeautifulSoup(html_doc, "html.parser")
# 查找与列表匹配的tag节点
tag = soup.find_all(["title", re.compile("b$"), func])
pprint([f"{type(i)}::{i.name}" for i in tag])
pprint(
    [f"{type(i)}::{i.name}" for i in soup.find_all(text=["Elsie", "Tillie"])])

输出:

["::title",
 "::b",
 "::a"]
["::None",
 "::None"]
True

布尔值 True 可用作过滤器:

使用 True 筛选 tag 时,会保留所有 tag 节点,且过滤掉所有 HTML 文本节点

使用 True 筛选 HTML 属性时,会保留所有具备该属性的 tag 节点,且过滤掉所有 HTML 文本节点

使用 True 筛选 HTML 文本时,会保留所有文本节点

soup = BeautifulSoup(html_doc, "html.parser")
pprint([f"{type(i)}::{i.name}" for i in soup.find_all(True)])
pprint([f"{type(i)}::{i.name}" for i in soup.find_all(id=True)])
pprint([f"{type(i)}::{i.name}" for i in soup.find_all(text=True)])

输出:

["::html",
 "::head",
 "::title",
 "::body",
 "::p",
 "::b",
 "::p",
 "::a",
 "::a",
 "::a",
 "::p"]
["::a",
 "::a",
 "::a"]
["::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None",
 "::None"]
函数

过滤器可以是某个函数(或任何可调用对象):

以 tag 节点为筛选对象时,过滤器函数需以 tag 节点作为参数,如果函数返回 True,则保留该 tag 节点,否则抛弃该节点。

示例 - 筛选出含 class 属性,但不含 id 属性的 tag 节点:

def has_class_but_no_id(tag):
    # Here’s a function that returns True if a tag defines the “class” attribute but doesn’t define the “id” attribute
    return tag.has_attr("class") and not tag.has_attr("id")


soup = BeautifulSoup(html_doc, "html.parser")
tag = soup.find_all(has_class_but_no_id)
pprint([f"{type(i)}::{i.name}" for i in tag])

输出:

["::p",
 "::p",
 "::p"]

针对 HTML 属性进行筛选时,过滤函数需以属性值作为参数,而非整个 tag 节点。如果 tag 节点包含目标属性,则会向过滤函数传递 None,否则传递实际值。如果函数返回 True,则保留该 tag 节点,否则抛弃该节点。

def not_lacie(href):
    # Here’s a function that finds all a tags whose href attribute does not match a regular expression
    return href and not re.compile("lacie").search(href)


soup = BeautifulSoup(html_doc, "html.parser")
tag = soup.find_all(href=not_lacie)
for i in tag:
    print(f"{type(i)}::{i.name}::{i}")

输出:

::a::Elsie
::a::Tillie

针对 HTML 文本进行筛选时,过滤需以文本值作为参数,而非整个 tag 节点。如果函数返回 True,则保留该 tag 节点,否则抛弃该节点。

def func(text):
    return text == "Lacie"

soup = BeautifulSoup(html_doc, "html.parser")
print([f"{type(i)}::{i}" for i in soup.find_all(text=func)])

输出:

["::Lacie"]

过滤函数可以被设计的非常复杂,比如:

html_doc = """
The Dormouse"s story

The Dormouse"s story

Once upon a time there were three little sisters; and their names were Elsie, Lacie and Tillie; and they lived at the bottom of a well.

...

""" def surrounded_by_strings(tag): # returns True if a tag is surrounded by string objects return (isinstance(tag.next_element, NavigableString) and isinstance(tag.previous_element, NavigableString)) soup = BeautifulSoup(html_doc, "html.parser") tag = soup.find_all(surrounded_by_strings) pprint([f"{type(i)}::{i.name}" for i in tag]) # 注意空白符对输出结果的影响

输出:

["::body",
 "::p",
 "::a",
 "::a",
 "::a",
 "::p"]
find_all()

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/45280.html

相关文章

  • BeautifulSoup 使用指北 - 0x02_操作解析

    摘要:,所有笔记均托管于仓库。中包含的字符串或等节点被视作该的或节点。为了便于在或节点中进行导航,提供了许多与此相关的方法。节点名可使用节点名来选取目标节点,此时会返回子孙节点中的第一个同名节点。 GitHub@orca-j35,所有笔记均托管于 python_notes 仓库。欢迎任何形式的转载,但请务必注明出处。 在解析树中导航 参考: Navigating the tree 在学习与...

    高胜山 评论0 收藏0
  • BeautifulSoup 使用指北 - 0x01_概览

    摘要:,所有笔记均托管于仓库。是一个用来从或文件中提取数据的库。如果对速度有严格要求,应直接使用库来解析。对而言,解析器的速度比或更快。可以通过安装库来显著提升检测编码方案的速度。 GitHub@orca-j35,所有笔记均托管于 python_notes 仓库。欢迎任何形式的转载,但请务必注明出处。 概述 ⚠官方文档中混杂了 Py2 和 Py3 的术语和代码,本笔记针对 Py3 梳理了文档...

    jay_tian 评论0 收藏0
  • python爬虫——爬取小说 | 探索白子画和花千骨的爱恨情仇

    摘要:先打开花千骨小说的目录页,是这样的。网页结构分析首先,目录页左上角有几个可以提高你此次爬虫成功后成就感的字眼暂不提供花千骨全集下载。打开盘查看花千骨文件。 知识就像碎布,记得缝一缝,你才能华丽丽地亮相。 1.Beautiful Soup 1.Beautifulsoup 简介 此次实战从网上爬取小说,需要使用到Beautiful Soup。Beautiful Soup为python的...

    newsning 评论0 收藏0
  • Python爬虫之自制英汉字典

    摘要:笔者看到了,觉得还蛮有意思的,因此,决定自己也写一个玩玩首先我们的爬虫要能将英语单词翻译成中文,因此,我们就需要一个网站帮助我们做这件事情。   最近在微信公众号中看到有人用Python做了一个爬虫,可以将输入的英语单词翻译成中文,或者把中文词语翻译成英语单词。笔者看到了,觉得还蛮有意思的,因此,决定自己也写一个玩玩~~  首先我们的爬虫要能将英语单词翻译成中文,因此,我们就需要一个网...

    graf 评论0 收藏0
  • python爬虫之BeautifulSoup

    摘要:爬虫之简介提供一些简单的式的函数用来处理导航搜索修改分析树等功能。自动将输入文档转换为编码,输出文档转换为编码。已成为和一样出色的解释器,为用户灵活地提供不同的解析策略或强劲的速度。 python爬虫之BeautifulSoup 简介 **Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取...

    Rocko 评论0 收藏0

发表评论

0条评论

xfee

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<