python爬蟲學習筆記-使用BeautifulSoup解析html
之前抓取豆瓣圖書Top250的時候,獲取內容使用的方法是正則表示式匹配,看上去是一種比較簡潔的方法,但問題在於,正則表示式的編寫必須非常細心,一旦出了任何小問題,就會導致得不到想要的結果。熟悉html的話,不難想到可以利用節點之間的結構和層級關係來作區分並進一步獲取節點內想要的文字。
於是BeautifulSoup庫為我們實現了這種更加直接的匹配方法,BeautifulSoup是一個python的HTML或XML解析庫,可以方便地從頁面中提取資料,它自動的將輸入的文件轉換為Unicode編碼,輸出文件轉換為UTF-8編碼,不需要考慮編碼方式。
BeautifulSoup在工作時,其實是依賴於解析器來解析文字的,除開python標準庫中的解析庫外,我們一般使用lxml這個庫來實現解析。
下面以豆瓣電影為例項介紹其用法:
為了例子的簡潔,這裡我們只抓取豆瓣電影排名的首頁資訊,其url為"https://movie.douban.com/top250",我們先使用requests庫獲取頁面資訊,程式碼如下:
url="https://movie.douban.com/top250"
headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36'}
r=requests.get(url,headers= headers).text
在文字總檢視包含我們需要獲取資訊的那部分html程式碼,這裡我們獲取資訊包括電影名稱,簡介,評分以及評價,抓取的html程式碼如下:
<div class="item">
<div class="pic">
<em class="">4</em>
<a href="https://movie.douban.com/subject/1292720/">
< img width="100" alt="阿甘正傳" src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p510876377.jpg" class="">
</a>
</div>
<div class="info">
<div class="hd">
<a href="https://movie.douban.com/subject/1292720/" class="">
<span class="title">阿甘正傳</span>
<span class="title"> / Forrest Gump</span>
<span class="other"> / 福雷斯特·岡普</span>
</a>
<span class="playable">[可播放]</span>
</div>
<div class="bd">
<p class="">
導演: Robert Zemeckis 主演: Tom Hanks / Robin Wright Penn / Gary Sinise<br>
1994 / 美國 / 劇情 愛情
</p>
<div class="star">
<span class="rating45-t"></span>
<span class="rating_num" property="v:average">9.4</span>
<span property="v:best" content="10.0"></span>
<span>948433人評價</span>
</div>
<p class="quote">
<span class="inq">一部美國近現代史。</span>
</p>
</div>
</div>
</div>
</li>
<li>
分析發現,所有要抓取的資訊都在標籤
中,所以需要做的第一步就是在整個頁面的HTML程式碼中匹配到這個標籤,BeautifulSoup提供一個find_all()方法來實現,即查詢所有符合條件的元素,給它傳入一些屬性或文字,就可以得到符合條件的元素,程式碼如下:alla=soup.find_all('div',class_='item')
這裡我們就得到了
內的所有內容,真正所要抓取的資訊都包含在裡面,下一步就是在alla物件中找出其它符合條件的標籤並獲取其內容,所以我們可以遍歷alla物件,並利用另一個fing()方法來獲取內容,與find_all()不同,find()方法只返回單個元素,即匹配到第一個符合條件的元素即返回,而find_all()返回的是所有符合條件元素組成的列表。首先我們嘗試抓取電影名稱資訊,對應的html單獨拿出來為:
<span class="title">阿甘正傳</span>
這個的獲取就很容易,就是在標籤內的文字,抓取程式碼如下:
for allo in alla:
#name=allo.find('img').get('alt')
name=allo.find('span',class_="title").get_text()
剩下的簡介以及評分和name獲取方法相同,程式碼為:
for allo in alla:
#name=allo.find('img').get('alt')
name=allo.find('span',class_="title").get_text()
infor=allo.find('p',class_="").get_text().strip()
#print(infor)
score=allo.find('span',class_="rating_num").get_text()
#print(score)
address=allo.find('img').get('src')
#print(address)
con=allo.find('span', class_="inq").get_text()
#print(con)
這樣我們就獲取全部所需要的資訊。但其實有一個比較不一樣的標籤資訊我們沒有提取,就是影片對應的圖片,它的html程式碼為:
<img width="100" alt="阿甘正傳" src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p510876377.jpg" class="">
我們發現之前的辦法不能使用了,我們要獲取的是img標籤下src後面的內容,型號BeutifulSoup提供了get()方法,可以提取標籤內其他屬性的文字資訊,程式碼為:
pic=allo.find('img').get('src')
這裡我們還是先找到對應的img標籤,然後利用get()方法來獲取"src"對應的文字內容。
這樣內容獲取大功告成,最後我們將它們儲存到文字中,程式碼如下:
with open ('doubanfilm250.txt','a',encoding='utf-8')as f:
f.write('\n'.join([name,infor,score,con]))
f.write('\n'+'*'*50+'\n')
這裡我們使用join方法對所獲取的四部分資訊進行構造,並新增換行符即’*'作為分割,最後文字儲存效果為: