BeautifulSoup官方介紹:
Beautiful Soup 是一個可以從HTML或XML文件中提取數據的Python庫.它能夠通過你喜歡的轉換器實現慣用的文檔導航,查找,修改文檔的方式.
官方網站:https://www.crummy.com/software/BeautifulSoup/
BeautifulSoup安裝
在"C:\Windows\System32"中找到"cmd.exe",使用管理員身份運行,在命令行中輸入:“pip install beautifulsoup4”運行。
C:\Windows\system32>pip install beautifulsoup4 Requirement already satisfied (use --upgrade to upgrade): beautifulsoup4 in c:\users\lei\appdata\local\programs\python\p ython35\lib\site-packages\beautifulsoup4-4.5.0-py3.5.egg You are using pip version 8.1.1, however version 9.0.1 is available. You should consider upgrading via the 'python -m pip install --upgrade pip' command.
提示pip版本過低,使用 python -m pip install --upgrade pip
進行升級。
Beautiful Soup庫的安裝測試:
from bs4 import BeautifulSoup soup = BeautifulSoup('<p>data</p>','html.parser')
演示HTML頁面地址:http://www.cnblogs.com/yan-lei
>>> import requests >>> from bs4 import BeautifulSoup >>> r = requests.get("http://www.cnblogs.com/yan-lei/") >>> demo = r.text >>> soup = BeautifulSoup(demo,"html.parser") >>> soup
Beautiful Soup庫的使用
以HTML為例,任何HTML文件都是有一組"<>"組織起來的,其實就是標簽,標簽之間形成了上下游關系,形成了標簽樹。BeautifulSoup庫是解析、遍歷、維護“標簽樹”的功能庫
<p>..</p>:標簽Tag
- 標簽Name一般成對出現
- 屬性Attributes 0個或多個
Beautiful Soup庫的引用
Beautiful Soup庫,也叫beautfulsoup4 或bs4。約定引用方式如下,即主要是用BeautifulSoup類。
from bs4 import BeautifulSoup import bs4
Beautiful Soup類
將標簽樹轉換為BeautifulSoup類,此時我們將HTML、標簽樹、BeautifulSoup類等價
from bs4 import BeautifulSoup soup1 = BeautifulSoup("<html>data</html>","html.parser") soup2 = BeautifulSoup(open("D://demo.html",'rb'),"html.parser")
使用 soup2 = BeautifulSoup(open("D://demo.html"),"html.parser")
報錯:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "C:\Users\lei\AppData\Local\Programs\Python\Python35\lib\site-packages\beautifulsoup4-4.5.0-py3.5.egg\bs4\__init_ _.py", line 191, in __init__ UnicodeDecodeError: 'gbk' codec can't decode byte 0xbf in position 2: illegal multibyte sequence
BeautifulSoup對應一個HTML/XML文檔的全部內容。
Beautiful Soup庫解析器
解析器 | 使用方法 | 條件 |
---|---|---|
bs4的HTML解析器 | BeautifulSoup(mk,'html.parser') | 安裝bs4庫 |
lxml的HTML解析器 | BeautifulSoup(mk,'lxml') | pip install lxml |
lxml的XML解析器 | BeautifulSoup(mk,'xml') | pip install lxml |
html5lib的解析器 | BeautifulSoup(mk,'html5lib') | pip install html5lib |
Beautiful Soup類的基本元素
基本元素 | 說明 |
---|---|
Tag | 標簽,最基本的信息組織單元,分別用<>和</>標明開頭和結尾 |
Name | 標簽的名字,<p>...</p>的名字是'p',格式:<tag>.name |
Attributes | 標簽的屬性,字典形式的組織,格式:<tag>.attrs |
NavigleString | 標簽內非屬性字符串,<>...</>中字符串,格式<tag>.string |
Comment | 標簽內字符串的注釋部分,一種特殊的Comment類型 |
- Tag標簽:任何存在於HTML語法中的標簽都可以用soup.<tag>訪問獲得;當HTML文檔中存在多個相同<tag>對應內容時,soup.<tag>返回第一個。
- Tag的名字(name):每個<tag>都有自己的名字,通過<tag>.name獲取,字符串類型。
- Tag的attrs(屬性):一個<tag>可以有0個或多個屬性,字典類型。
- Tag的NavigableString:NavigableString可以跨越多個層次
- Tag的Comment:Comment是一種特殊類型。
>>> import requests >>> from bs4 import BeautifulSoup >>> r = requests.get('http://www.cnblogs.com/yan-lei/') >>> html = r.text >>> soup = BeautifulSoup(html,'html.parser') >>> soup.title <title>Python學習者 - 博客園</title> >>> soup.a <a name="top"></a> >>> soup.a.name 'a' >>> soup.a.parent.name 'body' >>> soup.a.attrs {'name': 'top'} >>> type(soup.a) <class 'bs4.element.Tag'> >>> type(soup.a.attrs) <class 'dict'> >>> soup.h1.string 'Python學習者' >>> type(soup.h1.string) <class 'bs4.element.NavigableString'>
基於bs4庫的HTML內容遍歷方法
HTML中 <...>構成了所屬關系,形成了標簽的樹形結構,有三種遍歷方式。
使用以下的HTML進行測試:E:\BeautifulSoupTest.html
<html> <head> <meta charset="utf-8"> <title>BeautifulSoup</title> </head> <body> <div id="header"> <h1 style="font-size:16px;text-align:center">這里是標題</h1> </div> <div id="nav"> <h1>左導航</h1> </div> <div id="main"> <p>第一段</p> <p>第二段</p> <img src="test.jpg"/> <p><a href="http://www.cnblogs.com/yan-lei/">博客園</a></p> </div> <div id="footer"> <h1>底邊</h1> </div> </body> </html>
標簽樹的下行遍歷
屬性 | 說明 |
---|---|
.contents | 子節點的列表,將<tag>所有兒子節點存入列表 |
.contents | 子節點的列表,將<tag>所有兒子節點存入列表 |
.children | 子節點的迭代類型,與.contents類似,用於循環遍歷兒子節點 |
.descendants | 子孫節點的迭代類型,包含所有子孫節點,用於循環遍歷 |
BeautifulSoup類是標簽樹的根節點
>>> from bs4 import BeautifulSoup >>> soup = BeautifulSoup(open('E:\\BeautifulSoupTest.html','rb'),'html.parser') >>> soup.head.contents #返回的是列表 ['\n', <meta charset="utf-8"> <title>BeautifulSoup</title> </meta>] >>> len(soup.body.contents) 9 >>> for child in soup.body.children: # 遍歷兒子節點 ... print(child) ... <div id="header"> <h1 style="font-size:16px;text-align:center">這里是標題</h1> </div> <div id="nav"> <h1>左導航</h1> </div> <div id="main"> <p>第一段</p> <p>第二段</p> <img src="test.jpg"> <p><a href="http://www.cnblogs.com/yan-lei/">博客園</a></p> </img></div> <div id="footer"> <h1>底邊</h1> </div> >>> for child in soup.body.descendants: # 遍歷子孫節點 ... print(child) ... <div id="header"> <h1 style="font-size:16px;text-align:center">這里是標題</h1> </div> <h1 style="font-size:16px;text-align:center">這里是標題</h1> 這里是標題 <div id="nav"> <h1>左導航</h1> </div> <h1>左導航</h1> 左導航 <div id="main"> <p>第一段</p> <p>第二段</p> <img src="test.jpg"> <p><a href="http://www.cnblogs.com/yan-lei/">博客園</a></p> </img></div> <p>第一段</p> 第一段 <p>第二段</p> 第二段 <img src="test.jpg"> <p><a href="http://www.cnblogs.com/yan-lei/">博客園</a></p> </img> <p><a href="http://www.cnblogs.com/yan-lei/">博客園</a></p> <a href="http://www.cnblogs.com/yan-lei/">博客園</a> 博客園 <div id="footer"> <h1>底邊</h1> </div> <h1>底邊</h1> 底邊
for child in soup.body.children: # 遍歷兒子節點 print(child) for child in soup.body.descendants: # 遍歷子孫節點 print(child)
標簽樹的上行遍歷
屬性 | 說明 |
---|---|
.parent | 節點的父親標簽 |
.parents | 節點先輩標簽的迭代類型,用於循環遍歷先輩節點 |
>>> for parent in soup.a.parents: ... if parent is None: ... print(parent) ... else: ... print(parent.name) ... p img div body html [document]
# 判斷所有先輩節點,包括soup本身,所以要區別判斷 for parent in soup.a.parents: if parent is None: print(parent) else: print(parent.name)
標簽樹的平行遍歷
屬性 | 說明 |
---|---|
.next_sibling | 返回按照HTML文本順序的下一個平行節點標簽 |
.previous_sibling | 返回按照HTML文本順序的上一個平行節點標簽 |
.next_siblings | 迭代類型,返回按照HTML文本順序的后續所有平行節點標簽 |
.previous_siblings | 迭代類型,返回按照HTML文本順序的前續所有平行節點標簽 |
*所有的平行遍歷發生在同一個父節點下的各節點間。
# div標簽下一個平行節點標簽 soup.div.next_sibling # div標簽上一個平行節點標簽 soup.div.previous_sibling # 遍歷后續節點 for sibling in soup.div.next_sibling: print(sibling) # 遍歷前續節點 for sibling in soup.div.previous_sibling: print(sibling)
基於bs4庫的HTML格式輸出
bs4庫的prettify()方法
.prettify()為HTML文本<>及其內容增加'\n'
.prettify()可用於標簽,方法:<tag>.prettify()
print(soup.prettify())
bs4庫將任何HTML輸入都變成utf-8編碼,Python 3.x默認支持編碼是utf-8,解析無障礙。
信息標記的三種形式
信息的標記:
- 標記后的信息可形成信息組織結構,增加了信息維度
- 標記后的信息可用於通信、存儲或展示
- 標記的結構與信息一樣具有重要價值
- 標記后的信息更利於程序的理解和運用
HTML的信息標記:
HTML是WWW(World Wide Web)的信息組織方式。
HTML通過預定義的<>...</>標簽形式組織不同類型的信息。
XML eXtensible Markup Language
XML格式是基於HTML格式發展以來的一種通用的信息格式。
- XML基本格式:<name> ... </name>
- 空元素縮寫形式:<name />
- 注釋書寫形式:<!-- -->
JSON JavaScript Object Notation
有類型的鍵值對 key:value
使用 "" 表達是字符串類型,沒有字符串則是數字類型。
YAML YAML Ain't Markup Language
無類型鍵值對 key:value
通過縮進表達所屬關系
- - 表達並列關系
- | 表達整塊數據
- # 表示注釋
key : value key : #Comment -value1 -value2 key : subkey : subvalue
三種信息標記形式的比較:
XML 最早的通用信息標記語言,可擴展性好,但繁瑣。Internet上的信息交互與傳遞。
JSON 信息有類型,適合程序處理(js),較XML簡潔。移動應用雲端和節點的信息通信,無注釋。
YAML 信息無類型,文本信息比例最高,可讀性好。各類系統的配置文件,有注釋易讀。
信息提取的一般方法
方法一:完整解析信息的標記形式,再提取關鍵信息。
XML JSON YAML
需要標記解析器 例如bs4庫的標簽樹遍歷
優點:信息解析准確
缺點:提取過程繁瑣,速度慢。
方法二:無視標記形式,直接搜索關鍵信息。
搜索
對信息的文本查找函數即可。
優點:提取過程簡介,速度較快。
缺點:提取結果准確性與信息內容相關。
方法三:融合方法
融合方法:結合形式解析與搜索方法,提取關鍵信息。
基於bs4庫的HTML內容查找方法
<>.find_all(name,attrs,recursive,string,**kwargs)
返回一個列表類型,存儲查找結果。
- name:對標簽名稱的檢索字符串。
- attrs:對標簽屬性值的檢索字符串,可標注屬性檢索。
- recursive:是否對子孫全部檢索,默認True。
- string:<>...</>中字符串區域的檢索字符串。
<tag>(..) 等價於 <tag>.find_all(..)
soup(..) 等價於 soup.find_all(..)
>>> soup.div() [<h1 style="font-size:16px;text-align:center">這里是標題</h1>] >>> for tag in soup.find_all(True): # 返回所有的標簽 ... print(tag.name) ... html head meta title body div h1 div h1 div p p img p a div h1
擴展方法
方法 | 說明 |
---|---|
<>.find() | 搜索且只返回一個結果,自負串類型,同.find_all()參數 |
<>.find_parents() | 在先輩節點中搜索,返回列表類型,同find_all()參數 |
<>.find_parent() | 在先輩節點中返回一個結果,字符串類型,同.find()參數 |
<>.find_next_siblings() | 在后續平行節點中搜索,返回列表類型,同.find_all()參數 |
<>.find_next_sibling() | 在后續平行節點中返回一個結果,字符串類型,同.find()參數 |
<>.find_previous_siblings() | 在前序節點中搜索,返回列表類型,同.find_all()參數 |
<>.find_previous_sibling() | 在前序節點中返回一個結果,字符串類型,同.find()參數 |