Python - 爬虫-网页解析数据-库bs4(Beautiful Soup 4)

Python爬虫库bs4的使用详解

Beautiful Soup‌ 简称 BS4(其中 4 表示版本号)是一个 Python 第三方库,是一个用于解析HTML和XML文档的Python库,主要用于从网页中提取数据。它能够将HTML或XML文档转换为一个树形结构,使得用户可以通过编程方式方便地访问、提取和操作网页中的数据‌。

beautiful soup库(bs4)
图:BS4官网LOGO图

官网地址:Beautiful Soup 4.4.0 文档 — Beautiful Soup 4.2.0 中文 文档

一、下载安装

Beautiful Soup不是Python的内置库,因此在使用前需要安装。可以通过以下命令安装

pip install beautifulsoup4

阿里国内源安装:

pip install beautifulsoup4 -i http://mirrors.aliyun.com/pypi/simple --trusted-host mirrors.aliyun.com

此外,还可以安装其他解析器如html5lib

pip install html5lib

二、主要功能和使用方法

  1. 解析器‌:Beautiful Soup支持多种解析器,包括Python标准库中的HTML解析器以及第三方库如lxmlhtml5lib。推荐使用lxml,因为它速度快且功能强大‌。
  2. 创建对象‌:通过BeautifulSoup类可以创建对象,该对象代表整个HTML文档树。可以通过各种方法(如find()find_all())来访问文档的各个部分‌。
  3. 查找和提取数据‌:可以使用find()方法查找文档中符合条件的第一个元素,使用find_all()方法查找所有符合条件的元素。这些方法支持通过标签名、属性等多种方式定位元素‌。
  4. 处理文本内容‌:BeautifulSoup提供了处理文本内容的方法,如获取标签中的文本内容(NavigableString)和剥离标签但保留文本的字符串(stripped_strings)‌。

示例代码

以下是一个简单的示例,展示如何使用BeautifulSoup解析HTML文档并提取信息:

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 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_doc, 'lxml')
title_tag = soup.find('b')  # 查找第一个<b>标签
print(title_tag.text)  # 输出: 'The Dormouse's story'

bs4还支持一些第三方解析器:

解析器使用方法优势劣势
Python标准库BeautifulSoup(html,’html.parser’)Python内置标准库;执行速度快在python2.7.3和3.2.2之前的版本中文档容错能力差
lxml html解析器(需要额外导入)BeautifulSoup(html,’lxml’)速度快;容错能力强需要安装C语言库
lxml XML解析器(需要额外导入)BeautifulSoup(html,[‘lxml’,’xml’])或BeautifulSoup(html,’xml’)唯一支持解析xml需要安装C语言库
htm5libBeautifulSoup(html,’htm5llib’)以浏览器方式解析,最好的容错性,生成html5速度慢

三、bs4使用

1、bs4对html文件的处理

BeautifulSoup4将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:

(1)Tag

(2)NavigableString

(3)BeautifulSoup

(4)Comment

(1)Tag : Tag通俗点讲就是HTML中的一个个标签

from bs4 import BeautifulSoup
soup = BeautifulSoup(resp.text, 'html.parser')
 
# 获取title标签的所有内容
print(soup.title)
 
# 获取head标签的所有内容
print(soup.head)
 
# 获取第一个a标签的所有内容
print(soup.a)
 
# 类型
print(type(soup.a))

我们可以利用 soup 加标签名轻松地获取这些标签的内容,这些对象的类型是 bs4.element.Tag

但是注意,它查找的是在所有内容中的第一个符合要求的标签。

对于 Tag,它有两个重要的属性,是 name 和 attrs:

# [document] 
#bs 对象本身比较特殊,它的 name 即为 [document]
print(soup.name)
 
# head 
#对于其他内部标签,输出的值便为标签本身的名称
print(soup.head.name) 
 
# 在这里,我们把 a 标签的所有属性打印输出了出来,得到的类型是一个字典。
print(soup.a.attrs)
 
#还可以利用get方法,传入属性的名称,二者是等价的
print(soup.a['class']) # soup.a.get('class')
 
# 可以对这些属性和内容等等进行修改
soup.a['class'] = "newClass"
print(soup.a) 
 
# 还可以对这个属性进行删除
del soup.a['class'] 
print(soup.a)

(2)NavigableString:获取标签内部的文字用 .string 即可

print(soup.title.string) # 也可以soup.title.text
 
print(type(soup.title.string))

(3)BeautifulSoup:表示一个文档的内容

大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性

print(type(soup.name))
 
print(soup.name)
 
print(soup.attrs)

(4)Comment:是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号

print(soup.a)  # 此时不能出现空格和换行符,a标签如下:
# <a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!--新闻--></a>
 
print(soup.a.string) # 新闻
 
print(type(soup.a.string)) # <class 'bs4.element.Comment'>

2、遍历文档树

(1).contents:获取Tag的所有子节点,返回一个list

# tag的.content 属性可以将tag的子节点以列表的方式输出
print(soup.head.contents)
 
# 用列表索引来获取它的某一个元素
print(soup.head.contents[1])

(2).children:获取Tag的所有子节点,返回一个生成器

for child in soup.body.children:
    print(child)

3、搜索文档树

1、find_all(name, attrs, recursive, text, **kwargs)

(1)name参数:

字符串过滤:会查找与字符串完全匹配的内容

a_list = soup.find_all("a")
print(a_list)

正则表达式过滤:如果传入的是正则表达式,那么BeautifulSoup4会通过search()来匹配内容

t_list = soup.find_all(re.compile("a"))
for item in t_list:
    print(item)

列表: 如果传入一个列表,BeautifulSoup4将会与列表中的任一元素匹配到的节点返回

t_list = soup.find_all(["meta","link"])
for item in t_list:
    print(item)

方法: 传入一个方法,根据方法来匹配

def name_is_exists(tag):
    return tag.has_attr("name")
 
t_list = soup.find_all(name_is_exists)
for item in t_list:
    print(item)

(2)kwargs参数:

# 查询id=head的Tag
t_list = soup.find_all(id="head")
print(t_list)
 
# 查询href属性包含ss1.bdstatic.com的Tag
t_list = soup.find_all(href=re.compile("http://news.baidu.com"))
print(t_list)
 
# 查询所有包含class的Tag(注意:class在Python中属于关键字,所以加_以示区别)
t_list = soup.find_all(class_=True)
for item in t_list:
    print(item)

(3)attrs参数:

并不是所有的属性都可以使用上面这种方式进行搜索,比如HTML的data-*属性,我们可以使用attrs参数,定义一个字典来搜索包含特殊属性的tag:

t_list = soup.find_all(attrs={"data-foo":"value"})
for item in t_list:
    print(item)

(4)text参数:

通过text参数可以搜索文档中的字符串内容,与name参数的可选值一样。text参数接受 字符串,正则表达式,列表

t_list = soup.find_all(attrs={"data-foo": "value"})
for item in t_list:
    print(item)
 
t_list = soup.find_all(text="hao123")
for item in t_list:
    print(item)
 
t_list = soup.find_all(text=["hao123", "地图", "贴吧"])
for item in t_list:
    print(item)
 
t_list = soup.find_all(text=re.compile("\d"))
for item in t_list:
    print(item)

(5)limit参数:

传入一个limit参数来限制返回的数量,如下列放回数量为2

t_list = soup.find_all("a",limit=2)
for item in t_list:
    print(item)

2、find()

返回符合条件的第一个Tag;即当我们要取一个值的时候就可以用这个方法

t = soup.div.div
 
# 等价于

t = soup.find("div").find("div")

4、CSS选择器

(1)通过标签名查找

print(soup.select('title'))
 
print(soup.select('a'))

(2)通过类名查找

print(soup.select('.mnav'))

(3)通过id查找

print(soup.select('#u1'))

(4)组合查找

print(soup.select('div .bri'))

(5)属性查找

print(soup.select('a[class="bri"]'))
print(soup.select('a[href="http://tieba.baidu.com"]'))

(6)获取内容

t_list = soup.select("title")
print(soup.select('title')[0].get_text())

示例代码:

from bs4 import BeautifulSoup

'''
bs4
安装:pip install beautifulsoup4
官网:https://beautifulsoup.readthedocs.io/zh-cn/v4.4.0/
'''

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

# 创建一个BeautifulSoup对象
soup = BeautifulSoup(html_doc)

print(f"soup.prettify:{soup.prettify}")
print(f"soup.title:{soup.title}") # soup.title:<title>The Dormouse's story</title>
print(f"type(soup.title):{type(soup.title)}") # type(soup.title):<class 'bs4.element.Tag'>
print(f"dir(soup.title):{dir(soup.title)}") # dir(soup.title):['EMPTY_ELEMENT_EVENT', 'END_ELEMENT_EVENT', 'MAIN_CONTENT_STRING_TYPES', 'START_ELEMENT_EVENT', 'STRING_ELEMENT_EVENT', '_TreeTraversalEvent', '__annotations__', '__bool__', '__call__', '__class__', '__contains__', '__copy__', '__deepcopy__', '__delattr__', '__delitem__', '__dict__', '__dir__', '__doc__', '__eq__', '__firstlineno__', '__format__', '__ge__', '__getattr__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__static_attributes__', '__str__', '__subclasshook__', '__unicode__', '__weakref__', '_all_strings', '_event_stream', '_find_all', '_find_one', '_format_tag', '_indent_string', '_insert', '_is_xml', '_lastRecursiveChild', '_last_descendant', '_namespaces', '_self_and', '_should_pretty_print', 'append', 'attribute_value_list_class', 'attrs', 'can_be_empty_element', 'cdata_list_attributes', 'childGenerator', 'children', 'clear', 'contents', 'copy_self', 'css', 'decode', 'decode_contents', 'decompose', 'decomposed', 'default', 'descendants', 'encode', 'encode_contents', 'extend', 'extract', 'fetchAllPrevious', 'fetchNextSiblings', 'fetchParents', 'fetchPreviousSiblings', 'find', 'findAll', 'findAllNext', 'findAllPrevious', 'findChild', 'findChildren', 'findNext', 'findNextSibling', 'findNextSiblings', 'findParent', 'findParents', 'findPrevious', 'findPreviousSibling', 'findPreviousSiblings', 'find_all', 'find_all_next', 'find_all_previous', 'find_next', 'find_next_sibling', 'find_next_siblings', 'find_parent', 'find_parents', 'find_previous', 'find_previous_sibling', 'find_previous_siblings', 'format_string', 'formatter_for_name', 'get', 'getText', 'get_attribute_list', 'get_text', 'has_attr', 'has_key', 'hidden', 'index', 'insert', 'insert_after', 'insert_before', 'interesting_string_types', 'isSelfClosing', 'is_empty_element', 'known_xml', 'name', 'namespace', 'next', 'nextGenerator', 'nextSibling', 'nextSiblingGenerator', 'next_element', 'next_elements', 'next_sibling', 'next_siblings', 'parent', 'parentGenerator', 'parents', 'parserClass', 'parser_class', 'prefix', 'preserve_whitespace_tags', 'prettify', 'previous', 'previousGenerator', 'previousSibling', 'previousSiblingGenerator', 'previous_element', 'previous_elements', 'previous_sibling', 'previous_siblings', 'recursiveChildGenerator', 'renderContents', 'replaceWith', 'replaceWithChildren', 'replace_with', 'replace_with_children', 'select', 'select_one', 'self_and_descendants', 'self_and_next_elements', 'self_and_next_siblings', 'self_and_parents', 'self_and_previous_elements', 'self_and_previous_siblings', 'setup', 'smooth', 'sourceline', 'sourcepos', 'string', 'strings', 'stripped_strings', 'text', 'unwrap', 'wrap']

print(f"soup.title.text:{soup.title.text}") # soup.title.text:The Dormouse's story

# 取出第一个a标签的所有属性
print(f"取出第一个a标签的所有属性:{soup.a.attrs}") # {'href': 'http://example.com/elsie', 'class': ['sister'], 'id': 'link1'}

# 取出a标签的href属性
print(f"取出a标签的href属性:{soup.a.attrs['href']}") # 取出a标签的href属性:http://example.com/elsie

# 判断是否有class属性
print(f"判断是否有class属性:{soup.a.has_attr('class')}") # 判断是否有class属性:True

# 取出第一个p标签下的所有子节点
print(f"取出第一个p标签下的所有子节点:{soup.p.children}") # 取出第一个p标签下的所有子节点:<generator object Tag.children.<locals>.<genexpr> at 0x000001C1E376C1C0>
print(f"取出第一个p标签下的所有子节点使用list转换:{list(soup.p.children)}") # 取出第一个p标签下的所有子节点使用list转换:[<b>The Dormouse's story</b>]
print(f"取出第一个p标签下的所有子节点使用list转换:{list(soup.p.children)[0]}") # 取出第一个p标签下的所有子节点使用list转换:<b>The Dormouse's story</b>
print(f"取出第一个p标签下的所有子节点使用list转换:{list(soup.p.children)[0].text}") # 取出第一个p标签下的所有子节点使用list转换:The Dormouse's story
for child in soup.p.children:
    print(f"child:{child}") # child:<b>The Dormouse's story</b>

# 取出页面下所有a标签的href属性链接
soup.find_all('a')
for a in soup.find_all('a'):
    print(f"a.attrs['href']:{a.attrs['href']}")
    # a.attrs['href']:http://example.com/elsie
    # a.attrs['href']:http://example.com/lacie
    # a.attrs['href']:http://example.com/tillie

# 取出id=link3的a标签
print(f"soup.find:{soup.find(id='link3')}") # soup.find:<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>
print(f"soup.find:{soup.find(_class='story')}")

# 取出页面内所有文本
print(f"soup.get_text:{soup.get_text()}")
# 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.
# ...

# CSS选择器select
print(f"soup.select选择器:{soup.select('.story')}")
# [<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="link3">Tillie</a>;
# and they lived at the bottom of a well.</p>, <p class="story">...</p>]
print(f"soup.select选择器:{soup.select('#link1')}") # soup.select选择器:[<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
print(f"soup.select选择器:{soup.select('.story a')}") # soup.select选择器:[<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(f"soup.select选择器:{soup.select('p.story')}")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值