創作內容

3 GP

Beautiful Soup (上)

作者:Yotsuba│2020-05-26 18:09:52│巴幣:9│人氣:454
請你先點擊這個連結 : http://pythonscraping.com/pages/page1.html

這是上次用來練習 GET 的網站


如果我們想要擷取整份 HTML,可以發送一個 GET 請求

但如果我們想要擷取的是片段的 HTML 怎麼辦 ? 用正則表達式暴力擷取 ?

正則表達式雖然是一個方法,但那是最後的手段


在 Python 我們可以享受好用的函式庫

今天來介紹一下這個超強 HTML Parser ,它叫 Beautiful Soup


<html>
    <head>
        <title>A Useful Page</title>
    </head>
    
    <body>
        <h1>An Interesting Title</h1>
        <div>
            Lorem ipsum dolor sit amet, consectetur adipisicing ...
        </div>
    </body>
</html>


礙於版面大小,<div> 的部分文字被我刪減掉了

假設我們想要爬取 <h1> 這個節點,也就是大標題,我們就可以使用 Beautiful Soup

假設我們最終想要拿到「An Interesting Title 」這段文字,程式碼可以這樣寫


import requests
from bs4 import BeautifulSoup

response = requests.get('http://pythonscraping.com/pages/page1.html')

soup = BeautifulSoup(response.text, 'html.parser')

print(soup.h1)
print(soup.h1.text)
print(soup.find('h1').text)


執行結果




BeautifulSoup 在我撰寫文章時,最新版本是 4.x.x,所以函式庫名稱叫 bs4

使用時直接寫 from bs4 import BeautifulSoup 即可

這個函式庫還有更強大的功能,不過我單純把它當 HTML Parser 使用

所以沒有研究得太透徹,也沒有認真讀過官方文件


soup = BeautifulSoup(response.text, 'html.parser')

response.text 在這邊剛好是 HTML,第二個參數則是解析格式,參數有許多

如果填 html.parser 代表使用 Python 的 HTML Parser

其他還有像是 html5lib 的參數,專門用來解析 HTML5

或是 xml 的參數,不得不說 BeautifulSoup 真的超強,它也可以解析 xml 格式


接下來我寫了 3 個 print,我一一解釋

首先這份 HTML 裡面只有一個 <h1> 節點,所以寫 print(soup.h1) 可以直接抓到大標題

底層的行為其實是直接抓取第一個遇到的 <h1>

整個節點 print 出來就會是 <h1>An Interesting Title</h1>


第二個 print 有點變化,我寫成 print(soup.h1.text),表示只 print <h1> 裡面的文字

所以就會得到我們要的 An Interesting Title


第三個 print 我寫成 print(soup.find('h1').text),表示以 soup 去尋找第一個 <h1>

如果有找到的話就會回傳這個 <h1> 物件,然後使用 text 屬性,也順利拿到大標題了

如果 find 沒有找到會回傳空物件 (None)


乍看之下,第二種和第三種寫法差不多 ? 以這個例子來說的確差不多

但未來會遇到有 CSS 裝飾過的節點,或者有 class 屬性的節點

這時候就能利用 find 去過濾屬性,抓取我們真正想要的節點


BeautifulSoup 還有太多花俏的玩法,一時間無法全部解說完畢

可以繼續參考下一篇文章

延伸閱讀 : BeautifulSoup (下)
引用網址:https://home.gamer.com.tw/TrackBack.php?sn=4795586
All rights reserved. 版權所有,保留一切權利

相關創作

留言共 5 篇留言

多古尼爾拉布拉布拉格
針對最後三個print
第一個是找出所有的h1tag
第二個是print出所有h1tag裡面的text node
第三個我想應該是找出respond存的東西裡第一個的h1
這樣理解沒錯嗎?
那我想問後面的那段
經過Css或class渲染
但第二個print跟第三個print我想應該都跟CSS和class沒有相關吧?
請問有什麼例子是第二種和第三種方式的使用情況嗎@@
很高興大大解釋得這麼詳細

05-26 22:02

Yotsuba
每一個 print 都是找出 "第一個" 遇到的 <h1>,不是所有 <h1>

找出所有有另一個函式叫 find_all(),會在之後的章節解說

因為 Beautiful Soup 的用法實在太多了

即使我解說的很詳細,還是要請大家多使用 Beautiful Soup 才會熟練


假設今天 HTML 的結構裡面有

<div>Hello</div>

<div class = "hey">World</div>

無論寫 soup.h1.text 或 soup.find('div').text 都會得到 Hello

因為都是取得第一個看見的 <div>


都是一樣的節點,那要如何拿到 World 呢 ?

可以寫 soup.find('div', class_ = 'hey').text

這就是利用 class 屬性去拿到特定 <div> 的方法

注意,class 已經是 Python 的保留字,Beautiful Soup 做法是寫 class_


其實這裡有一篇教學寫得還不錯,之後的章節都會詳細談到

https://blog.gtwang.org/programming/python-beautiful-soup-module-scrape-web-pages-tutorial/05-26 22:23
多古尼爾拉布拉布拉格
我講得沒很清楚
我的意思是 resp.h1.text和 resp.find(h1)
應該都是抓出h1 那跟Css和class的相關是?
我想問的是有沒有情況是需要用到這兩個的差異這樣

05-26 22:05

Yotsuba
同上05-26 22:23
多古尼爾拉布拉布拉格
了解ㄌ 謝謝大大的解說

05-26 22:57

朝輝夕嵐
太神啦

05-27 22:32

風蕭蕭荊軻醬
想問一下
所以最後第2跟第3種print的差距
只在於有沒有回傳值嗎

07-12 18:00

Yotsuba
以文章中的例子來說兩種寫法都會得到一樣的回傳值,跟「有沒有」沒關係

但是在實戰爬蟲的時候,節點可能會非常複雜,這種時候就可以用 find 去過濾ㄌ07-12 18:34
我要留言提醒:您尚未登入,請先登入再留言

3喜歡★happy819tw 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:POST... 後一篇:我為什麼會學 Pytho...

追蹤私訊切換新版閱覽

作品資料夾

ilove487奇幻小說連載中
《克蘇魯的黎明》0666.所謂驅毒看更多我要大聲說2小時前


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】