Python網絡爬蟲與信息提取(二)—— BeautifulSoup


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()參數

回到頂部


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM