Photo by Stanley Dai on Unsplash
在實務上開發專案時,很多時候會利用其他網站的資料來進行分析或運用,而取得的方式除了透過網站所提供的API(Application Programming Interface)外,也可以利用Python來開發爬蟲程式,將網頁的HTML內容下載下來,接著利用BeautifulSoup套件(Package),擷取所需的資訊。本文將開發一個簡單的爬蟲程式,爬取「ETtoday旅遊雲」網頁,擷取桃園旅遊景點的標題資訊,如下圖:
取自ETtoday的旅遊雲
而在開發的過程中,常會需要搜尋HTML的節點,本文將分享幾個常用的方法,包含:
- BeautifulSoup安裝
- 以HTML標籤及屬性搜尋節點
- 以CSS屬性搜尋節點
- 搜尋父節點
- 搜尋前、後節點
- 取得屬性值
- 取得連結文字
一、BeautifulSoup安裝
BeautifulSoup是一個用來解析HTML結構的Python套件(Package),將取回的網頁HTML結構,透過其提供的方法(Method),能夠輕鬆的搜尋及擷取網頁上所需的資料,因此廣泛的應用在網頁爬蟲的開發上。
Beautifulsoup套件(Package)可以透過pip指令來進行安裝,如下範例:
Beautifulsoup套件(Package)可以透過pip指令來進行安裝,如下範例:
pip install beautifulsoup4
而要解析網頁的HTML程式碼前,還需要安裝Python的requests套件(Package),將要爬取的網頁HTML程式碼取回來,安裝方式如下:
pip install requests
安裝完成後,首先引用requests套件(Package),並且透過get()方法(Method)存取ETtoday旅遊雲的桃園景點網址,如下範例:
import requests
response = requests.get(
"https://travel.ettoday.net/category/%E6%A1%83%E5%9C%92/")
將網頁的HTML程式碼取回來後,接著引用BeautifulSoup類別(Class),傳入取回的HTML結構字串,並且指定HTML的解析型態來建立其物件,如下範例:
import requests
from bs4 import BeautifulSoup
response = requests.get(
"https://travel.ettoday.net/category/%E6%A1%83%E5%9C%92/")
soup = BeautifulSoup(response.text, "html.parser")
print(soup.prettify()) #輸出排版後的HTML內容
執行結果(截取其中的片段):接下來將以這個HTML結構為基礎,說明搜尋節點的常用方法。
網美必去!桃園打卡聖地玫瑰山谷 鮮花+童話小屋超浪漫
網美看過來!桃園熱門景點[玫瑰山谷],以浪漫的歐風童話小屋,加上滿院的豔麗玫瑰,成為IG上的打卡熱點.雖然歷經一次搬家,但在空間和環境都有做改變的情況下,人氣不減反升,是個不論情侶或姐妹聚會都能來的地方,趕緊揪人出門浪漫一下. (2020-02-09 16:03)
二、以HTML標籤及屬性搜尋節點
現在,soup物件已經包含了整個網頁的HTML程式碼,接下來就可以利用BeautifulSoup套件(Package)所提供的以下方法,來進行節點的搜尋。
- find()
只搜尋第一個符合條件的HTML節點,傳入要搜尋的標籤名稱,如下範例:
result = soup.find("h3")
print(result)
執行結果- find_all()
搜尋網頁中所有符合條件的HTML節點,傳入要搜尋的HTML標籤名稱。如果要更明確的搜尋,可以利用關鍵字參數(Keyword Argument)指定其屬性值。由於執行結果可能會搜出許多的HTML內容,所以最後也可以利用limit關鍵字參數(Keyword Argument)限制搜尋的節點數量,如下範例:
result = soup.find_all("h3", itemprop="headline", limit=3)
print(result)
執行結果
範例中可以看到,find_all()方法(Method)回傳了一個串列(List),包含了網頁中所有的<h3>標籤,且itemprop屬性值為headline的節點,由於限定搜尋數量為2,所以僅搜尋兩個節點。
另外,如果要同時搜尋多個HTML標籤,可以將標籤名稱打包成串列(List)後,傳入find_all()方法(Method)中即可,如下範例:
另外,如果要同時搜尋多個HTML標籤,可以將標籤名稱打包成串列(List)後,傳入find_all()方法(Method)中即可,如下範例:
result = soup.find_all(["h3", "p"], limit=2)
print(result)
執行結果
範例中同時搜尋了網頁中所有<h3>及<p>的HTML標籤內容,這邊限定只搜尋兩個節點。
範例中,由於<div>標籤下有多個<a>標籤的子節點,所以可以利用select()方法(Method),選取其下所有的<a>標籤,並且為串列(List)的資料型態。
- select_one()
result = soup.find("h3", itemprop="headline")
print(result.select_one("a"))
執行結果- select()
result = soup.find("div", itemprop="itemListElement")
print(result.select("a"))
執行結果三、以CSS屬性搜尋節點
要依據HTML的css屬性來進行節點的搜尋,需使用 class_ 關鍵字參數(Keyword Argument)來進行css屬性值的指定,同樣提供了以下的搜尋方式:
- find()
搜尋第一個符合指定的HTML標籤及css屬性值的節點,如下範例:
titles = soup.find("p", class_="summary")
print(titles)
執行結果- find_all()
搜尋網頁中符合指定的HTML標籤及css屬性值的所有節點,如下範例:
titles = soup.find_all("p", class_="summary", limit=3)
print(titles)
執行結果
第二、三個<p>節點由於其下還有<em>節點,所以也會進行回傳。
- select()
而如果單純只想要透過css屬性值來進行HTML節點的搜尋,則可以使用BeautifulSoup套件(Package)的select()方法(Method),如下範例:
titles = soup.select(".summary", limit=3)
print(titles)
執行結果四、搜尋父節點
以上皆為向下的搜尋節點方式,如果想要從某一個節點向上搜尋,則可以使用BeautifulSoup套件(Package)的find_parent()或find_parents()方法(Method),如下範例:
result = soup.find("a", itemprop="url")
parents = result.find_parents("h3")
print(parents)
執行結果
範例中,搜尋<a>標籤且itemprop屬性值為url的節點,接著透過find_parents()方法(Method),向上搜尋<h3>標籤的父節點。
五、搜尋前、後節點
在同一層級的節點,想要搜尋前一個節點,可以使用BeautifulSoup套件(Package)的find_previous_siblings()方法,如下範例:
result = soup.find("h3", itemprop="headline")
previous_node = result.find_previous_siblings("a")
print(previous_node)
執行結果
相反的,在同一層級的節點,想要搜尋後一個節點,則使用find_next_siblings()方法(Method),如下範例:
result = soup.find("h3", itemprop="headline")
next_node = result.find_next_siblings("p")
print(next_node)
六、取得屬性值
在前面範例中,皆為取得所需之HTML節點,而如果想要取得某一個節點中的屬性值,則可以利用BeautifulSoup套件(Package)的get()方法(Method)。
假設,想要爬取「ETtoday的旅遊雲」桃園景點首頁的標題連結。首先,利用find_all()方法搜尋網頁中所有<h3>標籤且itemprop屬性值為headline的節點,接著,透過for迴圈讀取串列(List)中的節點,由於<h3>標籤底下只有一個<a>標籤,所以可以利用BeautifulSoup套件的select_one()方法進行選取,如下範例:
假設,想要爬取「ETtoday的旅遊雲」桃園景點首頁的標題連結。首先,利用find_all()方法搜尋網頁中所有<h3>標籤且itemprop屬性值為headline的節點,接著,透過for迴圈讀取串列(List)中的節點,由於<h3>標籤底下只有一個<a>標籤,所以可以利用BeautifulSoup套件的select_one()方法進行選取,如下範例:
titles = soup.find_all("h3", itemprop="headline")
for title in titles:
print(title.select_one("a"))
執行結果titles = soup.find_all("h3", itemprop="headline")
for title in titles:
print(title.select_one("a").get("href"))
執行結果七、取得連結文字
要取得<a>標籤的連結文字,可以利用BeautifulSoup套件(Package)的getText()方法(Method),如下範例:
titles = soup.find_all("h3", itemprop="headline")
for title in titles:
print(title.select_one("a").getText())
執行結果八、小結
以上就是利用Python開發網頁爬蟲時,常用的HTML節點搜尋及資料取得的方式,透過實際的爬取旅遊景點資訊,讓各位可以瞭解Python基本的爬蟲開發,運用本文所教的概念,實作一個爬蟲獲取想要的資訊吧。如果在練習的過程中有遇到任何問題,或是有不錯的爬蟲開發技巧及經驗,歡迎留言分享。
如果您喜歡我的文章,請幫我按五下Like(使用Google或Facebook帳號免費註冊),支持我創作教學文章,回饋由LikeCoin基金會出資,完全不會花到錢,感謝大家。
如果您喜歡我的文章,請幫我按五下Like(使用Google或Facebook帳號免費註冊),支持我創作教學文章,回饋由LikeCoin基金會出資,完全不會花到錢,感謝大家。
有想要看的教學內容嗎?歡迎利用以下的Google表單讓我知道,將有機會成為教學文章,分享給大家😊
Python學習資源
Python網頁爬蟲推薦課程
Python網頁爬蟲-Selenium教學
Python非同步網頁爬蟲
Python網頁爬蟲應用
Python網頁爬蟲部署
Python網頁爬蟲資料儲存
Python網頁爬蟲技巧
你好
回覆刪除想請問find/find_all
與select_one/select
這兩種方法的差別和適合的使用時機是?
感謝!
您好:
刪除1.兩者的定位元素語法不同,select_one/select使用CSS的語法來進行元素定位。
2.find = select_one,皆是取得單一元素
find_all = select,皆是取得多個元素
3.find/find_all與select_one/select最大的差別就是語法不同,所以取決於您習慣哪一種語法來進行元素定位,如果要嚴格區分使用時機的話,通常select_one/select會使用在以class樣式類別來進行元素定位,或是定位元素的層級較多的情況,其餘會使用find/find_all。
希望以上有解答到您的問題,謝謝您的提問 :)
你好!請問如果有很多個網站的網址放在txt檔案內!可以一次輸出多個網站標頭嗎?
回覆刪除您好,可以唷,先讀取txt中的網址,存放在串列(List)中,後續就可以透過迴圈讀取串列(List)中的網址,來輸出多個網站的內容了,如下範例:
刪除file = 'example.txt'
urls = []
with open(file) as f:
for line in f.readlines():
urls.append(line)
print(urls)
希望有解決您的問題 :)
您好,我在 VS code 裡也有安裝 Code Runner
回覆刪除我照著您的文章做,但程式輸出時在 OUTPUT 分頁裡面它呈現亂碼耶!
若不裝 Code Runner 的話,執行時結果會呈現在 TERMINAL 裡面,
這時又沒有亂碼,請問是什麼問題呢?
我自問自答~~
刪除在網路上找到兩個方法解決 Code Runner 亂碼的問題
提供我找到的網頁供大家參考
方法一:將程式輸出資訊由 OUTPUT 分頁改至 TERMINAL 分頁
參考網頁:https://umin27.medium.com/vs-code%E6%8E%A1%E7%94%A8code-runner%E9%81%87%E5%88%B0%E7%9A%84-output%E4%B8%AD%E6%96%87%E4%BA%82%E7%A2%BC%E5%95%8F%E9%A1%8C-python-55e73edf9d0b
方法二:修改 OUTPUT 分頁輸出文字的編碼
參考網頁:https://www.cnblogs.com/charleswong/p/11367196.html
IvanKe,感謝您的分享,非常實用,推推 :)
刪除你好!嘗試用Python抓網頁上的資料 試過幾個還順利 但有些網頁上的資料只有抓到頭尾一部分 中間部分資料抓不到 用網頁開發者工具 也有找到相對映的ID 請問是要用BeautifulSoup之外的技巧抓嗎?
回覆刪除網頁: https://mis.twse.com.tw/stock/etf_nav.jsp?ex=tse/ctrl-reference