01_7爬蟲網頁_BS4

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.下載和安裝

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

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

2.使用Python setup.py install安裝

使用Python setup.py install安裝報錯,是因為進入當下路徑文件夾后,無steup.py文件可供安裝。調整1和2步驟,下載最新bs4包4.6版本,進入steup.py文件夾中

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

執行命令python setup.py install,正常進入安裝流程

安裝bs4_1.png

安裝bs4_2.png

3.進入python,使用from bs4 import BeautifulSoup查看是否正常

from bs4 import BeautifulSoup_報錯.png

查找上述報錯解決方法,因為使用python3.6版本,需更換庫,把python2的庫升級為python3的庫
具體:將bs4文件夾和2to3.py同時放到lib中,然后在cmd中定位到lib,運行:2to3.py bs4 -w就好了


2to3.py bs4 -w.png

之后運行報錯,操作異常,確認后發現,將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命令

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

進入python,使用from bs4 import BeautifulSoup查看是否正常


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

二、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'))
  1. 屬性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>
  1. 屬性soup.select()

練習示例bs4_04.py,學習地址
【目標】
通過采用soup.select()方法,遍歷html后獲得目標內容。
其中關鍵點在于,對于所需內容的精準定位,通過()內的語句來實現:

11.1 關鍵字class
對于html內的內容,可以通過class(賦值給關鍵字class的類名)來進行定位
soup.select('.class的類名')

直接寫成soup.select('.class')報錯,因為找不到目標內容

報錯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()遍歷和定位的目標是定位到類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_allfind
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_pageread()后繼續轉換編碼格式decode('uft-8')

最簡單一個爬蟲示例.png

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)
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容