在眾多的網頁中,當要載入的資料量非常龐大時,為了不影響執行效能的情況下,除了會使用滾動捲軸來動態載入更多的資料外,另一種最常見的方式就是利用分頁,來分別顯示特定筆數的資料。
如果Python網頁爬蟲遇到需滾動捲軸,才可爬取更多資料的實作方式,可以參考[Python爬蟲教學]整合Python Selenium及BeautifulSoup實現動態網頁爬蟲文章,而Python網頁爬蟲遇到分頁的網站時,該如何翻頁爬取內容,就是本文要來分享的主題。其中的重點包含:
- HTTP GET vs POST方法
- 頁碼使用GET的方式
- 頁碼使用POST的方式
一、HTTP GET vs POST方法
在說明Python網頁爬蟲讀取分頁的資料前,先來簡單瞭解一下什麼是HTTP的GET及POST方法。
HTTP的GET方法就像明信片,在上面需要撰寫目的地的地址及內容,其中的地址就像是請求的網址,而內容就像是接在網址後面的參數(querystring),只要拿到這個明信片(網址)的人,都知道要寄送到哪裡及內容是什麼。
HTTP的POST方法就像一般的信件,在信封上需撰寫目的地的地址,而信件內容會在信封中,所以拿到這封信的人只知道會寄送到哪裡,但不會知道內容是什麼,就像是知道請求的網址,但是其中送到伺服器端的資料,無法在網址知道。
瞭解了這兩個HTTP方法的基本觀念後,接下來就使用兩個網站,來分別說明頁碼使用GET及POST方式處理的網站,Python網頁爬蟲該如何翻頁爬取資料。
二、頁碼使用GET的方式
這就是典型GET方法的分頁方式,從網址就可以知道目的地網址及傳至伺服器端的頁碼參數(page),當變換page參數的值時,就可以前往對應的頁碼網頁。
接下來,在網頁上按F12鍵,進入開發者模式後,先來看一下要爬取的文章標題HTML原始碼架構,如下圖:
瞭解它的階層架構,就可以利用BeautifulSoup套件爬取第一頁的內容,如下範例:
from bs4 import BeautifulSoup import requests # 連結網站 response = requests.get( "https://www.inside.com.tw/tag/AI?page=1") # HTML原始碼解析 soup = BeautifulSoup(response.text, "html.parser") # 取得所有class為post_title的<h3> titles = soup.find_all("h3", {"class": "post_title"}) for title in titles: print(title.select_one("a").getText()) # 取得標題文字
執行結果
成功爬取第一頁的內容,就可以使用Python迴圈,透過變換網址頁碼參數(page)的方式,翻頁爬取網頁內容了,如下範例:
from bs4 import BeautifulSoup import requests for page in range(1, 4): # 執行1~3頁 # 連結網站 response = requests.get( "https://www.inside.com.tw/tag/AI?page=" + str(page)) # HTML原始碼解析 soup = BeautifulSoup(response.text, "html.parser") # 取得所有class為post_title的<h3> titles = soup.find_all("h3", {"class": "post_title"}) print(f"====================第{str(page)}頁====================") for title in titles: print(title.select_one("a").getText()) # 取得連結的標題文字
範例中只爬取1~3頁的內容,如果要更多頁的話可以自行調整第4行的range()參數。另外,要特別注意的是,Python迴圈讀取range()函式時,page的型別為數值(Integer),所以為了要加在網址後面,需透過str()函式轉型成字串,如範例中第8行。詳細的Python轉型教學可以參考[Python教學]Python數值與型別轉換的重要觀念文章。
三、頁碼使用POST的方式
另一個網站頁碼切換的方式會採用POST方法,就像信件一樣,知道寄送的地址(網址),卻不會知道信封中的內容(送往伺服器的頁碼參數)。
由於是使用POST方法來撈取網頁資料,所以當切換到第二頁時,會發現網址並不會像Inside 硬塞的網路趨勢觀察網站一樣,會出現頁碼的參數,而是和第一頁的網址一模一樣,都沒有動靜。
這時候,就需要結合Selenium套件,透過模擬使用者點擊下一頁按鈕,來進行換頁的動作。同樣先看一下所要爬取的租屋標題HTML原始碼結構,如下圖:
接著,就可以利用Selenium套件開啟瀏覽器並且連線至591房屋交易網的「租屋」類別,再使用BeautifulSoup套件爬取第一頁的租屋標題。首先,利用以下指令安裝開啟瀏覽器的WebDriver套件:
$ pip install webdriver-manager
安裝完成後,就可以按照邏輯撰寫如下的程式碼:
from selenium import webdriver from selenium.webdriver.chrome.options import Options from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup options = Options() options.add_argument("--disable-notifications") # 取消所有的alert彈出視窗 browser = webdriver.Chrome( ChromeDriverManager().install(), chrome_options=options) browser.get("https://rent.591.com.tw/") area = browser.find_element_by_id("area-box-close") area.click() # 取消「選擇縣市」的div視窗 soup = BeautifulSoup(browser.page_source, "html.parser") # 取得所有class為pull-left infoContent的<li>標籤 elements = soup.find_all("li", {"class": "pull-left infoContent"}) for element in elements: # 取得<li>標籤下的<h3>標籤,再取得<h3>標籤下的<a>標籤文字,並且去掉空白 title = element.find("h3").find("a").getText().strip() print(title)
執行結果
由於要點擊下一頁按鈕來進行換頁,所以,來觀察一下頁碼區域的HTML原始碼,如下圖:
from selenium import webdriver from selenium.webdriver.chrome.options import Options from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup options = Options() options.add_argument("--disable-notifications") # 取消所有的alert彈出視窗 browser = webdriver.Chrome( ChromeDriverManager().install(), chrome_options=options) browser.get("https://rent.591.com.tw/") area = browser.find_element_by_id("area-box-close") area.click() # 取消「選擇縣市」的div視窗 soup = BeautifulSoup(browser.page_source, "html.parser") # 取得所有class為pull-left infoContent的<li>標籤 elements = soup.find_all("li", {"class": "pull-left infoContent"}) for element in elements: # 取得<li>標籤下的<h3>標籤,再取得<h3>標籤下的<a>標籤文字,並且去掉空白 title = element.find("h3").find("a").getText().strip() print(title) page_next = browser.find_element_by_class_name("pageNext") page_next.click() # 點擊下一頁按鈕
最後,透過Python迴圈重覆執行以上的動作,來達到動態翻頁爬取網頁內容的目的,如下範例:
from selenium import webdriver from selenium.webdriver.chrome.options import Options from webdriver_manager.chrome import ChromeDriverManager from bs4 import BeautifulSoup import time options = Options() options.add_argument("--disable-notifications") # 取消所有的alert彈出視窗 browser = webdriver.Chrome( ChromeDriverManager().install(), chrome_options=options) browser.get("https://rent.591.com.tw/") area = browser.find_element_by_id("area-box-close") area.click() # 取消「選擇縣市」的div視窗 for page in range(1, 3): # 執行1~2頁 soup = BeautifulSoup(browser.page_source, "html.parser") # 取得所有class為pull-left infoContent的<li>標籤 elements = soup.find_all("li", {"class": "pull-left infoContent"}) print(f"==========第{str(page)}頁==========") for element in elements: # 取得<li>標籤下的<h3>標籤,再取得<h3>標籤下的<a>標籤文字,並且去掉空白 title = element.find("h3").find("a").getText().strip() print(title) page_next = browser.find_element_by_class_name("pageNext") page_next.click() # 點擊下一頁按鈕 time.sleep(10) # 暫停10秒
四、小結
以上就是Python網頁爬蟲在遇到有分頁的網站時,能夠動態換頁爬取網頁內容的實作方式,詳細的程式碼可以參考下方的GitHub網址,希望有幫助到大家。
有想要看的教學內容嗎?歡迎利用以下的Google表單讓我知道,將有機會成為教學文章,分享給大家😊
Python學習資源
Python網頁爬蟲推薦課程
Python網頁爬蟲-BeautifulSoup教學
Python網頁爬蟲-Selenium教學
Python非同步網頁爬蟲
Python網頁爬蟲應用
Python網頁爬蟲部署
Python網頁爬蟲資料儲存
Python網頁爬蟲技巧
留言
張貼留言