2024年4月10日 星期三

Python 學習筆記 : 網頁擷取 (四) : 開發網路爬蟲的步驟與工具

最近在讀下面這本書的第八章時發現原來撰寫網頁爬蟲有一個標準作業流程 :



Source : 博客來


書中範例檔案與工具程式可在碁峰網站下載 :


此書前半部講如何使用 Chrome 擴充工具 Web Scraper 來擷取網頁資料, 參考 :


後半部則是介紹用 Python 套件來撰寫爬蟲程式. 

以下是此書摘要 : 


一. 網頁爬蟲的開發步驟 :    
  1. 確定目標網頁之網址與參數 : 
    如果資料是由單一網頁提供, 則只要取得其網址即可; 若是使用分頁技術由多個網頁提供, 則其網址後面會攜帶分頁參數 (例如 data.htm?page=1 或 data1.htm).
  2. 判斷目標網頁為靜態網頁還是動態網頁 : 
    可以使用瀏覽器的擴充程式 Quick Javascript Switcher 來判斷, 若關閉 Javascript 目標資料不會消失或不完整, 則此為靜態網頁; 否則就是動態網頁. 
    • 靜態網頁 : 
      網頁內容為後端伺服器直接產生, 與有無執行 Javascript/Ajax 無關. 
    • 動態網頁 :
      網頁內容為執行 Javascript/Ajax 產生, 無法從伺服器回應的原始網頁內容中擷取目標資料. 
  3. 擬定爬蟲策略 :
    • 靜態網頁 : 可直接用 requests + BeautifulSoup 擷取網頁與剖析內容以取得目標資料.
    • 動態網頁 : 可先用瀏覽器的開發人員工具分析 Ajax 過程, 看看能否找到 Web API (例如 json 檔的 URL), 若找不到 Web API 可使用 Selenium 套件模擬瀏覽器執行網頁中的 Javascript 來產生目標資料. 
  4. 儲存目標資料 :
    • 檔案 : 例如 csv 或 json 等. 
    • 資料庫 : 例如 SQLite, MySQL, 或 MongoDB 等.
關於 Selenium 用法參考 :



二. 安裝 Quick Javascript Switcher 擴充程式 :   

首先到 Chrome 應用程式商店搜尋 Quick Javascript Switcher :





按 "加到 Chrome" :




按左邊的 "新增擴充功能" 鈕 : 



這時 Chrome 右上角就會出現一個有 JS 字樣的圖示, 按此圖示即可檢查網頁內容是否為 Javascript/Ajax 產生的動態網頁, 若按下去內容就部份或全部消失即為動態網頁, 否則為靜態網頁. 此圖示為 toggle (交替) 按鈕, 按一下關閉 Javascript, 再按一下打開 Javasript. 

如果右上角工具列沒有出現 Quick Javascript Switcher 的圖示按鈕, 可以按擴充程式圖示按鈕 (最右邊像拼圖的那個) 就會顯示所有擴充程式列表, 找到 Quick Javascript Switcher 再按其右邊的圖釘就可以將其固定在右上角的工具列了 :




也可以按 Chrome 右上角三個點圖示, 點選 "更多工具/擴充功能" 打開擴充程式列表 : 


 

接下來用 Quick Javascript Switcher 來檢查書中的範例網頁是靜態或動態網頁, 網址如下 :


結果為如下之書籍列表 : 



按 Quick Javascript Switcher 圖示鈕會發現框框內的資料 (書籍列表) 消失了, 表示此為 Javascript 產生的動態網頁 : 



檢視網頁原始碼可知網頁內容其實只有一個 id 為 result 的 div 元素而已, 書籍列表資料是 Javascript 從同網域底下的 books.json 檔取得資料後寫入瀏覽器 DOM 結構的 div 元素中生成的 :




如上所述, 這種動態網頁必須使用可模擬瀏覽器執行 Javascript 的 Selenium 套件才能取得其資料, 用 requests + BeautifulSoup 是抓不到的, 驗證如下 : 

>>> import requests  
>>> from bs4 import BeautifulSoup    
>>> r=requests.get("https://fchart.github.io/books.html")    
>>> bs4obj=BeautifulSoup(r.text, "lxml")    
>>> print(bs4obj.prettify())     
<!DOCTYPE html>
<html>
 <head>
  <title>
   books.html
  </title>
  <style type="text/css">
   .box {
   width:300px;
   background-color:#ffffff;
   border:2px solid blue;
   padding:10px;
}
  </style>
  <script src="jquery-3.1.0.min.js">
  </script>
  <script>
   $(document).ready(function() {
   $.getJSON('books.json', function(data) {
      var html = '<ul>';
      $.each(data, function(key, val) {
         html += '<li id="' + key + '">' + val.id + ':' + val.title + '</li>';
      });
      html += '</ul>';
      $('#result').html(html);
   });
});
  </script>
 </head>
 <body> 
  <div class="box" id="result">   
  </div>  
 </body>
</html>

可見 requests 擷取回來的伺服器回應的原始網頁, 放在 div 裡面的內容是空的, 網頁呈現的書籍列表是靠 Javascript 從 books.json 取得後填入 DOM 中, 但 bs4 無法取得這些由 Javascript 生成的網頁內容, 可用 bs4 物件的 select() 方法取得 id=result 的 Tag 物件, 檢視其 text 屬性為空可證 :  

>>> tag=bs4obj.select("#result")    
>>> tag   
[<div class="box" id="result"></div>] 
>>> tag[0].text       # 內容為空
''   

如果改用 Selenium 就可以抓到這些資料了 : 

>>> from selenium import webdriver   
>>> browser=webdriver.Chrome()      
>>> browser.get("https://fchart.github.io/books.html")      
>>> div=browser.find_element_by_id("result")       # 取得網頁元素 
>>> div.text      # 取得元素之內容
'W101:ASP.NET網頁程式設計\nW102:PHP網頁程式設計\nP102:Java程式設計\nM102:Android程式設計'
>>> browser.quit()     

執行 webdriver.Chrome() 就會開啟一個獨立的 Chrome 瀏覽器, 呼叫 get() 時就會載入網頁並執行 Javascript 生成書籍列表內容. 


三. 使用 Chrome 開發人員工具 :   

在 Chrome 瀏覽器按 F12 或 Ctrl+Shift+I 會顯示開發人員工具, 也可以按右上角頭像右邊那個三個點圖示, 點選 "更多工具/開發人員工具" :




或者在網頁中按滑鼠右鍵, 點選 "檢查" 也會開啟開發人員頁面 (須重載頁面才會有內容) :




其中開發網路爬蟲最常用的頁籤是 "元素" 與 "網路", 前者可看到網頁的最終 HTML 結果 (即完整執行完 Javascript 後的 DOM 結構); 後者則可用來觀察網頁內的資源載入與執行的過程, 也能看到瀏覽器與伺服器之間的 HTTP 通訊細節, 例如請求與回應的標頭, 傳遞了那些參數, 以及伺服器的回應結果等, 可從中找出 Web API 網址與確定爬蟲要傳遞那些參數或 Cookies. 
 

1. 元素 (Elements) :

點選底下開發工具中的 "元素 (Elements)" 會顯示 Javascript 執行後最的 HTML 內容, 這與上面檢視網頁原始碼看到的 HTML 不同, 原始碼的 body 內只有一個空的 div 元素, 而開發工具的 "元素" 中, div 元素裡面卻有 ul-li 清單, 這些內容是客戶端瀏覽器執行 Javascript 後插入到 DOM 結構樹中的. 點 div 內的 ul-li 元素時, 上面的瀏覽器視窗會以高亮背景顯示對應的元件 :




"元素" 頁籤還有一個常用的功能是可以取得元素的選擇器與 XPath, 點底下 HTML 中的任一元素, 按滑鼠右鍵選 "複製/複製 Selector" 或 "複製 XPath" 即可 : 




div 元素的選擇器複製結果為 : #result 
div 元素的 XPath 複製結果為 : //*[@id="result"] 

久沒用 CSS 選擇器與 XPath 時這個功能很好用.


2. 網路 (Network) :

此標籤紀錄 HTTP 請求與回應之過程與細節, 左邊是瀏覽器向伺服器提出的資源請求列表, 其中 books.json 便是 Javascript 透過 Ajax 向伺服器提出的非同步請求, 點 "標頭" 頁籤可以看到請求與回應的標頭內容, 從中可找到瀏覽網頁時夾在標頭中的傳遞參數與 Cookies 等資訊 : 




點 "預覽" 頁籤可看到伺服器回應結果是一個 json 格式資料 :




點 "回應" 頁籤則可看到回應內容 :




沒有留言:

張貼留言