前言
還記得前面分享過怎麼透過Python Requests套件來自動化爬取網頁下來嗎?忘記或是還沒看過前面介紹的朋友們為你們附上傳送門:
➡️ Python 網路爬蟲Web Crawler教學 — 資料結構複習+Requests篇
➡️ 用Postman+Requests輕鬆學網路爬蟲
當時我們是透過印出res.text
的方式來解析網站,但其實這樣不夠方便,因為會把html中全部的資料都爬取出來,而一般的爬蟲可能只需要抓取特定的資料,這時候就有一些方便的套件可以用,今天要介紹大家最常用的BS4!另外還有像是Pyquery也相當方便,改天有空也會在做這個套件的補充~
前置作業
跟其他的套件一樣,使用之前都要下載一下,只要打開你的terminal,輸入下面的指令,就完成啦!
pip3 install bs4
再來,跟大家分享一下html的組成是什麼,如果了解html的架構,之後的爬蟲也會得心應手的!
從上圖可以看到有個以<a>為起點,</a>為終點的元素,並且在這個元素中有個href(超連結)的屬性在裡面,而這個元素的內容則是夾在起始標籤跟結束標籤中。大概有個了解之後,我們就開始爬蟲吧~
開始爬蟲
首先我們先透過requests套件來爬取html,然後透過bs4來解析,記得要import requests跟bs4這兩個套件!然後這邊我們這邊用ptt八卦版來做範例。
import requests
from bs4 import BeautifulSoupurl = "https://www.ptt.cc/bbs/Beauty/index.html"
res = requests.get(url,cookies = {'over18':'1'})
#記得八卦版要over18=1這個cookies!Soup = BeautifulSoup(res.text,'html.parser')
BeautifulSoup的用法是要放入兩個參數,第一個參數就是一個檔案,像是我們透過requests套件讀取的html,並轉成text的格式這樣就可以了。第二個則是透過不同的解析方式,比較常用的是html.parser的方式,就如同字面上的意思是解析html檔案。另外解析方式還有lxml、html5lib等方式,詳細差異可以參考Document。接著我們把剛剛解析的實例存到Soup這個變數裡面,之後要做任何的讀取與解析都透過Soup來運作了。讓我們接著看下去~
基礎用法
讀取網站標題
我們現在可以假想,Soup這個變數裡面有整個html的資料,我們可以透過一些簡單的程式碼就可以把想要讀取的資料給拿出來了。
print(Soup.title) #可以讀取的網頁的title
<title>看板 Beauty 文章列表 - 批踢踢實業坊</title>
其實呢,這個用法就是把html結構中,藏在<head><title>之下的標題給解析出來,也就是一般網站看到的標題啦。但可以看到透過剛剛的方法解析是把整個標籤都給擷取下來啦!這時候只要加上.text
或是.string
就可以將裡面的字串或是純文字給解析出來了。
print(Soup.title.text)
看板 Beauty 文章列表 - 批踢踢實業坊
尋找標籤
在前面有提到,html的組成是起始標籤+結束標籤合成的元素,我們的爬蟲程式,就是去找對應的元素在哪裡,並且把裡面的內容給讀出,這時候就要跟大家介紹下面的用法。
接著我們來找到八卦版的標題為範例:
首先,我們透過檢查可以發現標題們都藏在class=’r-ent’
的元素裡面,接著先來找第一個標題,這時可以透過find的方式把該元素的html來擷取。
Soup.find(‘標籤名稱‘)
Soup.find(class_='r-ent') #我們就可以找到第一個class為'r-ent'的元素了
#find有兩個常用的用法:
- 直接接標籤名稱
- Soup.find(‘a’) 可以直接找到第一個a標籤的元素
- Soup.find(‘p’) 可以直接找到第一個p標籤的元素 - 屬性名稱用鍵值方式對應
- Soup.find(class_=’abc’) 可以找到第一個class為’abc’的元素
要注意的是因為python中class是保留字,所以要用class_才能表達
- Soup.find(id=’def’) 可以找到第一個id為’def’的元素
- Soup.find(type=’text’) 可以找到第一個type為’text’的元素
接著就可以開始使用了,我們透過右鍵>檢查
來查看原始碼
,可以發現標題是在class = r-ent
下層的 class = title
的a標籤
,所以我們可以再find一次來找到我們的第二層。
Soup.find(class_='r-ent').find(class_='title') #回傳的html就會只剩下面這樣<div class="title"> <a href= "/bbs/Gossiping/M.1601946581.A.88D.html">[問卦] 龍婆的預言 </a> </div>
我們會發現標題還是藏在a標籤裡面,這時候我們可以再用find找到a標籤或是用語法糖來讀取內容,最後只要再加上.text就可以輕鬆讀取裡面的文字。
Soup.find(class_='r-ent').find(class_='title').find('a')# 可以用一般用法.find('標籤名') Soup.find(class_='r-ent').find(class_='title').a #語法糖<a href="/bbs/Gossiping/M.1601946581.A.88D.html">[問卦] 龍婆的預言</a>print(Soup.find(class_='r-ent').find(class_='title').a.text)[問卦] 龍婆的預言
另外我們可以發現,該網頁的超連結
是藏在a標籤內,這時候可以用get
這個方式來把屬性內的資料讀出來,或是像是字典一樣,用[‘屬性名稱’]
來讀取。
Soup.find(‘標籤名稱‘).get(‘屬性名稱’)
Soup.find(class_='r-ent').find(class_='title').a.get('href')#從a標籤中用.get('屬性名')的方式讀取該屬性的值Soup.find(class_='r-ent').find(class_='title').a['href']# 或是像字典一樣用鍵值的方式,來讀取該屬性的值
到這邊我們順利的找得了第一個文章的標題跟超連結,接著我們要把該頁每一篇的文章都做一樣的事情,這時候我們要用find_all的方式:
Soup.find_all(‘標籤名稱‘)
Soup.find_all(class_='r-ent') #我們就可以找到全部class為'r-ent'的元素
find_all的用法基本上跟find一模一樣,只是他會回傳一個list,所以我們可以透過for迴圈的方式把資料給完整的讀取出來,經過整理一番就可以把我們想讀取的資料給讀出來了。
for i in Soup.find_all(class_='r-ent'): print(i.find(class_='title').a.text) #印出標題 print('https://www.ptt.cc',end='') #因為href中的網址不完整,要補上 print(i.find(class_='title').a['href']) #然後跟上面的接在一起
CSS選擇器用法
基本上最常用的BeautifulSoup語法就是透過解析html的架構來找資料,當然bs4也有提供css選擇器
的方式來讀取資料,
Soup.select_one(‘css選擇的語法‘)
Soup.select_one('.r-ent > .title > a ')
其實簡單的css選擇的用法不難理解,從這邊可以看得我是先找出r-ent這個class,在css中.代表class、#代表id,>代表下一層的意思
,所以從上面這行可以看出,我要找到的是第一個出現的,在 class = r-ent 中的 class= title 裡面的a標籤
,是不是其實相當的直覺呢?
這就相當於在前面用find的方式的程式碼
Soup.find(class_='r-ent').find(class_='title').find('a')
Soup.select(‘css選擇的語法‘)
至於對應find_all就是用select的方式,剛剛前面那段落落長的語法,在使用css選擇器的方式變得相當簡潔。
for i in Soup.select('.r-ent > .title > a '): print(i.text) #印出標題 print('https://www.ptt.cc',end='') #補上不完整的網址 print(i['href']) #讀出藏在href中的超連結網址
但這只是簡單css使用法,如果想要更詳盡的使用方法,我會推薦使用另一個套件 — Pyquery來做解析,另外如果你是前端工程師,已經熟悉Jquery,那麼Pyquery會是你的不二選擇,之後如果有空會再分享Jquery爬蟲方法。
小結
透過Python requests + bs4這兩個套件來爬蟲的教學,大概就到一個段落,如果想了解更詳細的資料可以直接參考官方文件,裡面有更多的使用情境對應的用法,但你只要熟悉上面說的用法就可以完成很多事了!
雖然bs4相當好用,而且解析速度非常的快,但還是有一些問題,就是只能處理靜態的網站,如果你要爬取的網站有javascipt,那你很可能無法順利爬取你要的資料,這時候有兩種比較常見的方法,第一種切換到手機版,通常手機版會比較好爬取;另一種就是之後要跟大家分享的套件 — Selenium,可以模擬一個使用者去做網頁的讀取解析,所以就可以順利的讀取javascript,而且還能克服許多反爬蟲的網站!那Selenium詳細的教學我們之後見!
我是尚恩,一個從商學院畢業的菜鳥工程師,有任何想從商轉換跑道的問題都可以找我聊聊,歡迎透過Linkedin@SeanChien聯絡我~
如果喜歡我的文章可以幫我鼓掌、訂閱、分享謝謝😇!