日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python版本回退_Python爬虫之BeautifulSoup解析之路

發布時間:2023/12/1 python 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python版本回退_Python爬虫之BeautifulSoup解析之路 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

上一篇分享了正則表達式的使用,相信大家對正則也已經有了一定的了解。它可以針對任意字符串做任何的匹配并提取所需信息。

但是我們爬蟲基本上解析的都是html或者xml結構的內容,而非任意字符串。正則表達式雖然很強大靈活,但是對于html這樣結構復雜的來說,寫pattern的工作量會大大增加,并且有任意一處出錯都得不到匹配結果,比較麻煩。

本篇將介紹一款針對html和xml結構,操作簡單并容易上手的解析利器—BeautifulSoup。

BeautifulSoup的介紹

第一次使用BeautifulSoup的時候就在想:這個名字有什么含義嗎?美味的湯?于是好信也在網上查了一下。

來看,官方文檔是這么解釋的:

BeautifulSoup:?We called him Tortoise because he taught us”

意思是我們叫他烏龜因為他教了我們,當然這里Tortoise是Taught us的諧音。BeautifulSoup這個詞來自于《愛麗絲漫游仙境》,意思是“甲魚湯”。上面那個官方配圖也是來自于《愛麗絲漫游仙境》,看來是沒跑了,估計是作者可能很喜歡這部小說吧,因而由此起了這個名字。

好,讓我們看看真正的BeautifulSoup是什么?

BeautifulSoup是Python語言中的模塊,專門用于解析html/xml,非常適合像爬蟲這樣的項目。它有如下幾個使其強大的特點:

它提供了幾個超級簡單的方法和Pythonic的語句來實現強大的導航、搜索、修改解析樹的功能。

它會自動把將要處理的文檔轉化為Unicode編碼,并輸出為utf-8的編碼,不需要你再考慮編碼的問題。

支持Python標準庫中的HTML解析器,還支持第三方的模塊,如 lxml解析器 。

BeautifulSoup的安裝

目前BeautifulSoup的最新發型版本是BeautifulSoup4,在Python中以bs4模塊引入。

博主使用的Python3.x,可以使用?pip3 install bs4?來進行安裝,也可以通過官方網站下載來安裝,鏈接:https://www.crummy.com/software/BeautifulSoup/,具體安裝步驟不在此敘述了。

以為安裝完了嗎?還沒有呢。

上面介紹BeautifulSoup的特點時說到了,BeautifulSoup支持Python標準庫的解析器html5lib,純Python實現的。除此之外,BeautifulSoup還支持lxml解析器,為了能達到更好的解析效果,建議將這兩個解析器也一并安裝上。

根據操作系統不同,可以選擇下列方法來安裝lxml:

$?apt-get?install?Python-lxml

$?easy_install?lxml

$?pip?install?lxml

另一個可供選擇的解析器是純Python實現的?html5lib?, html5lib的解析方式與瀏覽器相同,可以選擇下列方法來安裝html5lib:

$?apt-get?install?Python-html5lib

$?easy_install?html5lib

$?pip?install?html5lib

下面列出上面提到解析器的使用方法。

解析器使用方法

Python標準庫BeautifulSoup(markup, "html.parser")

lxml HTML解析器BeautifulSoup(markup, "lxml")

lxml HTML解析器BeautifulSoup(markup, ["lxml", ? "xml"])

BeautifulSoup(markup, "xml")

html5libBeautifulSoup(markup, "html5lib")

推薦使用lxml作為解析器,lxml是用C語言庫來實現的,因此效率更高。在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必須安裝lxml或html5lib, 因為那些Python版本的標準庫中內置的HTML解析方法不夠穩定。

BeautifulSoup的文檔對象創建

首先引入bs4庫,也就是BeautifulSoup在Python中的模塊。

from?bs4?import?BeautifulSoup

好了,我們來看一下官方提供的例子,這段例子引自《愛麗絲漫游記》。

html_doc?="""

The Dormouse's story

The Dormouse's story

Once upon a time there were three little sisters; and their names were

Elsie,

Lacie

andTillie;

and they lived at the bottom of a well.

...

"""

假設以上html_doc就是我們已經下載的網頁,我們需要從中解析并獲取感興趣的內容。

首先的首先,我們需要創建一個BeautifulSoup的文檔對象,依據不同需要可以傳入“字符串”或者“一個文件句柄”。

傳入“字符串”

soup = BeautifulSoup(html_doc)

傳入“文件句柄”,打開一個本地文件

soup = BeautifulSoup(open("index.html"))

文檔首先被轉換為Unicode,如果是解析html文檔,直接創建對象就可以了(像上面操作那樣),這時候BeautifulSoup會選擇一個最合適的解析器對文檔進行解析。

但同時,BeautifulSoup也支持手動選擇解析器,根據指定解析器進行解析(也就是我們安裝上面html5lib和lxml的原因)。

手動指定解析器如下:

soup = BeautifulSoup(html_doc, "lxml")

如果僅是想要解析HTML文檔,只要用文檔創建 BeautifulSoup?對象就可以了。Beautiful Soup會自動選擇一個解析器來解析文檔。但是還可以通過參數指定使用那種解析器來解析當前文檔。

BeautifulSoup?第一個參數應該是要被解析的文檔字符串或是文件句柄,第二個參數用來標識怎樣解析文檔。如果第二個參數為空,那么Beautiful Soup根據當前系統安裝的庫自動選擇解析器,解析器的優先數序: lxml, html5lib, Python標準庫。在下面兩種條件下解析器優先順序會變化:

要解析的文檔是什么類型: 目前支持, “html”, “xml”, 和 “html5”

指定使用哪種解析器: 目前支持, “lxml”, “html5lib”, 和 “html.parser”

BeautifulSoup的對象種類

Beautiful Soup將復雜HTML文檔轉換成一個復雜的樹形結構,每個節點都是Python對象,所有對象可以歸納為4種:Tag

NavigableString

BeautifulSoup

Comment

Tag就是html或者xml中的標簽,BeautifulSoup會通過一定的方法自動尋找你想要的指定標簽。查找標簽這部分會在后面“遍歷查找樹”和“搜索查找樹”中介紹,這里僅介紹對象。

soup = BeautifulSoup('Extremely bold')

tag=soup.b

type(tag)

>>>

Tag標簽下也有對象,有兩個重要的屬性對象:name和attributes。

Name

Name就是標簽tag的名字,以下簡單操作便可獲取。

tag.name

>>> u'b'

Attributes

我們都知道一個標簽下可能有很多屬性,比如上面那個標簽b有class屬性,屬性值為boldest,那么我們如何獲取這個屬性值呢?

其實標簽的屬性操作和Python中的字典操作一樣的,如下:

tag['class']

>>> u'boldest'

也可以通過“點”來獲取,比如:

tag.attrs

>>> {u'class': u'boldest'}

NavigableString是可遍歷字符串的意思,其實就是標簽內包括的字符串,在爬蟲里也是我們主要爬取的對象之一。

在BeautifulSoup中可以非常簡單的獲取標簽內這個字符串。

tag.string

>>> u'Extremely bold'

就這么簡單的完成了信息的提取,簡單吧。要說明一點,tag中包含的字符串是不能編輯的,但是可以替換。

tag.string.replace_with("No longer bold")

tag

>>>

No longer bold

BeautifulSoup對象表示的是一個文檔的全部內容。大部分時候,可以把它當作Tag對象。

soup.name

>>> u'[document]'

BeautifulSoup對象不是一個真正的tag,沒有name和attributes,但是卻可以查看它的name屬性。如上所示,“[document]”為BeautifulSoup文檔對象的特殊屬性名字。

還有一些對象也是我們需要特殊注意的,就是注釋。其實comment對象是一個特殊類型的NavigableString對象,請看下面。

markup =?""

soup = BeautifulSoup(markup)

comment?=?soup.b.string

type(comment)

>>>

comment

>>> u'Hey, buddy. Want to buy a used parser'

這和NavigableString的使用是一樣,同樣使用?.string?對標簽內字符串進行提取。但是,請看上面comment這個例子,里面字符串是一個comment,有這樣的格式,一樣使用了?.string對其進行提取,得到的結果是去掉了comment標志的里面的字符串。這樣的話,當我們并不知道它是否是comment,如果得到以上的結果很有可能不知道它是個comment。

因此,這可能會讓我們得到我們不想要的comment,擾亂我們的解析結果。

為了避免這種問題的發生,可以在使用之前首先通過以下代碼進行一個簡單的判斷,然后再進行其它操作。

iftype(soup.b.string)==bs4.element.Comment:

print(soup.b.string)

BeautifulSoup的遍歷文檔樹

仍然用最開始的《愛麗絲》中的一段話作為例子。

子節點

子節點有?.contents?和?.children?兩種用法。

contents

content屬性可以將標簽所有子節點以列表形式返回。

#

The Dormouse's story

print(soup.head.contents)

>>> [title>The Dormouse's story]

這樣就可以返回一個子節點標簽了。當然你也可以通過soup.title來實現,但是當文檔結構復雜的時候,比如有不止一個title的話,那這樣就不如contents使用來的快了。

head下只有一個標簽title,那么如果我們查看一下body下的子標簽。

print(soup.body.contents)

>>>

['\n',

The Dormouse's story

, '\n',

Once upon a time there were three little sisters; and their names were

Elsie,

Lacie

andTillie;

and they lived at the bottom of a well.

, '\n',

...

, '\n']

你會發現這些子節點列表中有很多“\n”,這是因為它把空格包括進去了,所以這里需要注意一下。

children

也可以通過?.chidren?得到相同的結果,只不過返回的children是一個生成器(generator),而不是一個列表。

print(soup.body.children)

>>>

看到這是一個生成器,因此我們可以for..in..進行遍歷,當然也可以得到以上同樣的結果。

forchildinsoup.body.children:?print(child)

子孫節點

子孫節點使用.descendants屬性。如果子節點可以直接獲取標簽的直接子節點,那么子孫節點則可以獲取所有子孫節點,注意說的是所有,也就是說孫子的孫子都得給我找出來,下用面開一個例子。

for?child?in?head_tag.descendants:?? ?print(child)

>>>

The Dormouse's story

>>> The Dormouse's stor

title是head的子節點,而title中的字符串是title的子節點,title和title所包含的字符串都是head的子孫節點,因此被循環遞歸的查找出來。.descendants?的用法和?.children?是一樣的,會返回一個生成器,需要for..in..進行遍歷。

父節點

父節點使用?.parents?屬性實現,可以得到父輩的標簽。

title_tag?=?soup.title

title_tag

>>>

The Dormouse's story

title_tag.parent

>>>

The Dormouse's story

title_tag.parent.name

>>> head

獲得全部父節點則使用.parents屬性實現,可以循環得到所有的父輩的節點。

link?=?soup.a

for?parent?in?link.parents:?? ?if?parent?is?None:?? ? ? ?print(parent)?? ?else:?? ? ? ?print(parent.name)

>>>

p

body

html

[document]

None

可以看到a節點的所有父輩標簽都被遍歷了,包括BeautifulSoup對象本身的[document]。

兄弟節點

兄弟節點使用.next_sibling和.previous_sibling屬性。

兄弟嘛,不難理解自然就是同等地位的節點了,其中next_sibling 獲取下一個兄弟節點,而previous_sibling 獲取前一個兄弟節點。

a_tag?=?soup.find("a",?id="link1")

a_tag.next_sibling

>>> ,

a_tag.previous_element

>>>

Once upon a time there were three little sisters; and their names were

兄弟節點可以通過?.next_siblings?和?.previous.sibling?獲取所有前后兄弟節點,同樣需要遍歷獲取每個元素。

回退和前進

當然還有一些其它用法,如回退和前進.next_element和.previous_element,它是針對所有節點的回退和前進,不分輩分。

a_tag?=?soup.find("a",?id="link1")

a_tag

>>>

Elsie,

a_tag.next_element

>>> Elsie

a_tag.previous_element

>>>

Once upon a time there were three little sisters; and their names were

因為使用了回退,將會尋找下一個節點對象而不分輩分,那么這個標簽的下一個節點就是它的子節點Elsie,而上一個節點就是上一個標簽的字符串對象。find用法會在后續搜索文檔樹里面詳細介紹。

回退和前進也可以尋找所有的前后節點,使用.next_elements和.previous_elements。

for?elem?in?last_a_tag.next_elements:

if?elem.nameisNone:continue

print(elem.name)

>>>

a

a

p

返回對象同樣是生成器,需要遍歷獲得元素。其中使用了if判斷去掉了不需要的None。

節點內容

前面提到過NavigableString對象的?.string?用法,這里在文檔遍歷再次體會一下其用法。

如果tag只有一個NavigableString?類型子節點,那么這個tag可以使用.string得到子節點,就像之前提到的一樣。而如果一個tag里面僅有一個子節點(比如tag里tag的字符串節點),那么這個tag也可以使用.string方法,輸出結果與當前唯一子節點的.string結果相同(如上所示)。

title_tag.string

>>> u'The Dormouse's story'

head_tag.contents

>>> [

The Dormouse's story]

head_tag.string

>>> u'The Dormouse's story'

但是如果這個tag里面有多個節點,那就不靈了。因為tag無法確定該調用哪個節點,如下面這種。

print(soup.html.string)

>>> None

如果tag中包含多個字符串,可以使用?.strings?來循環獲取,輸出的字符串中可能包含了很多空格或空行,使用.stripped_strings可以去除多余空白內容。

上面提介紹的都是如何遍歷各個節點,下面我們看看如何搜索我們我們真正想獲取的內容,如標簽屬性等。

BeautifulSoup的搜索文檔樹

搜索文檔樹有很多種用法,但使用方法都基本一致。這里只選擇介紹一種.find_all。

find_all()

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

find_all()?方法可以搜索當前標簽下的子節點,并會經過過濾條件判斷是否符合標準,先隨便看個例子。

soup.find_all("a")

>>>

[Elsie,

Lacie,

Tillie]

soup.find_all(id="link2")

>>>

[Lacie]

通過以上例子,可以發現,我們只要設定好我們的過濾條件,便可輕松的解析我們想要的內容。這些條件如何設定呢?

就是通過find_all()的這些參數來設置的,讓我們來看看。

Name參數

name參數就是標簽的名字,如上面的例子尋找所有標簽,name參數可以是字符串、True、正則表達式、列表、甚至具體方法。

下面舉個正則表達式的例子。

importre

soup?=BeautifulSoup(html_doc,?'lxml')fortag?insoup.find_all(re.compile("^t")):print(tag.name)

>>>?title

可以看到正則表達式的意思是匹配任何以“t”開頭的標簽名稱,就只有title一個。

使用“True”會匹配任何值,使用“列表”會匹配列表中所有的標簽項,如果沒有合適的過濾條件,還可以自定義一個“方法”。

Keyword參數

就如同Python中的關鍵字參數一樣,我們可以搜索指定的標簽屬性來定位標簽。

soup.find_all(id='link2')

>>>

[Lacie]

找到了id屬性為link2的標簽。

soup.find_all(href=re.compile("elsie"))

>>>

[Elsie]

找到了href屬性里含有“elsie”字樣的標簽。

也可以同時定義多個關鍵字條件來過濾匹配結果。

soup.find_all(href=re.compile("elsie"),?id='link1')

>>>

[three]

text參數

通過text參數可以搜索匹配的字符串內容,與name的用法相似,也可以使用字符串、True、正則表達式、列表、或者具體方法。

soup.find_all(text="Elsie")>>> [u'Elsie']

soup.find_all(text=re.compile("Dormouse")) >>>

[u"The Dormouse's story", u"The Dormouse's story"]

limit參數

limit參數可以限制返回匹配結果的數量,看下面這個例子。

soup.find_all("a",?limit=2)

>>>

[Elsie,

Lacie]

文檔中本來有三個標簽,但是通過限制只得到了兩個。

recursive參數

find_all()會尋找符合匹配條件的所有子孫節點,如果我們只想找直接的子節點,就可以設置recursive參數來進行限制,recursive=False。

soup.html.find_all("title")

>>> [

The Dormouse's story]

soup.html.find_all("title",?recursive=False)

>>> [ ]

上面是兩種使用recursive和沒有使用recursive的情況,可以發現它的作用。

以上就是find_all()所有參數的介紹,其它方法如find(),find_parents()等更多方法與find_all()基本一致,可以舉一反三。

總結

以上就是BeautifulSoup的使用方法介紹,主要記住三個部分內容:

BeautifulSoup對象種類

BeautifulSoup的遍歷文檔樹

BeautifulSoup的搜索文檔樹

總結

以上是生活随笔為你收集整理的python版本回退_Python爬虫之BeautifulSoup解析之路的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。