Beautiful Soup 函数库
Beautiful Soup 函数库 ( 模组 ) 是一个 Python 外部函数库,可以分析网页的 HTML 与 XML 文件,并将分析的结果转换成“网页标签树”( tag ) 的型态,让数据读取方式更接近网页的操作语法,处理起来也更为便利,这篇教学会介绍 Beautiful Soup 函数库的基本用法。
快速导览:
本篇使用的 Python 版本为 3.7.12,所有范例可使用 Google Colab 实作,不用安装任何软件 ( 参考:使用 Google Colab )
安装 Beautiful Soup 模组
如果是使用 Colab 或 Anaconda,默认已经安装了 Beautiful Soup 函数库,不用额外安装,如果是本机环境,输入下列指令,就能安装 Beautiful Soup 函数库 ( 依据每个人的作业环境不同,可使用 pip 或 pip3 或 pipenv )。
pip install beautifulsoup4
import Beautiful Soup
要使用 Beautiful Soup 必须先 import Beautiful Soup 模组。
from bs4 import BeautifulSoup
开始使用 Beautiful Soup
将 HTML 的源代码 ( 纯文字 ) 提供给 Beautiful Soup,就能转换成可读取的标签树 ( tag ),所以通常会搭配 requests 爬取网页内容一并使用,下方的程序码执行后,会使用 requests 抓取“台湾水库即时水情 ”网页的源代码,接着使用 Beautiful Soup 转换成标签树,最后印出 title 的标签。
import requests
from bs4 import BeautifulSoup
url = 'https://water.taiwanstat.com/'
web = requests.get(url) # 取得網頁內容
soup = BeautifulSoup(web.text, "html.parser") # 轉換成標籤樹
title = soup.title # 取得 title
print(title) # 印出 title ( 台灣水庫即時水情 )
认识基本网页架构
使用 Beautiful Soup 时,会读取特定的网页结构 ( 如同上面的范例会从网页源代码里读取 title 的标签 ),因此必须要从网页源代码着手,稍微了解网页的架构,如果要观看源代码,可以用浏览器 ( Chrome ) 打开网页,用鼠标在网页的任意位置按下右键,点选“检视网页源代码”。
点选后,会打开网页的源代码,这也是使用 requests 会读取到的基本数据。
网页是由“标签”的语法所构成,标签 ( tag ) 指的是由“<”和“>”包覆的代码,通常没有斜线的“<标签>”作为开头,有斜线“</标签>”做为结尾,标签代码并不会显示在网页中,只有被标签包覆的内容才会显示在网页里,而标签也会互相层叠包覆,形成所为的“巢状结构”。
每个标签和所包覆的内容,会组合成一个 DOM ( 文件模型 ),网页的程序通常会针对 DOM 去做运算和处理,也可以针对不同的 DOM,给予不同的 id 或样式属性 ( attribute、class、style...等 ),只要知道 DOM 的标签,或是取得特定的 id、class 或 attribute,就能进一步透过程控 DOM。
下图是一个简单网页范例,左方的源代码会产生右方的网页内容,当中包含 h1、h2、div、ul、li...等标签。
网页解析器
当借由 requests 取得网页源代码后,Beautiful Soup 还需要第二个“解析器”的参数,将源代码的“纯文字”,转换成可供分析取用的“标签树”,Python 本身内建“html.parser”的解析器,也可以使用下方指令,另外安装“html5lib”解析器 ( 依据每个人的作业环境不同,可使用 pip 或 pip3 或 pipenv )。
pip install html5lib
安装后,只要更换第二个参数,就可以更换解析器,下方的程序码使用 html5lib 解析器 ( 不需要 import,安装后就可以使用 ),html5lib 的容错率比 html.parser 高,但解析速度比较慢。
import requests
from bs4 import BeautifulSoup
url = 'https://water.taiwanstat.com/'
web = requests.get(url)
# soup = BeautifulSoup(web.text, "html.parser") # 使用 html.parser 解析器
soup = BeautifulSoup(web.text, "html5lib") # 使用 html5lib 解析器
title = soup.title
print(title)
Beautiful Soup 的方法
下方列出 Beautiful Soup 寻找网页内容的方法,当中最常使用的是 find_all()、find() 和 select()。
| 方法 | 说明 |
|---|---|
| select() | 以 CSS 选择器的方式寻找指定的 tag。 |
| find_all() | 以所在的 tag 位置,寻找内容里所有指定的 tag。 |
| find() | 以所在的 tag 位置,寻找第一个找到的 tag。 |
| find_parents()、find_parent() | 以所在的 tag 位置,寻找父层所有指定的 tag 或第一个找到的 tag。 |
| find_next_siblings()、find_next_sibling() | 以所在的 tag 位置,寻找同一层后方所有指定的 tag 或第一个找到的 tag。 |
| find_previous_siblings()、ind_previous_sibling() | 以所在的 tag 位置,寻找同一层前方所有指定的 tag 或第一个找到的 tag。 |
| find_all_next()、find_next() | 以所在的 tag 位置,寻找后方内容里所有指定的 tag 或第一个找到的 tag。 |
| find_all_previous()、find_previous() | 所在的 tag 位置,寻找前方内容里所有指定的 tag 或第一个找到的 tag。 |
下方的程序码,使用 Beautiful Soup 取得范例网页中指定 tag 的内容。
import requests
from bs4 import BeautifulSoup
url = 'https://www.iana.org/domains/'
web = requests.get(url)
soup = BeautifulSoup(web.text, "html.parser")
print(soup.select('#logo')) # 搜尋 id 為 logo 的 tag 內容
print('\n----------\n')
print(soup.find_all('div',id="logo")) # 搜尋所有 id 為 logo 的 div
print('\n----------\n')
divs = soup.find_all('div') # 搜尋所有的 div
print(divs[1]) # 取得搜尋到的第二個項目 ( 第一個為 divs[0] )
print('\n----------\n')
# 從搜尋到的項目裡,尋找父節點裡所有的 li
print(divs[1].find_parent().find_all('li'))
print('\n----------\n')
# 從搜尋到的項目裡,尋找父節點裡所有 li 的第三個項目,找到他後方同層的所有 li
print(divs[1].find_parent().find_all('li')[2].find_next_siblings())
print('\n----------\n')
# 從搜尋到的項目裡,尋找父節點裡所有 li 的第三個項目,找到他前方同層的所有 li
print(divs[1].find_parent().find_all('li')[2].find_previous_siblings())
由于 find_all() 是使用频率最高的方法,所以也可以简化成下列的写法:
import requests
from bs4 import BeautifulSoup
url = 'https://www.iana.org/domains/'
web = requests.get(url)
soup = BeautifulSoup(web.text, "html.parser")
print(soup.find_all('a')) # 等同於下方的 soup('a')
print(soup('a')) # 等同於上方的 find_all('a')
Beautiful Soup 方法的参数
使用 Beautiful Soup 方法时,可以加入一些参数,帮助更近一步的筛选搜索结果,下方是一些常用的参数:
| 参数 | 说明 |
|---|---|
| string | 搜索 tag 包含的文字。 |
| limit | 搜索 tag 后只回传多少个结果。 |
| recursive | 默认 True,会搜索内容所有层,设定 False 只会搜索下一层。 |
| id | 搜索 tag 的 id。 |
| class_ | 搜索 tag class,因为 class 为 Python 保留字,所以后方要加上底线。 |
| href | 搜索 tag href。 |
| attrs | 搜索 tag attribute 属性。 |
下方的程序码,使用 Beautiful Soup 取得范例网页中指定 tag 的内容,并加入参数做进一步的筛选。
import requests
from bs4 import BeautifulSoup
url = 'https://www.iana.org/domains/'
web = requests.get(url)
soup = BeautifulSoup(web.text, "html.parser")
print(soup.find_all('a')) # 找出所有 a tag
print(soup.find_all('a', string='Domains')) # 找出內容字串為 Domains 的 a tag
print(soup('a', limit=2)) # 找出前兩個 a tag
取得并输出内容
抓取到内容后,可以使用下列两种常用的方法,将内容或属性输出为字串:
| 方法 | 说明 |
|---|---|
| .get_text() | 输出 tag 的内容。 |
| [属性] | 输出 tag 里某个属性的内容。 |
下方的程序码执行后,会先输出第一个 a tag 的内容,接着输出第一个 a tag 里 href 属性的内容。
import requests
from bs4 import BeautifulSoup
url = 'https://www.iana.org/domains/'
web = requests.get(url)
soup = BeautifulSoup(web.text, "html.parser")
print(soup.find('a').get_text()) # 輸出第一個 a tag 的內容
print(soup.find('a')['href']) # 輸出第一個 a tag 的 href 屬性內容
抓取水库的容量
如果是“静态”页面 ( 不需要跟服务器沟通、页面内容不是动态产生 ),透过 Beautiful Soup 都能很轻松的抓取到对应的内容,抓取到内容后,将内容输出为纯文字。
下方的程序码执行后,会抓取水库的名称以及最大容量 ( 因即时水位是动态产生,所以单纯用这个方法读取 )。
import requests
from bs4 import BeautifulSoup
url = 'https://water.taiwanstat.com/'
web = requests.get(url)
soup = BeautifulSoup(web.text, "html.parser")
reservoir = soup.select('.reservoir') # 取得所有 class 為 reservoir 的 tag
for i in reservoir:
print(i.find('div', class_='name').get_text(), end=' ') # 取得內容的 class 為 name 的 div 文字
print(i.find('h5').get_text(), end=' ') # 取得內容 h5 tag 的文字
print()
参考数据
更多内容可以参考 Beautiful Soup 的官方网站说明:
微信扫码关注
抖音扫码关注