天天看點

python爬蟲之Beautiful Soup庫,基本使用以及提取頁面資訊

作者:運維筆記ywbj

一、Beautiful Soup簡介

爬蟲正規表達式參考我上一篇文章:Python 爬蟲正規表達式和re庫

在爬蟲過程中,可以利用正規表達式去提取資訊,但是有些人覺得比較麻煩。因為花大量時間分析正規表達式。這時候可以用高效的網頁解析庫Beautiful Soup。

Beautiful Soup 是一個HTML/XML 的解析器,主要用于解析和提取 HTML/XML 資料。

Beautiful Soup支援Python标準庫中的HTML解析器,還支援一些第三方的解析器,如果我們不安裝它,則 Python 會使用 Python預設的解析器,lxml 解析器更加強大,速度更快,推薦安裝。

下面是各種解析器優缺點

python爬蟲之Beautiful Soup庫,基本使用以及提取頁面資訊

二、Beautiful Soup 安裝

Beautiful Soup 3 目前已經停止開發,推薦在現在的項目中使用Beautiful Soup 4,不過它已經被移植到BS4了,也就是說導入時我們需要 import bs4。

安裝Beautiful Soup

pip install beautifulsoup4           

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

apt-get install Python-lxml

easy_install lxml

pip install lxml           

建立對象時,指定解析器,這裡為lxml

from bs4 import BeautifulSoup

bs = BeautifulSoup(html,"lxml")           

三、Beautiful Soup 使用

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

(1)Tag

标簽,最基本的資訊組織單元,分别用<>和标明開頭和結尾,通俗點講就是 HTML 中的一個個标簽。

Tag有很多方法和屬性,tag中最重要的屬性: name和attributes。

name:

每個tag都有自己的名字,通過 .name 來擷取:

慣例,同樣以豆瓣電影排行做分析,連結為:https://movie.douban.com/top250

python爬蟲之Beautiful Soup庫,基本使用以及提取頁面資訊
import requests
from bs4 import BeautifulSoup

headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/65.0.3325.162 Safari/537.36'}
url='https://movie.douban.com/top250'

req=requests.get(url,headers=headers)

html=req.text
#print(req.text)

soup=BeautifulSoup(html,'lxml')
print(soup.h1)
print(soup.a)           

執行結果:

<h1>豆瓣電影 Top 250</h1>  
<a class="nav-login" href="https://accounts.douban.com/passport/login?source=movie" rel="nofollow">登入/注冊</a>           

以上,就直接提取到标簽h1和a 的内容了,之是以隻有一個,因為隻提取第一個比對到的内容。

Attributes:

屬性,一個tag可能有很多個屬性, . tag的屬性的操作方法與字典相同。

如上:ol class="grid_view" 的屬性, 标簽名為ol,屬性為class,屬性值為:grid_view

import requests
from bs4 import BeautifulSoup

headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/65.0.3325.162 Safari/537.36'}
url='https://movie.douban.com/top250'

req=requests.get(url,headers=headers)

html=req.text
#print(req.text)

soup=BeautifulSoup(html,'lxml')
#擷取标簽div所有屬性,得到的是一個字典
print(soup.div.attrs)
#擷取标簽ol屬性為class的值
print(soup.ol['class'])           

執行結果:

{'id': 'db-global-nav', 'class': ['global-nav']} 
['grid_view']           

因為是字典屬性,是以tag的屬性可以被添加,删除或修改。不過,對于修改删除的操作,不是我們的主要用途,有需要的自行參考官方文檔。

(2)NavigableString

直譯為:可以周遊的字元串,通過名稱可知,得到字元串。

标簽内非屬性字元串,格式:soup.\<tag>.string, NavigableString可以跨越多個層次。

如,得到了标簽的内容,要想擷取标簽内部的文字,用 .string 即可。

上面代碼改為:

print(soup.h1.string)           

執行結果:

豆瓣電影 Top 250           

(3)BeautifulSoup

BeautifulSoup 對象表示的是一個文檔的全部内容.大部分時候,可以把它當作 Tag 對象,是一個特殊的 Tag,我們可以分别擷取它的類型,名稱。

print(soup.name)           

執行結果:

[document]           

(4)Comment

注釋及特殊字元串,Tag , NavigableString , BeautifulSoup 幾乎覆寫了html和xml中的所有内容,但是還有一些特殊對象.容易讓人擔心的内容是文檔的注釋部分:

from bs4 import BeautifulSoup

markup = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
soup = BeautifulSoup(markup)
comment = soup.b.string
print(type(comment))
print(comment)           

執行結果:

<class 'bs4.element.Comment'>
Hey, buddy. Want to buy a used parser?           

四、周遊文檔樹

HTML基本格式:<>…</>構成了所屬關系,周遊形成了标簽的樹形結構。

是以有時候不能做到一步就得到想要的元素,需要先選中一個元素再以它為基準再選擇它的子節點,父節點,兄弟節點等。

(1)子節點和子孫節點

子節點屬性:.contents .children

.content

tag 的 .content 屬性可以将tag的子節點以清單的方式輸出

import requests
from bs4 import BeautifulSoup

headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko)Chrome/65.0.3325.162 Safari/537.36'}
url='https://movie.douban.com/top250'

req=requests.get(url,headers=headers)

html=req.text
#print(req.text)

soup=BeautifulSoup(html,'lxml')
print(soup.ol.contents)           

執行結果:

['\n', <li>
<div class="item">
<div class="pic">
<em class="">1</em>
<a href="https://movie.douban.com/subject/1292052/">
<img alt="肖申克的救贖" class="" src="https://img9.doubanio.com/view/photo/s_ratio_poster/public/p480747492.jpg" width="100"/>
</a>
</div> 
<div class="info">
...           

輸出方式為清單,是以可以用清單索引來擷取它的某一個元素。

print(soup.ol.contents[1])           

.children

傳回的不是一個 list,不過我們可以通過周遊擷取所有子節點。

print(soup.ol.children)           

執行結果:

<list_iterator object at 0x7fbf14fbc4c0>           

列印輸出 .children ,可以發現它是一個 list 生成器對象,是以需要周遊一下擷取内容。

for child in soup.ol.children:
    print(child)           

輸入内容和.content差不多。

子孫節點.descendants

如果要獲得所有的子孫節點的話,可以調用descendants屬性,傳回結果還是生成器,是以需要周遊一下輸出可以看見span節點

print(soup.ol.descendants)
#print(soup.ol.children)
for child in soup.ol.descendants:
    print(child)           

descendants會遞歸查詢所有子節點,得到所有的子孫節點。

(2)父節點和祖父節點

擷取父節點.parent

print(soup.ol.parent)           

擷取所有祖先節點,同理需要周遊擷取。

for parent in soup.ol.parents:
    print(parent)           

(3)兄弟節點

擷取兄弟節點:.next_sibling 和 .previous_sibling

next_sibling和previous_sibling分别擷取節點的下一個和上一個兄弟元素。

print(soup.li.next_sibling)
print(soup.li.previous_sibling)           

如果節點不存在,則傳回 None,實際中通常是字元串或空白,因為空白或者換行也可以被視作一個節點,是以得到的結果可能是空白或者換行。

全部兄弟節點:next_siblings 和 previous_siblings

分别傳回後面和前面的兄弟節點,同理,所有節點需要周遊獲得。

print(soup.li.next_siblings)
print(soup.li.previous_siblings)

for sibling in soup.li.next_siblings:
    print(sibling)
for previous in soup.li.previous_siblings:
    print(previous)           

(4)回退和前進節點

前後節點:.next_element 和 .previous_element

與 .next_sibling .previous_sibling 不同,它并不是針對于兄弟節點,而是在所有節點,不分層次

比如 head 節點為

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

那麼它的下一個節點便是 title,它是不分層次關系的。

所有前後節點:.next_elements 和 .previous_elements

同理,傳回的是疊代器,需要周遊獲得。

五、搜尋文檔樹

eautiful Soup定義了很多搜尋方法,主要用的2個方法:find() 和 find_all()

(1)find_all

文法:find_all(name, attrs, recursive, text, **kwargs)

name:

我們可以根據節點名來查詢元素。name可以是:字元串、正規表達式、清單、True、方法

print(soup.find_all('a'))           

因為是Tag類型,我們可以進行嵌套查詢.

for a in soup.find_all('a'):
    print(a.find_all('span'))
    print(a.string)           

attrs

除了根據節點名查詢的話,同樣的也可以通過屬性來查詢。

print(soup.find_all(attrs={'id': 'link1'}))
print(soup.find_all(attrs={'name': 'Dormouse'}))           

常用的屬性比如class,我們可以直接傳入class這個參數。在這裡需要注意的是class是Python的保留字,是以在class的後面加上下劃線。

print(soup.find_all(class_="title"))           

執行結果:

<span class="title">肖申克的救贖</span>, <span class="title"> / The Shawshank Redemption</span>, <span class="title">霸王别姬</span>, <span class="title">阿甘正傳</span>           

(2)find

除了find_all( )方法,還有find( )方法,前者傳回的是多個元素,以清單形式傳回,字尾是傳回一個元素。即第一個元素。

find( )與find_all( )的使用方法相同。

find_parents() 和find_parent():前者傳回所有祖先節點,後者傳回直接父節點。

find_next_siblings()和find_next_sibling():前者傳回後面的所有兄弟節點,後者傳回後面第一個兄弟節點。

find_previous_siblings和find_previous_sibling():前者傳回前面的所有兄弟節點,後者傳回前面第一個兄弟節點。

六、CSS選擇器

Beautiful Soup還提供了另一種選擇器,即CSS選擇器。

soup.select(),傳回類型是 list。

同樣可以用 标簽名、類名、 id 名、組合、屬性查找。

(1)soup.select()

擷取title标簽節點
print(soup.select('title'))

擷取class為title的節點
print(soup.select('.title'))

擷取li标簽下的a節點
print(soup.select('li a'))

查找時還可以加入屬性元素,屬性需要用中括号括起來,
注意屬性和标簽屬于同一節點,是以中間不能加空格,否則會無法比對到
print soup.select('a[href="http://example.com/elsie"]')           

(2)嵌套選擇

同樣可以使用嵌套查詢

for ul in soup.select('ul'):
    print(ul.select('li'))           

(3)擷取屬性

for ul in soup.select('ul'):
    print(ul['id'])
    print(ul.attrs['id'])           

(4)擷取文本

for li in soup.select('li'):
    print('String:', li.string)
    print('get text:', li.get_text())           

七、擷取豆瓣電影排行首頁影片資訊

通過以上的方法,現在擷取豆瓣電影排行首頁的排名、電影名、導演演員、年份類型。

python爬蟲之Beautiful Soup庫,基本使用以及提取頁面資訊

從頁面分析,所有影片資訊,在class标簽值為grid_view的裡面。

是以第一步擷取所有grid_view裡面所有li标簽的值,傳回的是一個清單。

list= soup.find(class_='grid_view').find_all('li')           

排序,在清單每個元素中,擷取em标簽值,為排序,隻取字元串。

find('em').string           

電影名稱,擷取第一個title值

find(class_='title').string           

導演和年代資訊,在标簽p當中,擷取的是text文本格式。由于中間有空格,還有br換行符,是以最後還需要replace替換掉。

item.find('p').text.replace(' ','')           

最終代碼為:

url='https://movie.douban.com/top250'

req=requests.get(url,headers=headers)

html=req.text
#print(req.text)
soup=BeautifulSoup(html,'lxml')

list= soup.find(class_='grid_view').find_all('li')

for item in list:
    item_num=item.find('em').string
    item_name=item.find(class_='title').string
    item_act=item.find('p').text.replace(' ','')
    print("排名:"+item_num,"\n電影名稱:"+item_name,item_act)           

執行結果:

排名:1 
電影名稱:肖申克的救贖 
導演:弗蘭克·德拉邦特FrankDarabont   主演:蒂姆·羅賓斯TimRobbins/...
1994 / 美國 / 犯罪劇情

排名:2 
電影名稱:霸王别姬 
導演:陳凱歌KaigeChen   主演:張國榮LeslieCheung/張豐毅FengyiZha...
1993 / 中國大陸中國香港 / 劇情愛情同性

排名:3 
電影名稱:阿甘正傳 
導演:羅伯特·澤米吉斯RobertZemeckis   主演:湯姆·漢克斯TomHanks/...
1994 / 美國 / 劇情愛情

排名:4 
電影名稱:泰坦尼克号 
導演:詹姆斯·卡梅隆JamesCameron   主演:萊昂納多·迪卡普裡奧Leonardo...
1997 / 美國墨西哥澳洲加拿大 / 劇情愛情災難

排名:5 
電影名稱:這個殺手不太冷 
導演:呂克·貝松LucBesson   主演:讓·雷諾JeanReno/娜塔莉·波特曼...
1994 / 法國美國 / 劇情動作犯罪

排名:6 
電影名稱:美麗人生 
導演:羅伯托·貝尼尼RobertoBenigni   主演:羅伯托·貝尼尼RobertoBeni...
1997 / 意大利 / 劇情喜劇愛情戰争

排名:7 
電影名稱:千與千尋 
導演:宮崎駿HayaoMiyazaki   主演:柊瑠美RumiHîragi/入野自由Miy...
2001 / 日本 / 劇情動畫奇幻

排名:8 
電影名稱:辛德勒的名單 
導演:史蒂文·斯皮爾伯格StevenSpielberg   主演:連姆·尼森LiamNeeson...
1993 / 美國 / 劇情曆史戰争

排名:9 
電影名稱:盜夢空間 
導演:克裡斯托弗·諾蘭ChristopherNolan   主演:萊昂納多·迪卡普裡奧Le...
2010 / 美國英國 / 劇情科幻懸疑冒險

排名:10 
電影名稱:星際穿越 
導演:克裡斯托弗·諾蘭ChristopherNolan   主演:馬修·麥康納MatthewMc...
2014 / 美國英國加拿大 / 劇情科幻冒險

排名:11 
電影名稱:忠犬八公的故事 
導演:萊塞·霍爾斯道姆LasseHallström   主演:理查·基爾RichardGer...
2009 / 美國英國 / 劇情

排名:12 
電影名稱:楚門的世界 
導演:彼得·威爾PeterWeir   主演:金·凱瑞JimCarrey/勞拉·琳妮Lau...
1998 / 美國 / 劇情科幻

排名:13 
電影名稱:海上鋼琴師 
導演:朱塞佩·托納多雷GiuseppeTornatore   主演:蒂姆·羅斯TimRoth/...
1998 / 意大利 / 劇情音樂

排名:14 
電影名稱:三傻大鬧寶萊塢 
導演:拉庫馬·希拉尼RajkumarHirani   主演:阿米爾·汗AamirKhan/卡...
2009 / 印度 / 劇情喜劇愛情歌舞

排名:15 
電影名稱:機器人總動員 
導演:安德魯·斯坦頓AndrewStanton   主演:本·貝爾特BenBurtt/艾麗...
2008 / 美國 / 科幻動畫冒險

排名:16 
電影名稱:放牛班的春天 
導演:克裡斯托夫·巴拉蒂ChristopheBarratier   主演:讓-巴蒂斯特·莫尼...
2004 / 法國瑞士德國 / 劇情喜劇音樂

排名:17 
電影名稱:無間道 
導演:劉偉強/麥兆輝   主演:劉德華/梁朝偉/黃秋生
2002 / 中國香港 / 劇情犯罪驚悚

排名:18 
電影名稱:瘋狂動物城 
導演:拜倫·霍華德ByronHoward/瑞奇·摩爾RichMoore   主演:金妮弗·...
2016 / 美國 / 喜劇動畫冒險

排名:19 
電影名稱:大話西遊之大聖娶親 
導演:劉鎮偉JeffreyLau   主演:周星馳StephenChow/吳孟達ManTatNg...
1995 / 中國香港中國大陸 / 喜劇愛情奇幻古裝

排名:20 
電影名稱:熔爐 
導演:黃東赫Dong-hyukHwang   主演:孔侑YooGong/鄭有美Yu-miJung/...
2011 / 南韓 / 劇情

排名:21 
電影名稱:控方證人 
導演:比利·懷爾德BillyWilder   主演:泰隆·鮑華TyronePower/瑪琳·...
1957 / 美國 / 劇情犯罪懸疑

排名:22 
電影名稱:教父 
導演:弗朗西斯·福特·科波拉FrancisFordCoppola   主演:馬龍·白蘭度M...
1972 / 美國 / 劇情犯罪

排名:23 
電影名稱:當幸福來敲門 
導演:加布裡爾·穆奇諾GabrieleMuccino   主演:威爾·史密斯WillSmith...
2006 / 美國 / 劇情傳記家庭

排名:24 
電影名稱:觸不可及 
導演:奧利維·那卡什OlivierNakache/艾力克·托蘭達EricToledano   主...
2011 / 法國 / 劇情喜劇

排名:25 
電影名稱:怦然心動 
導演:羅伯·萊納RobReiner   主演:瑪德琳·卡羅爾MadelineCarroll/卡...
2010 / 美國 / 劇情喜劇愛情           

八、小結

推薦使用lxml解析庫,必要時選擇html.parser。相對于正規表達式,Beautiful Soup更加簡單,但是網上有些推薦正規表達式,理由是精确。

具體用哪個,還是根據環境選擇吧,一起使用都可以。