跳到主要內容

[Python爬蟲教學]Python網頁爬蟲動態翻頁的實作技巧

how_to_scrape_different_pages_using_python_scraper
Photo by True Agency on Unsplash
在眾多的網頁中,當要載入的資料量非常龐大時,為了不影響執行效能的情況下,除了會使用滾動捲軸來動態載入更多的資料外,另一種最常見的方式就是利用分頁,來分別顯示特定筆數的資料。

如果Python網頁爬蟲遇到需滾動捲軸,才可爬取更多資料的實作方式,可以參考[Python爬蟲教學]整合Python SeleniumBeautifulSoup實現動態網頁爬蟲文章,而Python網頁爬蟲遇到分頁的網站時,該如何翻頁爬取內容,就是本文要來分享的主題。其中的重點包含:
  • HTTP GET vs POST方法
  • 頁碼使用GET的方式
  • 頁碼使用POST的方式

一、HTTP GET vs  POST方法

在說明Python網頁爬蟲讀取分頁的資料前,先來簡單瞭解一下什麼是HTTPGETPOST方法。

HTTPGET方法就像明信片,在上面需要撰寫目的地的地址及內容,其中的地址就像是請求的網址,而內容就像是接在網址後面的參數(querystring),只要拿到這個明信片(網址)的人,都知道要寄送到哪裡及內容是什麼。

HTTPPOST方法就像一般的信件,在信封上需撰寫目的地的地址,而信件內容會在信封中,所以拿到這封信的人只知道會寄送到哪裡,但不會知道內容是什麼,就像是知道請求的網址,但是其中送到伺服器端的資料,無法在網址知道。

瞭解了這兩個HTTP方法的基本觀念後,接下來就使用兩個網站,來分別說明頁碼使用GETPOST方式處理的網站,Python網頁爬蟲該如何翻頁爬取資料。

二、頁碼使用GET的方式

大部分的網站分頁,都是使用GET方法來處理,這邊以Inside 硬塞的網路趨勢觀察網站的「AI類別為例,可以看到網址如下:
how_to_scrape_different_pages_using_python_scraper
當切換至第二頁時,網址為:
how_to_scrape_different_pages_using_python_scraper
這就是典型GET方法的分頁方式,從網址就可以知道目的地網址及傳至伺服器端的頁碼參數(page),當變換page參數的值時,就可以前往對應的頁碼網頁。

接下來,在網頁上按F12鍵,進入開發者模式後,先來看一下要爬取的文章標題HTML原始碼架構,如下圖:
how_to_scrape_different_pages_using_python_scraper
瞭解它的階層架構,就可以利用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())  # 取得標題文字
執行結果
how_to_scrape_different_pages_using_python_scraper
成功爬取第一頁的內容,就可以使用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方法,就像信件一樣,知道寄送的地址(網址),卻不會知道信封中的內容(送往伺服器的頁碼參數)。

這邊以591房屋交易網的「租屋類別為例,可以看到網址如下:
how_to_scrape_different_pages_using_python_scraper
由於是使用POST方法來撈取網頁資料,所以當切換到第二頁時,會發現網址並不會像Inside 硬塞的網路趨勢觀察網站一樣,會出現頁碼的參數,而是和第一頁的網址一模一樣,都沒有動靜。

這時候,就需要結合Selenium套件,透過模擬使用者點擊下一頁按鈕,來進行換頁的動作。同樣先看一下所要爬取的租屋標題HTML原始碼結構,如下圖:
how_to_scrape_different_pages_using_python_scraper
接著,就可以利用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)
執行結果
how_to_scrape_different_pages_using_python_scraper
由於要點擊下一頁按鈕來進行換頁,所以,來觀察一下頁碼區域的HTML原始碼,如下圖:
how_to_scrape_different_pages_using_python_scraper
得知下一頁按鈕的樣式類別(class)為「pageNext」後,就可以利用Selenium套件進行元素的定位與點擊換頁了,如下範例
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網址,希望有幫助到大家。

如果您喜歡我的文章,請幫我按五下Like(使用GoogleFacebook帳號免費註冊),支持我創作教學文章,回饋由LikeCoin基金會出資,完全不會花到錢,感謝大家。

有想要看的教學內容嗎?歡迎利用以下的Google表單讓我知道,將有機會成為教學文章,分享給大家😊

Python學習資源
Python網頁爬蟲推薦課程
    Python網頁爬蟲-BeautifulSoup教學
    Python網頁爬蟲-Selenium教學
    Python非同步網頁爬蟲
    Python網頁爬蟲應用
    Python網頁爬蟲部署
    Python網頁爬蟲資料儲存
    Python網頁爬蟲技巧









    留言

    1. 你好,謝謝你詳細的分享~~想另外請教一下,目前的教學比較著重在去爬「已知網站」的網頁資料;那如果是想要爬「未知網站」的資料,因為是未知的網頁結構,會有比較建議用什麼方式或套件嗎~應用場景大概是:使用者在前端輸入某個網址,後端(預計用python爬蟲)要提供出這個網址的文章內容

      回覆刪除
      回覆
      1. 我蠻好奇的。因為你的留言已經過一年了。不知道你解決了嗎?因為就目前我學爬蟲的部分,未知的網頁應該看起來是沒辦法抓取吧?因為光是已知的狀態之下,你要知道位置定位才能抓到,更何況如果是未知的?謝謝

        刪除
      2. 嗨,後來是 import 一個開源套件 去試著實作,叫 Readability,github 網址:https://github.com/buriy/python-readability。這個 lib 的原理應該是用大部分網址應有的架構去抓出網頁的內容,不過實作起來,效果沒有很好,十個網頁大概只能有約4.5個可完整抓出(越單純網頁效果越好),提供你參考~謝謝

        刪除
      3. 謝謝你的回覆。聽起來是蠻合理的。因為複雜的網頁定位抓取就是比較麻煩一點。所以如果是未知的,照著整體一般架構去抓,的確就是越單純越好。

        刪除

    張貼留言