Try   HackMD

動態網頁爬蟲-使用Selenium

tags: python selenium crawler

介紹

動態網頁

動態網頁顧名思義,指的就是網頁內容是動態的,每次瀏覽同一個網頁的內容可能都不同,例如: 書本的搜尋,匯率,新聞等等,根據使用者的選擇或輸入不同的互動,動態的產生網頁內容。

客戶端動態網頁

產生有兩種方式:

  • 從網頁伺服器下載JavaScript程式碼,在客戶端執行後產生內容。
  • 透過客戶端的需求,在伺服器端產生內容後,以AJAX(Asynchronous JavaScript And XML)技術下載到客戶端。

伺服器端動態網頁

在網頁伺服器內以伺服器程式語言(如: PHP,ASP.NET或JSP等等)執行後來動態產生網頁後再回應給客戶端。

Selenium

對於爬蟲來說,如果爬取動態網頁內容,只會得到一堆JavaScript程式碼,因為網頁內容需要透過執行JavaScript程式碼後產生,所以對於動態網頁,爬蟲會看不到執行後的結果,所以無法使用Beautiful Soup或lxml來爬取資料。

Selenim為一個跨平台的自動瀏覽器(Automates Browsers),其原本是用來做為Web應用程式的軟體測試框架,本身為開放原始碼,用在爬蟲上,可以做為模擬使用者輸入內容,點擊連結來與網頁作互動。

Selenium套件

Selenium為數個元件組合而成的一個套件,其元件有:

  • Selenium IDE: 一套建立Selenium測試的整合開發環境,附屬在Chrome或Firefox瀏覽器內,可以錄製,編輯和除錯建立的Selenium測試。
  • Selenium Client API: 可以直接使用程式語言來建立Selenium測試,支援: Java,Ruby,JavaScript,C#和Pythonx來跟Selenium WebDriver通訊。
  • Selenium WebDriver: 接收來自Selenium API的命令來控制瀏覽器,支援Chrome,Firefox,Safari,Microsoft Edge ,IE等瀏覽器。

安裝Selenium

對Python來說,需要安裝有個,一個是Selenium Client API(也就是Python模組),另一個就是WebDriver,。

安裝Selenium Client API

pip3 install selenium

安裝WebDriver

步驟一: 下載

https://www.selenium.dev/documentation/webdriver/getting_started/install_drivers/

備註:

  1. Selenium 4.6版(包含)以後不需要再下載driver了。
  2. Selenium 4.5版以前請下載對應瀏覽器的WebDriver

注意:

  • WebDriver並非下載最新版本就好,而是下載的版本必須和你的瀏覽器版本一樣,例如你的Chrome瀏覽器是106版,那WebDriver就要下載106版的。
    Windows作業系統請下載chromedriver_win32.zip即可。
解壓縮

將下載的zip檔案解壓縮到你的Python程式目錄下。

Selenium基本操作

引入selenium的webdriver物件

from selenium import webdriver

初始化WebDriver

driver = webdriver.Chrome('chromedriver')

注意:

如果是在MacOS下,如果和Python放在同一層目錄,需要額外加上代表目前路徑的./符號,如:

driver = webdriver.Chrome('./chromedriver')

設定等待網頁載入的時間,如果提早載入完成,會提早結束等待,如果時間不夠,讀到的網頁內容會有殘缺:

driver.implicitly_wait(10)

連線到網站:

driver.get('https://rate.bot.com.tw/xrt?Lang=zh-TW')

印出網頁標題:

print(driver.title)

取得網頁內容並印出:

html = driver.page_source
print(html)

也可以利用BeautifulSoup來分析網頁內容:

soup = BeautifulSoup(driver.page_source, 'lxml')
print(soup.prettify())

將取得的網頁內容存到本地端:

with open('index.html', 'w', encoding='utf-8',) as file:
    file.write(soup.prettify())

關閉WebDriver, 瀏覽器也會跟著關閉:

driver.quit()

完整程式碼

from selenium import webdriver from bs4 import BeautifulSoup import requests driver = webdriver.Chrome('chromedriver') driver.implicitly_wait(10) driver.get('https://rate.bot.com.tw/xrt?Lang=zh-TW') print(driver.title) html = driver.page_source print(html) soup = BeautifulSoup(driver.page_source, 'lxml') print(soup.prettify()) with open('index.html', 'w', encoding='utf-8',) as file: file.write(soup.prettify()) driver.quit()

Selenium資料定位

Selenium有兩個系列的資料定位函式:

  • find_element(): 用來取得網頁中的第一個定位到的HTML元素。
  • find_elements(): (名稱中多了一個s),用來取得所有網頁中定位到的元素。

這兩個函式都可以使用下面方式來定位元素:

名稱 說明
"id" 使用id屬性值來定位元素
"name" 使用name屬性值來定位元素
"xpath" 使用XPath表達式來定位元素
"link text" 使用超連結文字來定位元素
"partial link text" 使用部分超連結文字來定位元素
"tag name" 使用標籤名稱來定位元素
"class name" 使用class屬性值來定位元素
"css selector" 使用CSS選擇器來定位元素
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"

定位台灣銀行匯率下載CSV按鈕,並模擬點擊來下載檔案

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
from bs4 import BeautifulSoup
import requests

driver = webdriver.Chrome('chromedriver')
driver.implicitly_wait(10)
driver.get('https://rate.bot.com.tw/xrt?Lang=zh-TW')
print(driver.title)
html = driver.page_source

try:
    download_csv = driver.find_element(By.LINK_TEXT, '下載 Excel (CSV) 檔')
    print(download_csv.tag_name)
    print(download_csv.get_attribute('href'))

    download_csv.click()
except NoSuchElementException:
    print('無法定位')
driver.quit()

備註:
下載的檔案名稱會跟直接從網站下載的檔名不同

Selenium動作函式:

名稱 說明
click() 點擊元素
click_and_hold() 在元素上按住滑鼠左鍵
context_click() 在元素上按住滑鼠右鍵
double_click() 點擊兩次元素
move_to_element() 移動滑鼠游標到元素中間
key_up() 放開鍵盤的按鍵
key_down() 按下鍵盤的按鍵
perform() 執行所有儲存的動作
send_keys() 送出按鍵到元素
release() 在元素上鬆開滑鼠按鍵

執行JavaScript程式碼

使用 Selenium 滾動網頁捲軸(scrollBar)
driver.execute_script('window.scrollBy(0,1000)')

說明:
scrollBy(x,y)中,x為必須參數,表示向右滾動的像素值;y也為必須參數,表示向下滾動的像素值

driver.execute_script('window.scrollTo(0,1000)')

說明:
scrollTo(x,y) 中,x為必要參數,表示要在視窗顯示區左上角顯示的x坐標;y也為必要參數,表示要在視窗顯示區左上角顯示的y坐標

捲軸拉到底
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')

driver.execute_script('window.scrollTo(0,document.documentElement.scrollHeight)')

send_key()常用的按鍵代碼

ENTER SHIFT LEFT_SHIFT CONTROL LEFT_CONTROL ALT LEFT_ALT SPACE

Selenium例外物件

名稱 說明
ElementNotSelectableException 選取的該元素不允許被選取
ElementNotVisibleException 元素存在,但是不可見
ErrorInResponseException 伺服器端回應錯誤
NoSuchElementException 選取的元素不存在
TimeoutException 超過時間限制