BeautifulSoup
是一個非常優秀的Python擴展庫,可以用來從HTML或XML文件中提取我們感興趣的數據,并且允許指定使用不同的解析器。
一、安裝BeautifulSoup
1.1 mac安裝bs4
完成安裝python3后,直接在命令行使用pip3
或者easy_install
來安裝
1.pip3安裝
pip3 install beautifulsoup4
2.easy_install安裝
easy_install beautifulsoup4
1.2 win下安裝bs4
需要先下載bs4安裝包到本地python目錄,再執行命令
借鑒網上方法
python3.4.3 對BeautifulSoup的支持不太好,大多網上都是python2.7 的安裝教程,而按那個真是頗費周折。最后,在[https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/](https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/) 找到了解決方案
1.下載
[https://www.crummy.com/software/BeautifulSoup/bs4/download/ ](https://www.crummy.com/software/BeautifulSoup/bs4/download/)
2.解壓至D:\python34 即python安裝目錄
3.打開cmd,進入D:\python34\beautifulsoup4-4.4.1 ,這是我的安裝路徑,這里面有setup.py 文件
4.cmd中輸入 ```Python setup.py install```
如果行不通,Beautiful Soup的發布協議允許你將BS4的代碼打包在你的項目中,這樣無須安裝即可使用.
5.測試是否安裝好
5.1輸入python,進入python模塊
5.2輸入from bs4 import BeautifulSoup檢測是否成功。
另附BeautifulSoup中文文檔鏈接,接下來好好享受爬蟲旅程。[https://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html#Quick%20Start](https://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html#Quick%20Start)
根據方法執行
1.下載和安裝
備注:cmd中可通過
where python
獲得本地python路徑
2.使用Python setup.py install
安裝
使用Python setup.py install
安裝報錯,是因為進入當下路徑文件夾后,無steup.py
文件可供安裝。調整1和2步驟,下載最新bs4包4.6版本,進入steup.py
文件夾中
執行命令python setup.py install
,正常進入安裝流程
3.進入python,使用from bs4 import BeautifulSoup
查看是否正常
查找上述報錯解決方法,因為使用python3.6版本,需更換庫,把python2的庫升級為python3的庫
具體:將bs4文件夾和2to3.py同時放到lib中,然后在cmd中定位到lib,運行:2to3.py bs4 -w就好了
之后運行報錯,操作異常,確認后發現,將bs4文件夾放入lib文件夾中
執行錯誤
--1.beautifulSoup4解壓目錄中的bs4文件夾C:\Users\xx\AppData\Local\Programs\Python\Python36\beautifulsoup4-4.6.0\beautifulsoup4-4.6.0\bs4
--2. 2to3.pyC:\Users\xx\AppData\Local\Programs\Python\Python36\Tools\scripts
都復制到python的安裝目錄下的LibC:\Users\xx\AppData\Local\Programs\Python\Python36\Lib
文件夾下
進入D:\Python37-32\Lib 目錄,并執行2to3.py bs4 -w
命令
進入python,使用from bs4 import BeautifulSoup查看是否正常
二、BeautifulSoup語法
1.學習基本夠用的即可
2.學習2,已完成
3.學習3,待學習搜索文檔樹、find_all
4.學習4,好的實踐
2.1. BeautifulSoup類的基本元素
Tag
Tag 對象與 XML 或 HTML 原生文檔中的 tag 相同,表示標簽,是最基本的信息組織單元,分別用<>和</>開頭和結尾
<Tag>.name
: Name 表示標簽的名字
<Tag>.attrs
: Attributes 表示標簽的屬性,返回字典形式組織,
<Tag>.string
: NavigableString 表示標簽內非屬性字符串
<Tag>.string
: Comment 表示標簽內的注釋部分
1.tag實例
如上之前已經學過,soup.標簽a/p,代表遍歷到第一個a標簽或者p標簽
>>> tag1 = soup.a
>>> print(tag1)
<a class="sister" id="link1">Elsie</a>
>>> tag2 = soup.p
>>> print(tag2)
<p class="title"><b>The Dormouse's story</b></p>
2.Name實例
類似:當我們通過soup.title.name的時候就可以獲得該title標簽的名稱,即<title>括號中的title
>>> tag1.name
'a'
>>> tag2.name
'p'
3.Attributes 實例
>>> tag1.attrs
{'href': 'http://example.com/elsie', 'class': ['sister'], 'id': 'link1'}
#在這里,我們把 tag1即a標簽的所有屬性打印輸出了出來,得到的類型是一個字典。
>>> tag2.attrs
{'class': ['title']}
如果我們想要單獨獲取某個屬性,可以這樣,例如我們獲取它的 class 叫什么
>>> tag2.attrs.get('class')
['title']
我們也可以通過這個attrs去更加詳細地過濾標簽--find_all
如果想要通過名字得到比一個 tag 更多的內容的時候就需要用 Searching the tree 中描述的方法, 比如 : find_all()
>>> soup.find_all('p')
[<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" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a> and
<a class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>, <p class="story">...</p>]
4.NavigableString
NavigableString按照字面意義上理解為可遍歷字符串,
是BeautifulSoup對象四種類型tag|NavigableString|BeautifulSoap|Comment
中的一種
>>> tag1.string
'Elsie'
# tag1即a標簽的內容 #
>>> type(tag1.string)
<class 'bs4.element.NavigableString'>
# 知道是一種類型,寫明對象類型 NavigableString #
>>> tag2.string
"The Dormouse's story"
>>> type(tag2.string)
<class 'bs4.element.NavigableString'>
5.Comment 實例 (與 NavigableString 的區別)
Comment 對象是一個特殊類型的 NavigableString 對象??還是不太懂
2.2 學習屬性和打印語句
2.2.1 學習屬性
1.標簽選擇器
在快速使用中我們添加如下代碼
print(soup.title)
print(type(soup.title))
print(soup.head)
print(soup.p)
作用:通過這種soup.標簽名 我們就可以獲得這個標簽的內容
備注:這里有個問題需要注意,通過這種方式獲取標簽,如果文檔中有多個這樣的標簽,返回的結果是第一個標簽的內容,如上面我們通過soup.p獲取p標簽,而文檔中有多個p標簽,但是只返回了第一個p標簽內容,見2.1.2 打印語句6.屬性print(soup.p)打印結果
2.獲取名稱
當我們通過soup.title.name的時候就可以獲得該title標簽的名稱,即title
print(soup.title.name)
3.獲取屬性
print(soup.p.attrs['name'])
print(soup.p['name'])
4.獲取內容
print(soup.p.string)
結果就可以獲取第一個p標簽的內容:
The Dormouse's story
5.嵌套選擇
見下方 5.屬性print(soup.title.parent.name)
打印結果
嵌套有 父子節點的概念,通過子.parent=父狀態,來嵌套獲得父的信息
6.標準選擇器
find_all:可以根據標簽名,屬性,內容查找文檔
find_all() 方法搜索當前 tag 的所有 tag 子節點, 并判斷是否符合過濾器的條件??
待學習find_all示例
find_all(name,attrs,recursive,text,**kwargs)
其余屬性目前未涉及,暫時未關注,可繼續回溯‘https://www.cnblogs.com/zhaof/p/6930955.html’
2.2.2 打印語句
#-*- coding:utf-8 -*-
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 class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a> and
<a class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
soup = BeautifulSoup(html_doc, 'html5lib')
print(soup.prettify())
print(soup.title)
print(soup.title.name)
print(soup.title.string)
print(soup.title.parent.name)
print(soup.p)
print(soup.p["class"])
print(soup.a)
print(soup.find_all('a'))
print(soup.find(id='link3'))
- 屬性
print(soup.prettify())
打印結果
prettify()函數,實現格式化輸出:把代碼格式給搞的標準一些,符合html代碼格式(從.py文件中發現,相關html格式并不規范),使用prettify規范格式,更清楚
C:\Users\sylvia.li\PycharmProjects\untitled\venv\Scripts\python.exe F:/01_python/01_testsamples/bs4_04.py
<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" id="link1">
Elsie
</a>
,
<a class="sister" id="link2">
Lacie
</a>
and
<a class="sister" id="link3">
Tillie
</a>
;
and they lived at the bottom of a well.
</p>
<p class="story">
...
</p>
</body>
</html>
Process finished with exit code 0
2.屬性print(soup.title)
打印結果
head標簽中的起始于<title>完結于</title>的內容
<title>The Dormouse's story</title>
屬性print(soup.head)
打印結果
html中起始于<head>完結于</head>的內容
<head><title>The Dormouse's story</title></head>
3.屬性print(soup.title.name)
打印結果
當我們通過soup.title.name的時候就可以獲得該title標簽的名稱,即<title>括號中的title
title
4.屬性print(soup.title.string)
打印結果
title標簽中string,即<title>The Dormouse's story</title>
中><
中間string部分
The Dormouse's story
5.屬性print(soup.title.parent.name)
打印結果
title.parent
是指title
標簽的父標簽,是指 head
標簽
head.name
可以獲得該head標簽的名稱,即<head>括號中的head
head
6.屬性print(soup.p)
打印結果
如果文檔中有多個這樣的標簽,返回的結果是第一個標簽的內容,如上面我們通過soup.p獲取p標簽,而文檔中有多個p標簽,但是只返回了第一個p標簽內容起始于<p到/p>為止
<p class="title"><b>The Dormouse's story</b></p>
7.屬性print(soup.p["class"])
打印結果
第一個P標簽中'class'的內容,把class=‘title’中賦給class的內容,字符串‘title’
['title']
8.屬性print(soup.a)
打印結果
第一個a標簽內容起始于<a到/a>為止
<a class="sister" id="link1">Elsie</a>
9.屬性print(soup.find_all('a'))
打印結果
找到所有a標簽并打印相關內容
[<a class="sister" id="link1">Elsie</a>, <a class="sister" id="link2">Lacie</a>, <a class="sister" id="link3">Tillie</a>]
10.屬性print(soup.find(id='link3'))
打印結果
打印id=link3的標簽結果
<a class="sister" id="link3">Tillie</a>
- 屬性
soup.select()
練習示例bs4_04.py,學習地址
【目標】
通過采用soup.select()
方法,遍歷html后獲得目標內容。
其中關鍵點在于,對于所需內容的精準定位,通過()內的語句
來實現:
11.1 關鍵字class
對于html內的內容,可以通過class(賦值給關鍵字class的類名)來進行定位
soup.select('.class的類名')
直接寫成soup.select('.class')
報錯,因為找不到目標內容
head
class:*************************
Traceback (most recent call last):
File "F:/01_python/01_testsamples/bs4_04.py", line 31, in <module>
print(soup.selecet('.class'))
TypeError: 'NoneType' object is not callable
Process finished with exit code 1
理解格式含義,使用select()
遍歷和定位的目標是定位到類class對應名稱中的內容:上面html中 class=‘sister’目標類名稱是sister格式,按照類名查找 sister
print(soup.select(".目標類名稱"))
示例見下
#按照類名查找 sister 上面html中 class=‘sister’目標類名稱是sister,格式是print(soup.select(".目標類名稱"))
print('sister:*************************')
print(soup.select(".sister"))
比如上述例子 會打印處類=sister的內容
sister:*************************
[<a class="sister" id="link1">Elsie</a>, <a class="sister" id="link2">Lacie</a>, <a class="sister" id="link3">Tillie</a>]
參考文檔
1.確定遍歷目標
2.根據不同目標特性,找到語法格式
11.2 關鍵字id
按照id名稱查找 注意格式 print(soup.select("#目標id名稱 "))。目標是id=link3,則寫成"#link3"
print('id=link3:*************************')
print(soup.select("#link3"))
打印結果:
[<a class="sister" id="link3">Tillie</a>]
11.4 組合高級查找
按照id名稱查找 x標簽中目標id y 格式 print(soup.select("x #y"))
print('P標簽id=link2:*************************')
print(soup.select("p #link2"))
打印結果:
P標簽id=link2:*************************
[<a class="sister" id="link2">Lacie</a>]
11.3 關鍵字標簽
按照標簽查找,注意目標標簽名稱
print('tag:*************************')
print(soup.select('a'))
打印結果:
tag:*************************
[<a class="sister" id="link1">Elsie</a>, <a class="sister" id="link2">Lacie</a>, <a class="sister" id="link3">Tillie</a>]
綜上,在bs4
中希望篩選(或者查找)sth方法
1 直接查找
2 find_all
和find
3 通過css選擇器select()
方法
2.2 BeautifulSoup :一些常用功能的使用和測試
點擊此處,很喜歡這位小姐姐的文風,可以靜下心閱讀
2.2.1 關于bs4的解析速度
1.仔細閱讀文檔后發現,文檔解析器對速度至關重要!
2.安裝chardet
模塊
如果沒有安裝chardet模塊,那么光一個網頁就要7秒!!(安裝方法自行度娘), 還不包括獲取網頁時間。然而試過后,如過山車一般:,安裝了chardet以后7秒變成了一瞬。
ps:然而,用了幾天后又變回了7秒,卸載了chardet又變回了一瞬間!
2.2.2 導入方式
BeautifulSoup升級到4以后,導入方法變了,如下:
from bs4 import BeautifulSoup
2.2.3 關于輸入文本格式
關于被解析文檔的編碼格式
1.官方說無論被傳入什么編碼的文檔,都會被統一為unicode
2.實際上有時候我發現,必須以unicode傳入才能獲得正確結果,這里試驗發現,還真的是如此!必須傳入decode過的碼
html_doc = open('test-Zhilian-list-page-sm1.html', 'r').read().decode('utf-8')
# ^ 這個html文件其實是智聯招聘搜索頁的源碼,可以自己保存下來直接試一試。
如下圖,最簡單一個爬蟲示例。如果要用bs4
,需要把參數the_page
在read()
后繼續轉換編碼格式decode('uft-8')
2.2.4 關于bs4的文檔解析器
又是一個大坑:bs升級到4后,實例化時需要明確指定文檔解析器,如:
soup = BeautifulSoup(html_doc, 'lxml')
坑的地方:
1.但是著名的lxml在這里就是個大坑啊,
2.因為它會直接略過html所有沒寫規范的tag,而不管人家多在乎那些信息
PS:因為這個解析器的事,我少說也折騰了好幾個小時才找到原因吧。
【總結】記住,選擇 * html5lib*!效率沒查多少,最起碼容錯率強,不會亂刪你東西!
soup = BeautifulSoup(html_doc, 'html5lib')
5.# 關于bs4的輸出格式 #################
# prettify()官方解釋是一律輸出utf-8格式,
# 其實卻是unicode類型!!所以必須在prettify()里面指定編碼。
output = soup.prettify('utf-8')
print repr(output)