以 requests 搭配 beautifulsoup4 或 pyquery 套件實踐網站爬蟲

郭耀仁 Yao-Jen Kuo
Apr 26 · 14 min read
Photo by Trevin Rudy on Unsplash

The world’s most valuable resource is no longer oil, but data.

The Economist

這個小節將延續輕鬆學習 Python:透過 API 擷取網站資料,討論第三種資料來源:網頁,簡介如何使用 requests 搭配 beautifulsoup4 或 pyquery 來擷取 HTML(全名為 HyperText Markup Language)格式的資料源。由於無法直接取得以 listdict 存儲的資料結構,還需要花一層心思以 XPath(提供在 XML/HTML 資料中以 XML 節點找尋特定資料位置的定位方法)或 CSS Selector(提供在 HTML 資料中以層疊樣式表找尋特定資料位置的定位方法)來解析。

我們將擷取 IMDB.comAvengers: Endgame (2019) 的 HTML 格式資料作示範,完整程式可以參考這個 Google Colab:https://colab.research.google.com/drive/1D_vm1uMHWjUOE1HSEN2vbkuNqtGECJHu


在 HTML 格式資料中定位

向伺服器發送請求後若是獲得 HTML 格式資料,將需要進行較複雜的解析任務,原因是請求後的 HTML 文件包含了太多不需要的資訊,諸如包含在 <style></style> 標籤中的 CSS(Cascading Style Sheets,階層樣式表)語言或者包含在 <script></script> 標籤中的 JavaScript 語言。

熟練定位網頁中特定資料位址的技巧就變得十分重要,如同在地圖上加入標記(Marker)一般,我們需要景點或建築物的位址,可以是門牌號碼、詳細地址甚至是精準的經緯度。在網頁上標記資料為止有非常多方法能夠表示,常見的像是使用:

  • HTML 的標籤名稱
  • HTML 標籤中給予的 id
  • HTML 標籤中給予的 class
  • CSS 選擇器(CSS Selector)
  • XPath

考量多數資料科學愛好者並不具備網頁工程師的背景技能,透過 Chrome 瀏覽器的外掛來取得資料所在的 CSS 選擇器是快速入門的捷徑。

安裝 Chrome 瀏覽器外掛:Selector Gadget

透過下列步驟將 Selector Gadget 外掛加入 Chrome 瀏覽器。

  1. 前往 Chrome Web Store,點選外掛(Extensions)
  2. 搜尋 Selector Gadget 並點選加入到 Chrome 瀏覽器
  3. 確認要加入 Selector Gadget
  4. 完成安裝
前往 Chrome Web Store,點選外掛(Extensions)
搜尋 Selector Gadget 並點選加入到 Chrome 瀏覽器
確認要加入 Selector Gadget
完成安裝

使用 Chrome 瀏覽器外掛:Selector Gadget

依照下列步驟使用 Chrome 瀏覽器外掛:Selector Gadget。

  1. 點選 Selector Gadget 的外掛圖示
  2. 在想要定位的評分上面點選左鍵,留意此時的 CSS 選擇器位址與資料筆數,通常在第一次點擊後網頁上很多的資料都會同時被選到(以黃底標記),Clear 後面數字表示有多少筆
  3. 移動滑鼠點選不要選擇的元素(改以紅底標記),並同時注意 CSS 選擇器位址與資料筆數的變動,當資料筆數與預期相符時表示完成定位

我們以 IMDB.comAvengers: Endgame (2019) 頁面示範如何用 Selector Gadget 定位評等。

點選 Selector Gadget 外掛圖示
在想要定位的評分上面點選左鍵,留意此時的 CSS 選擇器位址與資料筆數
移動滑鼠點選不要選擇的元素,當資料筆數與預期相符時表示完成定位

安裝套件

主要應用在這個範例的套件有 requests、beautifulsoup4、pyquery 與 json,可以選擇透過 Windows 的命令提示字元(或 Anaconda Prompt)、macOS 的 Terminal 或者在筆記本的儲存格加上 ! 進行套件安裝,其中 json 套件是 Python 的標準函式庫(Standard Library)不需要額外安裝。

## Requirement already up-to-date: requests in /usr/local/lib/python3.6/dist-packages (2.21.0)
## Collecting beautifulsoup4
## Downloading https://files.pythonhosted.org/packages/1d/5d/3260694a59df0ec52f8b4883f5d23b130bc237602a1411fa670eae12351e/beautifulsoup4-4.7.1-py3-none-any.whl (94kB)
## 100% |████████████████████████████████| 102kB 6.5MB/s
## Collecting pyquery
## Downloading https://files.pythonhosted.org/packages/09/c7/ce8c9c37ab8ff8337faad3335c088d60bed4a35a4bed33a64f0e64fbcf29/pyquery-1.4.0-py2.py3-none-any.whl
## Requirement already satisfied, skipping upgrade: idna<2.9,>=2.5 in /usr/local/lib/python3.6/dist-packages (from requests) (2.8)
## Requirement already satisfied, skipping upgrade: chardet<3.1.0,>=3.0.2 in /usr/local/lib/python3.6/dist-packages (from requests) (3.0.4)
## Requirement already satisfied, skipping upgrade: certifi>=2017.4.17 in /usr/local/lib/python3.6/dist-packages (from requests) (2019.3.9)
## Requirement already satisfied, skipping upgrade: urllib3<1.25,>=1.21.1 in /usr/local/lib/python3.6/dist-packages (from requests) (1.24.2)
## Collecting soupsieve>=1.2 (from beautifulsoup4)
## Downloading https://files.pythonhosted.org/packages/b9/a5/7ea40d0f8676bde6e464a6435a48bc5db09b1a8f4f06d41dd997b8f3c616/soupsieve-1.9.1-py2.py3-none-any.whl
## Collecting cssselect>0.7.9 (from pyquery)
## Downloading https://files.pythonhosted.org/packages/7b/44/25b7283e50585f0b4156960691d951b05d061abf4a714078393e51929b30/cssselect-1.0.3-py2.py3-none-any.whl
## Requirement already satisfied, skipping upgrade: lxml>=2.1 in /usr/local/lib/python3.6/dist-packages (from pyquery) (4.2.6)
## Installing collected packages: soupsieve, beautifulsoup4, cssselect, pyquery
## Found existing installation: beautifulsoup4 4.6.3
## Uninstalling beautifulsoup4-4.6.3:
## Successfully uninstalled beautifulsoup4-4.6.3
## Successfully installed beautifulsoup4-4.7.1 cssselect-1.0.3 pyquery-1.4.0 soupsieve-1.9.1

透過 requests 請求 HTML 資料

輕鬆學習 Python:透過 API 擷取網站資料同樣使用 requests 模組中的 get() 函數 向 Avengers: Endgame (2019) 頁面索取資料,取得一個 response 類別,因為格式為 HTML 所以我們以 .text 屬性擷取為 str 資料型態,再仰賴 beautifulsoup4 或 pyquery 解析這個純文字資料的內容,beautifulsoup4 與 pyquery 均是 Python 使用者常拿來解析 HTML 格式的常用套件,兩者都依賴 lxml 作為解析器。

## 200
## <class 'requests.models.Response'>
## <class 'str'>

透過 beautifulsoup4 解析 HTML 資料

Beautiful Soup is a Python library for pulling data out of HTML and XML files. It works with your favorite parser to provide idiomatic ways of navigating, searching, and modifying the parse tree. It commonly saves programmers hours or days of work.

beautifulsoup4 的基本用法是將 HTML 資料輸入 BeautifulSoup() 函數獲得 BeautifulSoup 類別,進而以 .select() 方法搭配 CSS 選擇器精準萃取出資料,再用 .text 屬性將標籤的部分去除。

## <class 'bs4.BeautifulSoup'>
## [<span itemprop="ratingValue">9.2</span>]
## 9.2

有時我們不一定是要擷取標籤中的文字,而是想擷取標籤的參數值,像是 <a></a> 標籤的 href 或是 <img> 標籤的 src ,這時可以改用 .get() 方法。

## [<img alt="Avengers: Endgame Poster" src="https://m.media-amazon.com/images/M/MV5BMTc5MDE2ODcwNV5BMl5BanBnXkFtZTgwMzI2NzQ2NzM@._V1_UX182_CR0,0,182,268_AL_.jpg" title="Avengers: Endgame Poster"/>]
## https://m.media-amazon.com/images/M/MV5BMTc5MDE2ODcwNV5BMl5BanBnXkFtZTgwMzI2NzQ2NzM@._V1_UX182_CR0,0,182,268_AL_.jpg

透過 pyquery 解析 HTML 資料

pyquery allows you to make jquery queries on xml documents. The API is as much as possible the similar to jquery. pyquery uses lxml for fast xml and html manipulation.

pyquery 的基本用法是將 HTML 資料輸入 PyQuery() 函數(約定縮寫為 pq())獲得 PyQuery 類別,進而搭配 CSS 選擇器精準萃取出資料,再用類別的 .items().text() 方法將標籤的部分去除。

## <class 'pyquery.pyquery.PyQuery'>
## <span itemprop="ratingValue">9.2</span>
## 9.2

有時我們不一定是要擷取標籤中的文字,而是想擷取標籤的參數值,像是 <a></a> 標籤的 href 或是 <img> 標籤的 src ,這時可以改用 .attr() 方法。

## <img alt="Avengers: Endgame Poster" title="Avengers: Endgame Poster" src="https://m.media-amazon.com/images/M/MV5BMTc5MDE2ODcwNV5BMl5BanBnXkFtZTgwMzI2NzQ2NzM@._V1_UX182_CR0,0,182,268_AL_.jpg"/>
##
## https://m.media-amazon.com/images/M/MV5BMTc5MDE2ODcwNV5BMl5BanBnXkFtZTgwMzI2NzQ2NzM@._V1_UX182_CR0,0,182,268_AL_.jpg

寫出資料

Avengers: Endgame (2019) 頁面擷取出的資料為非對稱型結構(電影名稱、評等與海報連結的資料長度為 1、演員名單的資料長度為 15),面對非對稱型結構資料在 Python 中以 dict 儲存,輸出格式為 JSON 檔案,可以透過 json 套件的 dump(ensure_ascii=False) 函數將 dict 寫出。

輸出格式為 JSON 檔案

小結

在這個小節中我們簡介如何以 Python 透過 requests 搭配 beautifulsoup4 或 pyquery 套件實踐網站爬蟲,第一項核心任務:請求資料(requesting data)由 requests 套件負責;第二項核心任務:解析資料(parsing data)則可以依個人喜好選擇以 beautifulsoup4 或 pyquery 套件應用。


DataInPoint

DataInPoint 是一個超棒的資料科學專欄,主題涵蓋資料、程式、機器學習與高效能運算。

郭耀仁 Yao-Jen Kuo

Written by

Could that data be any tidier? It is always nice to meet a data enthusiast / 2:43 marathon runner.

DataInPoint

DataInPoint 是一個超棒的資料科學專欄,主題涵蓋資料、程式、機器學習與高效能運算。

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade