01_7爬蟲(chóng)網(wǎng)頁(yè)_BS4

BeautifulSoup

是一個(gè)非常優(yōu)秀的Python擴(kuò)展庫(kù),可以用來(lái)從HTML或XML文件中提取我們感興趣的數(shù)據(jù),并且允許指定使用不同的解析器。

一、安裝BeautifulSoup

1.1 mac安裝bs4

完成安裝python3后,直接在命令行使用pip3或者easy_install來(lái)安裝

1.pip3安裝

pip3 install beautifulsoup4

2.easy_install安裝

easy_install beautifulsoup4

1.2 win下安裝bs4

需要先下載bs4安裝包到本地python目錄,再執(zhí)行命令

借鑒網(wǎng)上方法

    python3.4.3 對(duì)BeautifulSoup的支持不太好,大多網(wǎng)上都是python2.7 的安裝教程,而按那個(gè)真是頗費(fèi)周折。最后,在[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.打開(kāi)cmd,進(jìn)入D:\python34\beautifulsoup4-4.4.1  ,這是我的安裝路徑,這里面有setup.py  文件
     4.cmd中輸入 ```Python setup.py install```
     如果行不通,Beautiful Soup的發(fā)布協(xié)議允許你將BS4的代碼打包在你的項(xiàng)目中,這樣無(wú)須安裝即可使用.
     5.測(cè)試是否安裝好
         5.1輸入python,進(jìn)入python模塊
         5.2輸入from bs4 import BeautifulSoup檢測(cè)是否成功。
      另附BeautifulSoup中文文檔鏈接,接下來(lái)好好享受爬蟲(chóng)旅程。[https://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html#Quick%20Start](https://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html#Quick%20Start)


根據(jù)方法執(zhí)行

1.下載和安裝

下載bs4包后,解壓至本地python目錄

備注:cmd中可通過(guò)where python獲得本地python路徑

2.使用Python setup.py install安裝

使用Python setup.py install安裝報(bào)錯(cuò),是因?yàn)檫M(jìn)入當(dāng)下路徑文件夾后,無(wú)steup.py文件可供安裝。調(diào)整1和2步驟,下載最新bs4包4.6版本,進(jìn)入steup.py文件夾中

下載bs4包后,解壓至本地python目錄.png

執(zhí)行命令python setup.py install,正常進(jìn)入安裝流程

安裝bs4_1.png

安裝bs4_2.png

3.進(jìn)入python,使用from bs4 import BeautifulSoup查看是否正常

from bs4 import BeautifulSoup_報(bào)錯(cuò).png

查找上述報(bào)錯(cuò)解決方法,因?yàn)槭褂胮ython3.6版本,需更換庫(kù),把python2的庫(kù)升級(jí)為python3的庫(kù)
具體:將bs4文件夾和2to3.py同時(shí)放到lib中,然后在cmd中定位到lib,運(yùn)行:2to3.py bs4 -w就好了


2to3.py bs4 -w.png

之后運(yùn)行報(bào)錯(cuò),操作異常,確認(rèn)后發(fā)現(xiàn),將bs4文件夾放入lib文件夾中執(zhí)行錯(cuò)誤

--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
都復(fù)制到python的安裝目錄下的LibC:\Users\xx\AppData\Local\Programs\Python\Python36\Lib文件夾下
進(jìn)入D:\Python37-32\Lib 目錄,并執(zhí)行2to3.py bs4 -w命令

bs4安裝包下bs4文件夾.png
2to3.py文件.png

進(jìn)入python,使用from bs4 import BeautifulSoup查看是否正常


完成安裝,并可正常使用bs4.png

二、BeautifulSoup語(yǔ)法

1.學(xué)習(xí)基本夠用的即可
2.學(xué)習(xí)2,已完成
3.學(xué)習(xí)3,待學(xué)習(xí)搜索文檔樹(shù)、find_all
4.學(xué)習(xí)4,好的實(shí)踐

2.1. BeautifulSoup類的基本元素

Tag
Tag 對(duì)象與 XML 或 HTML 原生文檔中的 tag 相同,表示標(biāo)簽,是最基本的信息組織單元,分別用<>和</>開(kāi)頭和結(jié)尾

<Tag>.name : Name 表示標(biāo)簽的名字
<Tag>.attrs: Attributes 表示標(biāo)簽的屬性,返回字典形式組織,
<Tag>.string : NavigableString 表示標(biāo)簽內(nèi)非屬性字符串
<Tag>.string: Comment 表示標(biāo)簽內(nèi)的注釋部分

1.tag實(shí)例
如上之前已經(jīng)學(xué)過(guò),soup.標(biāo)簽a/p,代表遍歷到第一個(gè)a標(biāo)簽或者p標(biāo)簽

>>> 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實(shí)例
類似:當(dāng)我們通過(guò)soup.title.name的時(shí)候就可以獲得該title標(biāo)簽的名稱,即<title>括號(hào)中的title

>>> tag1.name
'a'
>>> tag2.name
'p'

3.Attributes 實(shí)例

 >>> tag1.attrs
{'href': 'http://example.com/elsie', 'class': ['sister'], 'id': 'link1'}

#在這里,我們把 tag1即a標(biāo)簽的所有屬性打印輸出了出來(lái),得到的類型是一個(gè)字典。
>>> tag2.attrs
{'class': ['title']}

如果我們想要單獨(dú)獲取某個(gè)屬性,可以這樣,例如我們獲取它的 class 叫什么

>>> tag2.attrs.get('class')
['title']

我們也可以通過(guò)這個(gè)attrs去更加詳細(xì)地過(guò)濾標(biāo)簽--find_all
如果想要通過(guò)名字得到比一個(gè) tag 更多的內(nèi)容的時(shí)候就需要用 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對(duì)象四種類型tag|NavigableString|BeautifulSoap|Comment中的一種

>>> tag1.string
'Elsie'
# tag1即a標(biāo)簽的內(nèi)容 #
>>> type(tag1.string)
<class 'bs4.element.NavigableString'>
# 知道是一種類型,寫(xiě)明對(duì)象類型 NavigableString #
>>> tag2.string
"The Dormouse's story"
>>> type(tag2.string)
<class 'bs4.element.NavigableString'>

5.Comment 實(shí)例 (與 NavigableString 的區(qū)別)
Comment 對(duì)象是一個(gè)特殊類型的 NavigableString 對(duì)象??還是不太懂

2.2 學(xué)習(xí)屬性和打印語(yǔ)句

2.2.1 學(xué)習(xí)屬性

1.標(biāo)簽選擇器

在快速使用中我們添加如下代碼

print(soup.title)
print(type(soup.title))
print(soup.head)
print(soup.p)

作用:通過(guò)這種soup.標(biāo)簽名 我們就可以獲得這個(gè)標(biāo)簽的內(nèi)容
備注:這里有個(gè)問(wèn)題需要注意,通過(guò)這種方式獲取標(biāo)簽,如果文檔中有多個(gè)這樣的標(biāo)簽,返回的結(jié)果是第一個(gè)標(biāo)簽的內(nèi)容,如上面我們通過(guò)soup.p獲取p標(biāo)簽,而文檔中有多個(gè)p標(biāo)簽,但是只返回了第一個(gè)p標(biāo)簽內(nèi)容,見(jiàn)2.1.2 打印語(yǔ)句6.屬性print(soup.p)打印結(jié)果

2.獲取名稱

當(dāng)我們通過(guò)soup.title.name的時(shí)候就可以獲得該title標(biāo)簽的名稱,即title
print(soup.title.name)

3.獲取屬性

print(soup.p.attrs['name'])
print(soup.p['name'])

4.獲取內(nèi)容

print(soup.p.string)

結(jié)果就可以獲取第一個(gè)p標(biāo)簽的內(nèi)容:

The Dormouse's story

5.嵌套選擇

見(jiàn)下方 5.屬性print(soup.title.parent.name)打印結(jié)果
嵌套有 父子節(jié)點(diǎn)的概念,通過(guò)子.parent=父狀態(tài),來(lái)嵌套獲得父的信息

6.標(biāo)準(zhǔn)選擇器

find_all:可以根據(jù)標(biāo)簽名,屬性,內(nèi)容查找文檔
find_all() 方法搜索當(dāng)前 tag 的所有 tag 子節(jié)點(diǎn), 并判斷是否符合過(guò)濾器的條件??

待學(xué)習(xí)find_all示例

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

其余屬性目前未涉及,暫時(shí)未關(guān)注,可繼續(xù)回溯‘https://www.cnblogs.com/zhaof/p/6930955.html

2.2.2 打印語(yǔ)句

#-*- 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'))
  1. 屬性print(soup.prettify())打印結(jié)果
    prettify()函數(shù),實(shí)現(xiàn)格式化輸出:把代碼格式給搞的標(biāo)準(zhǔn)一些,符合html代碼格式(從.py文件中發(fā)現(xiàn),相關(guān)html格式并不規(guī)范),使用prettify規(guī)范格式,更清楚
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)打印結(jié)果
head標(biāo)簽中的起始于<title>完結(jié)于</title>的內(nèi)容

<title>The Dormouse's story</title>

屬性print(soup.head)打印結(jié)果
html中起始于<head>完結(jié)于</head>的內(nèi)容

<head><title>The Dormouse's story</title></head>

3.屬性print(soup.title.name)打印結(jié)果
當(dāng)我們通過(guò)soup.title.name的時(shí)候就可以獲得該title標(biāo)簽的名稱,即<title>括號(hào)中的title

title

4.屬性print(soup.title.string)打印結(jié)果
title標(biāo)簽中string,即<title>The Dormouse's story</title>><中間string部分

The Dormouse's story

5.屬性print(soup.title.parent.name)打印結(jié)果
title.parent 是指title標(biāo)簽的父標(biāo)簽,是指 head 標(biāo)簽
head.name 可以獲得該head標(biāo)簽的名稱,即<head>括號(hào)中的head

head

6.屬性print(soup.p)打印結(jié)果
如果文檔中有多個(gè)這樣的標(biāo)簽,返回的結(jié)果是第一個(gè)標(biāo)簽的內(nèi)容,如上面我們通過(guò)soup.p獲取p標(biāo)簽,而文檔中有多個(gè)p標(biāo)簽,但是只返回了第一個(gè)p標(biāo)簽內(nèi)容起始于<p到/p>為止

<p class="title"><b>The Dormouse's story</b></p>

7.屬性print(soup.p["class"])打印結(jié)果
第一個(gè)P標(biāo)簽中'class'的內(nèi)容,把class=‘title’中賦給class的內(nèi)容,字符串‘title’

['title']

8.屬性print(soup.a)打印結(jié)果
第一個(gè)a標(biāo)簽內(nèi)容起始于<a到/a>為止

<a class="sister"  id="link1">Elsie</a>

9.屬性print(soup.find_all('a'))打印結(jié)果
找到所有a標(biāo)簽并打印相關(guān)內(nèi)容

[<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'))打印結(jié)果
打印id=link3的標(biāo)簽結(jié)果

<a class="sister"  id="link3">Tillie</a>
  1. 屬性soup.select()

練習(xí)示例bs4_04.py,學(xué)習(xí)地址
【目標(biāo)】
通過(guò)采用soup.select()方法,遍歷html后獲得目標(biāo)內(nèi)容。
其中關(guān)鍵點(diǎn)在于,對(duì)于所需內(nèi)容的精準(zhǔn)定位,通過(guò)()內(nèi)的語(yǔ)句來(lái)實(shí)現(xiàn):

11.1 關(guān)鍵字class
對(duì)于html內(nèi)的內(nèi)容,可以通過(guò)class(賦值給關(guān)鍵字class的類名)來(lái)進(jìn)行定位
soup.select('.class的類名')

直接寫(xiě)成soup.select('.class')報(bào)錯(cuò),因?yàn)檎也坏侥繕?biāo)內(nèi)容

報(bào)錯(cuò)TypeError: 'NoneType' object is not callable.png

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()遍歷和定位的目標(biāo)是定位到類class對(duì)應(yīng)名稱中的內(nèi)容:上面html中 class=‘sister’目標(biāo)類名稱是sister格式,按照類名查找 sister

print(soup.select(".目標(biāo)類名稱"))

示例見(jiàn)下

#按照類名查找 sister 上面html中 class=‘sister’目標(biāo)類名稱是sister,格式是print(soup.select(".目標(biāo)類名稱"))
print('sister:*************************')
print(soup.select(".sister"))

比如上述例子 會(huì)打印處類=sister的內(nèi)容

sister:*************************
[<a class="sister"  id="link1">Elsie</a>, <a class="sister"  id="link2">Lacie</a>, <a class="sister"  id="link3">Tillie</a>]

參考文檔
1.確定遍歷目標(biāo)
2.根據(jù)不同目標(biāo)特性,找到語(yǔ)法格式

11.2 關(guān)鍵字id
按照id名稱查找 注意格式 print(soup.select("#目標(biāo)id名稱 "))。目標(biāo)是id=link3,則寫(xiě)成"#link3"

print('id=link3:*************************')
print(soup.select("#link3"))

打印結(jié)果:

[<a class="sister"  id="link3">Tillie</a>]

11.4 組合高級(jí)查找
按照id名稱查找 x標(biāo)簽中目標(biāo)id y 格式 print(soup.select("x #y"))

print('P標(biāo)簽id=link2:*************************')
print(soup.select("p #link2"))

打印結(jié)果:

P標(biāo)簽id=link2:*************************
[<a class="sister"  id="link2">Lacie</a>]

11.3 關(guān)鍵字標(biāo)簽
按照標(biāo)簽查找,注意目標(biāo)標(biāo)簽名稱

print('tag:*************************')
print(soup.select('a'))

打印結(jié)果:

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_allfind
3 通過(guò)css選擇器select()方法

2.2 BeautifulSoup :一些常用功能的使用和測(cè)試

點(diǎn)擊此處,很喜歡這位小姐姐的文風(fēng),可以靜下心閱讀

2.2.1 關(guān)于bs4的解析速度

1.仔細(xì)閱讀文檔后發(fā)現(xiàn),文檔解析器對(duì)速度至關(guān)重要!
2.安裝chardet模塊
如果沒(méi)有安裝chardet模塊,那么光一個(gè)網(wǎng)頁(yè)就要7秒?。。ò惭b方法自行度娘), 還不包括獲取網(wǎng)頁(yè)時(shí)間。然而試過(guò)后,如過(guò)山車一般:,安裝了chardet以后7秒變成了一瞬。
ps:然而,用了幾天后又變回了7秒,卸載了chardet又變回了一瞬間!

2.2.2 導(dǎo)入方式

BeautifulSoup升級(jí)到4以后,導(dǎo)入方法變了,如下:
from bs4 import BeautifulSoup

2.2.3 關(guān)于輸入文本格式

關(guān)于被解析文檔的編碼格式
1.官方說(shuō)無(wú)論被傳入什么編碼的文檔,都會(huì)被統(tǒng)一為unicode
2.實(shí)際上有時(shí)候我發(fā)現(xiàn),必須以u(píng)nicode傳入才能獲得正確結(jié)果,這里試驗(yàn)發(fā)現(xiàn),還真的是如此!必須傳入decode過(guò)的碼

    html_doc = open('test-Zhilian-list-page-sm1.html', 'r').read().decode('utf-8')
    # ^ 這個(gè)html文件其實(shí)是智聯(lián)招聘搜索頁(yè)的源碼,可以自己保存下來(lái)直接試一試。

如下圖,最簡(jiǎn)單一個(gè)爬蟲(chóng)示例。如果要用bs4,需要把參數(shù)the_pageread()后繼續(xù)轉(zhuǎn)換編碼格式decode('uft-8')

最簡(jiǎn)單一個(gè)爬蟲(chóng)示例.png

2.2.4 關(guān)于bs4的文檔解析器

又是一個(gè)大坑:bs升級(jí)到4后,實(shí)例化時(shí)需要明確指定文檔解析器,如:
soup = BeautifulSoup(html_doc, 'lxml')
坑的地方:
1.但是著名的lxml在這里就是個(gè)大坑啊,
2.因?yàn)樗鼤?huì)直接略過(guò)html所有沒(méi)寫(xiě)規(guī)范的tag,而不管人家多在乎那些信息
PS:因?yàn)檫@個(gè)解析器的事,我少說(shuō)也折騰了好幾個(gè)小時(shí)才找到原因吧。

【總結(jié)】記住,選擇 * html5lib*!效率沒(méi)查多少,最起碼容錯(cuò)率強(qiáng),不會(huì)亂刪你東西!
soup = BeautifulSoup(html_doc, 'html5lib')

5.# 關(guān)于bs4的輸出格式 #################
# prettify()官方解釋是一律輸出utf-8格式,
# 其實(shí)卻是unicode類型??!所以必須在prettify()里面指定編碼。

output = soup.prettify('utf-8')
print repr(output)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容