Python-Beautiful Soup库学习(基础)

本文介绍如何使用Python的BeautifulSoup库解析HTML文档,提取所需数据。通过实例展示了如何安装配置库,创建soup对象,以及如何通过多种方法导航和搜索HTML文档。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Beautiful Soup 是一个python库,从html和xml文件中提取数据。它通常为程序员节省数小时或数天的工作。

让我们开始吧

这是一个HTML文档,我将在整个文档中使用它作为示例。这是《爱丽丝梦游仙境》故事的一部分:

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 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>
"""

通过我们使用Beautiful Soup,输出了整齐的数据组织:

from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')

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

这里有简单的方法:
直接获取第一个遇到的元素。
如soup.title 提取dsad soup.title.name提取name,string提出内容

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

soup.title.name
# u'title'

soup.title.string
# u'The Dormouse's story'

soup.title.parent.name
# u'head'

soup.p
# <p class="title"><b>The Dormouse's story</b></p>

soup.p['class']
# u'title'

soup.a
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>

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>]

soup.find(id="link3")
# <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>

一个通常的任务就是取提取url在页面中的a标签:

for link in soup.find_all('a'):
    print(link.get('href'))
# http://example.com/elsie
# http://example.com/lacie
# http://example.com/tillie

另一个通常的任务就是从一个页面中提取所有的文本:

print(soup.get_text())
# 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.
#
# ...

安装Beautiful Soup

直接pip3 install bs4

安装一个解析器

Beautiful Soup即支持python内部安装的html解析器,也支持很多第三方解析器。
这里是几种解析器的优缺点:
在这里插入图片描述

创建soup

要解析文档,请将其传递到BeautifulSoup构造函数中。您可以传入一个字符串或一个打开的文件句柄:

from bs4 import BeautifulSoup

with open("index.html") as fp:
    soup = BeautifulSoup(fp)

soup = BeautifulSoup("<html>data</html>")

首先,将文档转换为Unicode,将HTML实体转换为Unicode字符:

BeautifulSoup("Sacr&eacute; bleu!")
<html><head></head><body>Sacré bleu!</body></html>

对象类型

Beautiful Soup将复杂的HTML文档转换为复杂的Python对象树。但是您只需要处理四种对象:Tag、NavigableString、BeautifulSoup和Comment。

标签类:

标签有很多属性和方法,我将在导航树和搜索树的过程中介绍其中的大部分。目前,标签最重要的特性是它的名称和属性。

soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
type(tag)
# <class 'bs4.element.Tag'>

Name

tag.name
# u'b'

如果您更改了标签的名称,更改将反映在Beautiful Soup生成的任何HTML标记中:

tag.name = "blockquote"
tag
# <blockquote class="boldest">Extremely bold</blockquote>

Attributes
一个标签可能有很多的属性。标签有一个属性" id “,其值是"boldest”。您可以通过将标签视为字典来访问标签的属性:

tag['id']
# u'boldest'

你可以直接获取字典通过 .attrs:

tag.attrs
# {u'id': 'boldest'}

您可以添加、删除和修改标记的属性。同样,这是通过把标签当作字典来实现的:

tag['id'] = 'verybold'
tag['another-attribute'] = 1
tag
# <b another-attribute="1" id="verybold"></b>

del tag['id']
del tag['another-attribute']
tag
# <b></b>

tag['id']
# KeyError: 'id'
print(tag.get('id'))
# None

Multi-valued attributes
多值属性:常见的就是class
HTML 4定义了一些可以有多个值的属性。HTML 5删除了其中的一些,但定义了更多。最常见的多值属性是class(也就是说,一个标签可以有多个CSS类)。其他包括rel、rev、accept-charset、header和accesskey。Beautiful Soup将多值属性的值表示为列表:

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

# 这是一个多值属性。
css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.p['class']
# ["body", "strikeout"]

如果一个属性看起来有不止一个值,但它不是HTML标准的任何版本定义的多值属性,Beautiful Soup将不考虑这个属性:
这是一个单值属性:

id_soup = BeautifulSoup('<p id="my id"></p>')
id_soup.p['id']
# 'my id'

当您将标签转换回字符串时,将合并多个属性值:

rel_soup = BeautifulSoup('<p>Back to the <a rel="index">homepage</a></p>')
rel_soup.a['rel']
# ['index']
rel_soup.a['rel'] = ['index', 'contents']
print(rel_soup.p)
# <p>Back to the <a rel="index contents">homepage</a></p>

HTML 标签的 rel 属性
提示:尽管浏览器不会以任何方式使用该属性,不过搜索引擎可以利用该属性获得更多有关链接的信息。

您可以使用’ get_attribute_list来获得一个总是列表、字符串的值,无论它是否是多值属性。

get_attribute_list(' id ') 
# [" my id "]

如果将文档解析为XML,则不存在多值属性 。

NavigableString
字符串对应于标记中的一小段文本。Beautiful Soup使用NavigableString类来包含这些文本:

tag.string
# u'Extremely bold'
type(tag.string)
# <class 'bs4.element.NavigableString'>

NavigableString就像Python Unicode字符串一样,只是它还支持在导航树和搜索树时描述的一些特性。您可以使用Unicode()将NavigableString转换为Unicode字符串:

unicode_string = unicode(tag.string)
unicode_string
# u'Extremely bold'
type(unicode_string)
# <type 'unicode'>

您不能就地编辑字符串,但是可以使用**replace_with()**将一个字符串替换为另一个字符串:

tag.string.replace_with("No longer bold")
tag
# <blockquote>No longer bold</blockquote>

NavigableString支持导航树和搜索树时描述的大部分特性,但不是所有特性。特别是,由于字符串不能包含任何内容(就像标记可能包含字符串或其他标记一样),所以字符串不支持.contents或.string属性或find()方法。

如果希望在Beautiful Soup之外使用NavigableString,应该对其调用unicode()将其转换为普通的Python unicode字符串。如果您不这样做,您的字符串将携带对整个Beautiful Soup解析树的引用,即使您已经使用了Beautiful Soup。这是对内存的巨大浪费。

BeautifulSoup
BeautifulSoup对象本身作为一个整体表示文档。在大多数情况下,可以将其视为标记对象。这意味着它支持导航树和搜索树中描述的大多数方法。
因为BeautifulSoup对象不对应于实际的HTML或XML标记,所以它没有名称和属性。但是有时候,查看它的.name是很有用的,所以它被赋予了一个特殊的.name“[document]”:

soup.name
# u'[document]'

Comments and other special strings
Tag、NavigableString和BeautifulSoup几乎涵盖了HTML或XML文件中看到的所有内容,但是还有一些剩余部分。你唯一需要担心的可能就是Comments:

markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
soup = BeautifulSoup(markup)
comment = soup.b.string
type(comment)
# <class 'bs4.element.Comment'>

注释。

Comment对象只是NavigableString的一种特殊类型:

comment
# u'Hey, buddy. Want to buy a used parser'

但当它作为HTML文档的一部分出现时,会显示一条特殊格式的注释:

print(soup.b.prettify())
# <b>
#  <!--Hey, buddy. Want to buy a used parser?-->
# </b>

Beautiful Soup为XML文档中可能出现的任何其他东西定义了类:CData、ProcessingInstruction、Declaration和Doctype。与Comment一样,这些类也是NavigableString的子类,它们向字符串添加了一些额外的内容。下面是一个用CDATA块替换注释的例子:

from bs4 import CData
cdata = CData("A CDATA block")
comment.replace_with(cdata)

print(soup.b.prettify())
# <b>
#  <![CDATA[A CDATA block]]>
# </b>

导航树

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 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>
"""

from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc, 'html.parser')

标签可以包含字符串和其他标签。这些元素是标记的子元素。Beautiful Soup为导航和遍历标记的子元素提供了许多不同的属性。
注意,Beautiful Soup字符串不支持这些属性,因为字符串不能有子字符串。

通过tag名称来导航。

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

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

.contents 和 .children

一个标签的子属性,可以通过.contents来调用:

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

head_tag.contents
[<title>The Dormouse's story</title>]

title_tag = head_tag.contents[0]
title_tag
# <title>The Dormouse's story</title>
title_tag.contents
# [u'The Dormouse's story']

BeatifulSoup 对象自己也有子属性,在这个例子中,它的子属性是标签。

len(soup.contents)
# 1
soup.contents[0].name
# u'html'

一个字符串没有子属性:

text = title_tag.contents[0]
text.contents
# AttributeError: 'NavigableString' object has no attribute 'contents'

您可以使用.children生成器迭代标记的子元素,而不是将它们作为列表获取:

for child in title_tag.children:
    print(child)
# The Dormouse's story

.descendants (子孙后代)

.contents和.children属性只考虑标记的直接子元素。例如,标签只有一个直接子标签—标签:

head_tag.contents
# [<title>The Dormouse's story</title>]

遍历子孙后代:

for child in head_tag.descendants:
    print(child)
# <title>The Dormouse's story</title>
# The Dormouse's story

儿子很少,子孙很多:

len(list(soup.children))
# 1
len(list(soup.descendants))
# 25

.string
如果一个tag只有一个子属性,并且它是NavigableString,那么可以通过.string 来获取

title_tag.string
# u'The Dormouse's story'

如果一个标签的唯一子标签是另一个标签,并且这个标签有一个.string,那么父标签被认为和它的子标签有相同的.string:

head_tag.contents
# [<title>The Dormouse's story</title>]
head_tag.string
# u'The Dormouse's story'

如果有多个属性,那么.string 返回None

.strings and stripped_strings

如果标签中有不止一个东西,你仍然可以只看字符串。使用.strings生成器:
读取多个子属性的string

for string in soup.strings:
    print(repr(string))
# u"The Dormouse's story"
# u'\n\n'
# u"The Dormouse's story"
# u'\n\n'
# u'Once upon a time there were three little sisters; and their names were\n'
# u'Elsie'
# u',\n'
# u'Lacie'
# u' and\n'
# u'Tillie'
# u';\nand they lived at the bottom of a well.'
# u'\n\n'
# u'...'
# u'\n'

发现有很多空格,换行那么选择:.stripped_strings

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值