使用 Python 的 requests 和 Beautiful Soup 來分析網頁

語言: CN / TW / HK

  • 學習這個 Python 教程,輕鬆提取網頁的有關資訊。

瀏覽網頁可能佔了你一天中的大部分時間。然而,你總是需要手動瀏覽,這很討厭,不是嗎?你必須開啟瀏覽器,然後訪問一個網站,單擊按鈕,移動滑鼠……相當費時費力。如果能夠通過程式碼與網際網路互動,豈不是更好嗎?

在 Python 的 requests 模組的幫助下,你可以使用 Python 從網際網路中獲取資料:

import requests
    DATA = "https://opensource.com/article/22/5/document-source-code-doxygen-linux"
    PAGE = requests.get(DATA)
    print(PAGE.text)

在以上程式碼示例中,你首先匯入了 requests 模組。接著,你建立了兩個變數:其中一個叫做 DATA,它用來儲存你要下載的 URL。在之後的程式碼中,你將能夠在每次執行應用程式時提供不同的 URL。不過,就目前而言,最簡單的方法是“硬編碼”一個測試 URL,以達到演示目的。

另一個變數是 PAGE。程式碼讀取了儲存在 DATA 中的 URL,然後把它作為引數傳入 requests.get 函式,最後用變數 PAGE 來接收函式的返回值。requests 模組及其 .get 函式的功能是:“讀取”一個網際網路地址(一個 URL)、訪問網際網路,並下載位於該地址的任何內容。

當然,其中涉及到很多步驟。幸運的是,你不必自己弄清楚,這也正是 Python 模組存在的原因。最後,你告訴 Python 列印 requests.get 儲存在 PAGE 變數的 .text 欄位中的所有內容。

Beautiful Soup

如果你執行上面的示例程式碼,你會得到示例 URL 的所有內容,並且,它們會不加選擇地輸出到你的終端裡。這是因為在程式碼中,你對 requests 收集到的資料所做的唯一事情,就是列印它。然而,解析文字才是更加有趣的。

Python 可以通過其最基本的功能來“讀取”文字,但解析文字允許你搜索模式、特定單詞、HTML 標籤等。你可以自己解析 requests 返回的文字,不過,使用專門的模組會容易得多。針對 HTML 和 XML 文字,我們有 Beautiful Soup 庫。

下面這段程式碼完成了同樣的事情,只不過,它使用了 Beautiful Soup 來解析下載的文字。因為 Beautiful Soup 可以識別 HTML 元素,所以你可以使用它的一些內建功能,讓輸出對人眼更友好。

例如,在程式的末尾,你可以使用 Beautiful Soup 的 .prettify 函式來處理文字(使其更美觀),而不是直接列印原始文字:

from bs4 import BeautifulSoup
    import requests
    PAGE = requests.get("https://opensource.com/article/22/5/document-source-code-doxygen-linux")
    SOUP = BeautifulSoup(PAGE.text, 'html.parser')
    # Press the green button in the gutter to run the script.
    if __name__ == '__main__':
        # do a thing here
        print(SOUP.prettify())

通過以上程式碼,我們確保了每個開啟的 HTML 標籤都輸出在單獨的一行,並帶有適當的縮排,以幫助說明標籤的繼承關係。實際上,Beautiful Soup 能夠通過更多方式來理解 HTML 標籤,而不僅僅是將它打印出來。

你可以選擇列印某個特定標籤,而不是列印整個頁面。例如,嘗試將列印的選擇器從 print(SOUP.prettify()) 更改為:

print(SOUP.p)

這隻會列印一個 <p> 標籤。具體來說,它只打印遇到的第一個 <p> 標籤。要列印所有的 <p> 標籤,你需要使用一個迴圈。

迴圈

使用 Beautiful Soup 的 find_all 函式,你可以建立一個 for 迴圈,從而遍歷 SOUP 變數中包含的整個網頁。除了 <p> 標籤之外,你可能也會對其他標籤感興趣,因此最好將其構建為自定義函式,由 Python 中的 def 關鍵字(意思是 “定義”define)指定。

def loopit():
        for TAG in SOUP.find_all('p'):
            print(TAG)

你可以隨意更改臨時變數 TAG 的名字,例如 ITEM 或 i 或任何你喜歡的。每次迴圈執行時,TAG 中都會包含 find_all 函式的搜尋結果。在此程式碼中,它搜尋的是 <p> 標籤。

函式不會自動執行,除非你顯式地呼叫它。你可以在程式碼的末尾呼叫這個函式:

# Press the green button in the gutter to run the script.
    if __name__ == '__main__':
        # do a thing here
        loopit()

執行程式碼以檢視所有的 <p> 標籤和它們的內容。

只獲取內容

你可以通過指定只需要 “字串string”(它是 “單詞words” 的程式設計術語)來排除列印標籤。

def loopit():
        for TAG in SOUP.find_all('p'):
            print(TAG.string)

當然,一旦你有了網頁的文字,你就可以用標準的 Python 字串庫進一步解析它。例如,你可以使用 len 和 split 函式獲得單詞個數:

def loopit():
        for TAG in SOUP.find_all('p'):
            if TAG.string is not None:
                print(len(TAG.string.split()))

這將列印每個段落元素中的字串個數,省略那些沒有任何字串的段落。要獲得字串總數,你需要用到變數和一些基本數學知識:

def loopit():
        NUM = 0
        for TAG in SOUP.find_all('p'):
            if TAG.string is not None:
                NUM = NUM + len(TAG.string.split())
        print("Grand total is ", NUM)

Python 作業

你可以使用 Beautiful Soup 和 Python 提取更多資訊。以下是有關如何改進你的應用程式的一些想法:

  • 接受輸入,這樣你就可以在啟動應用程式時,指定要下載和分析的 URL。
  • 統計頁面上圖片(<img> 標籤)的數量。
  • 統計另一個標籤中的圖片(<img> 標籤)的數量(例如,僅出現在<main> div 中的圖片,或僅出現在</p> 標籤之後的圖片)。