Selenium 網路爬蟲的王者
Selenium 網路爬蟲的王者
前言
在前面我們有介紹有些網頁伺服器會阻擋網路爬蟲讀取網頁內容,我們可以使用 headers 的宣告,將爬蟲程式偽裝成瀏覽器,這樣我們克服了讀取網頁內容的障礙。
Selenium 功能可以控制瀏覽器,所以當使用 Selenium 當爬蟲工具時,網路伺服器會認為來讀取資料的是瀏覽器,所以不會有被阻擋無法讀取網頁 HTML 原始檔的問題。當然則 Selenium 不只如此,可以使用它按連結、填寫登入資訊、甚至訂票系統、搶購系統.....等。
大綱
- 順利使用Selenium 工具前的安裝工作
- 獲得webdriver 的物件型態
- 擷取網頁
- 尋找 HTML 文件的元素
- XPath 語法
- 認識HTML的架構
- 絕對路徑與相對路徑
- 索引爬取重複的元素
- 元素的屬性
- 列出屬性值
- contains()
- 隱藏參數與等待網頁載入
- 進入Chrome 開發工具觀察 XPath 運作
- Chrome 外掛套件 ChroPath
- 用 Python 控制點選超連結
- 用 Python 填寫表單和送出
- 用 Python 處理使用網頁的特殊按鍵
- 用 Python 處理瀏覽器運作
- 自動進入 Google 系統
- 自動化下載環保署空氣品質資料
順利使用 Selenium 工具前的安裝工作
如果想要在 Windows 系統內順利使用 Selenium 執行工作,必須安裝下列三項工具以及一個設定。
- Selenium 工具。
- 瀏覽器 : 使用 Selenium 市面上最常使用的是安裝 Firefox,也可以是Chrome。本文將以 Firefox 為主要說明,另外也會說明安裝 Chrome方式。
- 驅動程式 : 這是指 Selenium 驅動瀏覽器的程式,其實這部分資訊很重要,卻是目前極少文件有說明,因此常造成讀者學習上的障礙,因為依照一般說明結果,是錯誤訊息。
安裝 Selenium
安裝
pip install selenium
導入
from selenium import webdriver
安裝驅動程式
Selenium 需要一個驅動程序來與所選瀏覽器互動。 例如 : Firefox,需要 geckodriver,它需要在運行以下範例之前安裝。 確保它在您的 PATH 中,例如 : 將它放在 /usr/bin 或 /usr/local/bin 中。
若少安裝這一步會給你一個錯誤 "error selenium.common.exceptions.WebDriverException: Message: ‘geckodriver’ executable needs to be in PATH."。
其他受支持的瀏覽器將有自己的驅動程序可用。 一些更流行的瀏覽器驅動程序的鏈接如下:
- Chrome : https://chromedriver.chromium.org/downloads
- Edge : https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/
- Firefox : https://github.com/mozilla/geckodriver/releases
- Safari : https://webkit.org/blog/6900/webdriver-support-in-safari-10/
驅動程式的安裝需要幾個步驟
- 下載與解壓縮。
- 將驅動程式放在 PATH 路徑內。
- 將驅動程式路徑放在 Python 程式內。
Firefox 安裝驅動程式為例
點選 Firefox驅動程式的連結 => 選擇 geckodriver-v0.30.0-win64.zip 的版本 => 下載存放路徑, 這裡我們的驅動程式路徑為 C:\driver ,未來這個檔案路徑配合參數設定,放在 webdriver.Firefox() 內,就可正確執行了。
Chrome 安裝驅動程式為例
點選 Chrome 驅動程式的連結 => 選擇 ChromeDriver 95.0.4638.17 的版本 => 下載存放路徑, 這裡我們的驅動程式路徑為 C:\driver ,未來這個檔案路徑配合參數設定,放在 webdriver.Chrome() 內,就可正確執行了。
獲得webdriver 的物件型態
使用 Selenium 的第一步是獲得 webdriver 物件。
Firefox 瀏覽器為例
範例 pythonSelenium-02.py : 列出 webdriver 物件型態。
# pythonSelenium-02.py from selenium import webdriver driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) print(type(browser))
執行結果
<class 'selenium.webdriver.firefox.webdriver.WebDriver'>
這個程式在執行時,螢幕將出現 'c:\driver\geckodriver.exe' 視窗,讀者可以不用理會。接著,會啟動 Firefox 視窗,因為我們沒有設定找尋任何網頁,所以視窗是空白的,不過在 Python Shell 視窗可以看到程式的執行結果。
上述程式的重點是第5行,我們將參數 “executable_path=driverPath” 當作參數設在 webdriver.Firefox() 內,driverPath 主要是設定驅動程式的位置在第4行設定,如果不這樣,也可以將 c:\driver 路徑設在系統 PATH 內,此時可以省略第4行和 webdriver.Firefox() 參數設定。最後程式印出來變數 browser 的物件類別
Chrome 瀏覽器為例
範例 pythonSelenium-03.py : 列出 webdriver 物件型態。
# pythonSelenium-03.py from selenium import webdriver dirverPath = 'c:\driver\chromedriver.exe' browser = webdriver.Chrome(dirverPath) print(type(browser))
執行結果
<class 'selenium.webdriver.chrome.webdriver.WebDriver'>
這個程式在執行時,螢幕將出現 'c:\driver\chromedriver.exe' (這是筆者放置 chromedriver.exe 檔案路徑)的視窗,讀者可以不必理會,接著會啟動 Chrome 視窗,因為我們沒有設定找尋任何網頁,所以視窗是空白的,不過 Python Shell 視窗可以看到程式的執行結果。
上述程式的重點是第5行,我們將參數 "driverPath" 當作參數設在 webdrive.Chrome() 內,driverPath 主要是設定驅動程式的檔案路徑在第4行設定。最後程式印出來變數 browser 的物件類別。
擷取網頁
獲得 browser 物件後,可以使用 get() 讓瀏覽器連上網頁。
範例 pythonSelenium-04.py : 讓瀏覽器連上網頁與列印網頁標題。
# pythonSelenium-04.py from selenium import webdriver driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) url = 'https://icook.tw/' browser.get(url) # 網頁下載至瀏覽器
執行結果
由於上述程式沒有輸出任何資料,所以 Python Shell 視窗沒有任何結果,另外,由 webbrowser 物件啟動的 Firefox 視窗將可以看到所載入的網頁。下列是 webdriver 常見的屬性 :
- name : 瀏覽器名稱
- title : 網頁標題
- page_source : 網頁的原始碼
- current_url : 目前的網址
- session_id : 網頁連線ID
- capabilities : 瀏覽器功能設定
下列是常見的方法,對於所取得的瀏覽器位置與大小皆是以字典方式顯示結果 ,(x, y) 是座標, (width, height) 是大小。
- get_window_position() : 取得瀏覽器視窗左上角位置
- set_window_position() : 設定(x, y) 為瀏覽器視窗左上角位置
- get_window_size() : 取得瀏覽器視窗大小
- set_window_size(x, y) : 設定 (x, y) 為瀏覽器視窗大小
- maximize_window() : 設定瀏覽器視窗最大化
範例 pythonSelenium-04-1.py : 列出網頁的 HTML 原始碼 。
# pythonSelenium-04-1.py from selenium import webdriver driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) url = 'https://icook.tw/' browser.get(url) # 網頁下載至瀏覽器 print(browser.page_source) # 列印網頁原始碼
執行結果
Firefox 瀏覽器會打開網頁 https://icook.tw/ ,並且列印網頁原始碼
範例 pythonSelenium-04-2.py : 列出 name、current_url、session_id 和 capabilities 屬性。
# pythonSelenium-04-1.py from selenium import webdriver driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) url = 'https://icook.tw/' browser.get(url) # 網頁下載至瀏覽器 print(browser.page_source) # 列印網頁原始碼
執行結果
瀏覽器名稱 = firefox 網頁url = https://icook.tw/ 網頁連線id = ff973e9c-212b-4f1f-8a0a-c73aa97b0f33 瀏覽器功能 = {'acceptInsecureCerts': True, 'browserName': 'firefox', 'browserVersion': '93.0', 'moz:accessibilityChecks': False, 'moz:buildID': '20210927210923', 'moz:debuggerAddress': 'localhost:52392', 'moz:geckodriverVersion': '0.30.0', 'moz:headless': False, 'moz:processID': 7704, 'moz:profile': 'C:\\Users\\Administrator\\AppData\\Local\\Temp\\rust_mozprofileDZ6B33', 'moz:shutdownTimeout': 60000, 'moz:useNonSpecCompliantPointerOrigin': False, 'moz:webdriverClick': True, 'pageLoadStrategy': 'normal', 'platformName': 'windows', 'platformVersion': '10.0', 'proxy': {}, 'setWindowRect': True, 'strictFileInteractability': False, 'timeouts': {'implicit': 0, 'pageLoad': 300000, 'script': 30000}, 'unhandledPromptBehavior': 'dismiss and notify'}
範例 pythonSelenium-04-3.py : 每隔5秒瀏覽一個網站。
# pythonSelenium-04-3.py
from selenium import webdriver
import time
urls = ['https://icook.tw/',
'http://www.mcut.edu.tw',
'http://www.siliconstone.com']
driverPath = 'c:\driver\geckodriver.exe'
browser = webdriver.Firefox(executable_path=driverPath)
for url in urls:
browser.get(url) # 網頁下載至瀏覽器
time.sleep(5)
browser.quit()
尋找 HTML 文件的元素
使用 Selenium 建立 browser 物件時,可以使用下列方法獲得 HTML 文件的元素(WebElement),在下列方法中 find_element_* 可以找到一個符合的元素,find_elements_* 則可以找到所有相符的元素同時用串列傳回。
- find_element_by_id(id) : 傳回第一個相符ID的元素。
- find_elements_by_id(id) : 傳回所有相符的ID的元素,以串列的方式傳回。
- find_element_by_class_name(name) : 傳回第一個相符 Class 的元素。
- find_elements_by_class_name(name) : 傳回所有相符的 Class 的元素,以串列方式傳回。
- find_element_by_name(name) : 傳回第一個相符 name 屬性的元素。
- find_elements_by_name(name) : 傳回所有相符的 name 屬性的元素,以串列方式傳回。
- find_element_by_css_selector(selector) : 傳回第一個相符 CSS Selector 的元素。
- find_elements_by_css_selector(selector) : 傳回所有相符的 CSS Selector 的元素,以串列方式傳回。
- find_element_by_partial_link_text(text) : 傳回第一個內含有 text 的 <a> 元素。
- find_elements_by_partial_link_text(text) : 傳回所有內含相符 text 的 <a> 元素,以串列方式傳回。
- find_element_by_link_text(text) : 傳回第一個完全相同 text 的 <a> 元素。
- find_elements_by_link_text(text) : 傳回所有完全相同 text 的 <a> 元素,以串列方式傳回。
- find_element_by_tag_name(name) : 不區分大小寫,傳回第一個相符name 的元素,例如 : <p> 與 <P> 是一樣的。
- find_elements_by_tag_name(name) : 不區分大小寫,傳回所有相符的name 的元素,以串列方式傳回,例如 : <p> 與 <P> 是一樣的。
上述方法如果沒有找到相符的,會產生 NoSuchElement 異常,如果我們期待沒有找到時,程式不要列出錯誤而結束,可以使用 try…..except 執行例外處理。
找到 HTML 元素物件後,可以使用下列方式方法或屬性獲得 HTML 元素物件的內容。
- tag_name : 元素名稱。
- text : 元素內容。
- location : 這是字典,內含有 x 和 y 鍵值,表示元素在頁面上的座標。
- clear() : 可以刪除在文字 (text) 欄位和文字區域 (textarea) 欄位的文字。
- get_attribute(name) : 可以獲得這個元素 name 屬性的值。
- is_displayed() : 如果元素可以看到傳回 True,否則傳回 False。
- is_enabled() : 如果元素是可以立即使用則傳回 True,否則傳回 False。
- is_selected() : 如果元素的核取方塊有勾選則傳回 True,否則傳回 False。
範例 pythonSelenium-05.py : 找不到符合條件的元素,造成程式結束的範例 。
# pythonSelenium-05.py from selenium import webdriver driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) url = 'https://icook.tw/' browser.get(url) # 網頁下載至瀏覽器 tag = browser.find_element_by_id('main') print(tag.tag_name)
可以使用下列方式處理。
範例 pythonSelenium-06.py : 找不到符合條件的元素,執行例外處理 。
# pythonSelenium-06.py from selenium import webdriver driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) url = 'https://icook.tw/' browser.get(url) # 網頁下載至瀏覽器 try: tag = browser.find_element_by_id('main') print(tag.tag_name) except: print("沒有找到相符的元素")
執行結果
沒有找到相符的元素
範例 pythonSelenium-07.py : 抓取不同元素的應用 。
# pythonSelenium-07.py from selenium import webdriver driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) url = 'http://127.0.0.1:5500/htmlExampleBS4-02.html' browser.get(url) # 網頁下載至瀏覽器 print("網頁標題內容是 = ", browser.title) tag2 = browser.find_element_by_id('header') # 傳回<h1 id='header'> print("\n標籤名稱 = %s, 內容是 = %s " % (tag2.tag_name, tag2.text)) tag4 = browser.find_elements_by_tag_name('p') # 傳回<p> for t4 in tag4: print("標籤名稱 = %s, 內容是 = %s " % (t4.tag_name, t4.text)) tag5 = browser.find_elements_by_tag_name('img') # 傳回<img> for t5 in tag5: print("標籤名稱 = %s, 內容是 = %s " % (t5.tag_name, t5.get_attribute('src')))
執行結果
tag2 = browser.find_element_by_id('header') # 傳回<h1 id='header'> 標籤名稱 = h1, 內容是 = 這是表頭區塊 tag4 = browser.find_elements_by_tag_name('p') # 傳回<p> 標籤名稱 = p, 內容是 = 人物介紹-1 標籤名稱 = p, 內容是 = 人物介紹-2 標籤名稱 = p, 內容是 = 人物介紹-2 tag5 = browser.find_elements_by_tag_name('img') # 傳回<img> 標籤名稱 = img, 內容是 = http://127.0.0.1:5500/media/components/user-1.jpg 標籤名稱 = img, 內容是 = http://127.0.0.1:5500/media/components/user-2.jpg 標籤名稱 = img, 內容是 = http://127.0.0.1:5500/media/components/user-3.jpg
XPath 語法
在前一小節,我們使用了 find_element_by 系列指令,應用在搜尋網頁的節點,其實可以發現我們搜尋了 id、name、class,如果 HTML 文件沒有這些則搜尋會有困難。這一節,我們將介紹相對路徑方式搜尋網頁的節點 find_element_by_xpath() 的方法。
XPath 全名是 XML Path,主要是可以用來查詢 HTML/XML 文件的所有元素,在 XPath 中所有的 HTML/XML 元素皆是一個節點,整個文件是一個樹狀結構,本書所述是使用 XPath 查詢 HTML 文件的節點,這個觀念也可以應用在 XML 文件。
認識HTML的架構
範例 htmlExampleBS4-02.html : 簡單的 HTML 文件。
<!doctype html> <html lang="zh-Hant-TW"> <head> <meta charset="utf-8"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> <title>htmlExampleBS4-02.html</title> <style> header { background-color: rgb(218, 180, 231); min-height: 100px; } main { background-color: rgb(239, 238, 238); min-height: 300px; } footer { min-height: 80px; } </style> </head> <body> <header class="d-flex justify-content-center align-items-center"> <h1 class="text-center" id='header'>這是表頭區塊</h1> </header> <main> <h1 class="text-center">這是主要內容區</h1> <section class="d-flex justify-content-center align-items-center"> <div class="card" style="width: 18rem;"> <img src="media/components/user-1.jpg" class="card-img-top" alt="card-1"> <div class="card-body"> <p class="card-text text-center" data-author='author1'>人物介紹-1</p> </div> </div> <div class="card" style="width: 18rem;"> <img src="media/components/user-2.jpg" class="card-img-top" alt="card-2"> <div class="card-body"> <p class="card-text text-center" data-author='author2'>人物介紹-2</p> </div> </div> <div class="card" style="width: 18rem;"> <img src="media/components/user-3.jpg" class="card-img-top" alt="card-2"> <div class="card-body"> <p class="card-text text-center" data-author='author3'>人物介紹-2</p> </div> </div> </section> </main> <footer class="bg-dark text-white d-flex justify-content-center align-items-center"> <h3 class="text-center">這是表尾</h3> </footer> <!-- Bootstrap Bundle with Popper --> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> </body> </html>
執行結果
此範例所有節點的樹狀結構如下:
往們將使用上圖來講解各節點的觀念。
- 根節點 ( Root Node ) : <html> 就是根結點。
- 父節點 ( Parent Node ) : <html> 是 <head> 和 <body> 的父節點。
- 子節點 ( Children Node ) : <head> 和 <body> 是 <html> 的子節點。
- 相鄰節點 ( Sibling Node ) : <head> 和 <body> 有共同的 <html> 父節點,所以彼此為相鄰節點。 <header> 和 <main> 有共同的 <body> 父節點,所以他們也是為相鄰節點。
絕對路徑與相對路徑
XPath 用絕對路徑與相對路徑標示各節點,其中 "/" 標示為絕對路徑, "//" 標示為相對路徑,這兩個標示可以交互使用。一般來說 "//" 相對路徑較常使用。我們以下圖示說明絕對路徑與相對路徑 :
範例 pythonSelenium-08.py : 使用 htmlExampleBS4-02.html 驗證相對路徑節點 。
# pythonSelenium-08.py from selenium import webdriver driverPath = 'c:\driver\chromedriver.exe' browser = webdriver.Chrome(executable_path=driverPath) url = 'F:\GoogleDrive\Coding\CodeIndex\Example-Python\Examples\htmlExampleBS4-02.html' browser.get(url) # 網頁下載至瀏覽器 n1 = browser.find_element_by_xpath('//h1') print(n1.text) n2 = browser.find_element_by_xpath('//body/header/h1') print(n2.text) n3 = browser.find_element_by_xpath('//header/h1') print(n3.text) n4 = browser.find_element_by_xpath('//body/*/h1') print(n4.text)
執行結果
n1 = browser.find_element_by_xpath('//h1') 這是表頭區塊 n2 = browser.find_element_by_xpath('//body/*/h1') 這是表頭區塊 n3 = browser.find_element_by_xpath('//header/h1') 這是表頭區塊 n4 = browser.find_element_by_xpath('//body/*/h1') 這是表頭區塊
範例 pythonSelenium-08-1.py : 使用 htmlExampleBS4-02.html 找出第一個 <p> ,<p>元素共有3個,第一個是 "人物介紹-1" 。
# pythonSelenium-08-1.py from selenium import webdriver driverPath = 'c:\driver\chromedriver.exe' browser = webdriver.Chrome(executable_path=driverPath) url = 'F:\GoogleDrive\Coding\CodeIndex\Example-Python\Examples\htmlExampleBS4-02.html' browser.get(url) # 網頁下載至瀏覽器 n1 = browser.find_element_by_xpath('//p') print(n1.text)
執行結果
n1 = browser.find_element_by_xpath('//p') 人物介紹-1
索引爬取重複的元素
在 htmlExampleBS4-02.html 文件中,我們有3個 <p> 元素,上面我們只列出第一個元素,如果我們想列出不同的元素,可以使用索引方式處理。
範例 pythonSelenium-08-2.py : 在 htmlExampleBS4-02.html 文件中<p>元素共有3個,找出第1、2個 <p> 元素 。
# pythonSelenium-08-2.py from selenium import webdriver driverPath = 'c:\driver\chromedriver.exe' browser = webdriver.Chrome(executable_path=driverPath) url = 'F:\GoogleDrive\Coding\CodeIndex\Example-Python\Examples\htmlExampleBS4-02.html' browser.get(url) # 網頁下載至瀏覽器 n1 = browser.find_element_by_xpath("//section/div[1]/div/p") print(n1.text) n2 = browser.find_element_by_xpath("//section/div[2]/div/p") print(n2.text)
執行結果
n1 = browser.find_element_by_xpath("//section/div[1]/div/p") 人物介紹-1 n2 = browser.find_element_by_xpath("//section/div[2]/div/p") 人物介紹-2
元素的屬性
在 htmlExampleBS4-02.html 文件中,有3個 <p> 元素,第2個 <p> 元素內有 data-author='author2' ,我們稱 "data-author" 為屬性 attribute, 第3個 <p> 元素內有 data-author='author3',我們可以使用屬性列印出我們想要的節點。
範例 pythonSelenium-08-3.py : 在 htmlExampleBS4-02.html 文件中<p>元素共有3個,找出第2、3個 <p> 元素 。
# pythonSelenium-08-3.py from selenium import webdriver driverPath = 'c:\driver\chromedriver.exe' browser = webdriver.Chrome(executable_path=driverPath) url = 'F:\GoogleDrive\Coding\CodeIndex\Example-Python\Examples\htmlExampleBS4-02.html' browser.get(url) # 網頁下載至瀏覽器 n1 = browser.find_element_by_xpath("//section/*/*/p[@data-author='author2']") print(n1.text) n1 = browser.find_element_by_xpath("//section/*/*/p[@data-author='author3']") print(n1.text)
執行結果
n1 = browser.find_element_by_xpath("//section/*/*/p[@data-author='author2']") 人物介紹-2 n1 = browser.find_element_by_xpath("//section/*/*/p[@data-author='author3']") 人物介紹-3
列出屬性值
範例 pythonSelenium-08-4.py : 在 htmlExampleBS4-02.html 文件中,列出圖片的完整路徑。
# pythonSelenium-08-4.py from selenium import webdriver driverPath = 'c:\driver\chromedriver.exe' browser = webdriver.Chrome(executable_path=driverPath) url = 'F:\GoogleDrive\Coding\CodeIndex\Example-Python\Examples\htmlExampleBS4-02.html' browser.get(url) # 網頁下載至瀏覽器 pict = browser.find_element_by_xpath("//section/div/img") print(pict.get_attribute('src'))
執行結果
pict = browser.find_element_by_xpath("//section/div/img") file:///F:/GoogleDrive/Coding/CodeIndex/Example-Python/Examples/media/components/user-1.jpg
範例 pythonSelenium-08-5.py : 以 htmlExampleBS4-02.html 為例,說明屬性的用法。
# pythonSelenium-08-5.py from selenium import webdriver driverPath = 'c:\driver\chromedriver.exe' browser = webdriver.Chrome(executable_path=driverPath) url = 'F:\GoogleDrive\Coding\CodeIndex\Example-Python\Examples\htmlExampleBS4-02.html' browser.get(url) # 網頁下載至瀏覽器 n1 = browser.find_element_by_xpath("//h1/em") print('em : ', n1.text) n2 = browser.find_element_by_xpath("//h1") print('h1 : ', n2.text) n3 = browser.find_element_by_xpath("//h1") print('textContent : ', n3.get_attribute('textContent')) n4 = browser.find_element_by_xpath("//h1") print('innerHTML : ', n4.get_attribute('innerHTML')) n5 = browser.find_element_by_xpath("//h1") print('outerHTML : ', n5.get_attribute('outerHTML'))
執行結果
n1 = browser.find_element_by_xpath("//h1/em") em : 表頭區塊 n2 = browser.find_element_by_xpath("//h1") h1 : 這是表頭區塊 n3 = browser.find_element_by_xpath("//h1") textContent : 這是表頭區塊 n4 = browser.find_element_by_xpath("//h1") innerHTML : 這是<em>表頭區塊</em> n5 = browser.find_element_by_xpath("//h1") outerHTML : <h1 class="text-center" id="header">這是<em>表頭區塊</em></h1>
contains()
當網頁有多個元素重複時,XPath 也包含 contains() 方法讓我們找出包含某個字串的元素節點。
範例 pythonSelenium-08-6.py : 以 htmlExampleBS4-02.html 為例,使用 contains() 方法,找出節點的 outerHTML 和 data-author 屬性。
# pythonSelenium-08-6.py from selenium import webdriver driverPath = 'c:\driver\chromedriver.exe' browser = webdriver.Chrome(executable_path=driverPath) url = 'F:\GoogleDrive\Coding\CodeIndex\Example-Python\Examples\htmlExampleBS4-02.html' browser.get(url) # 網頁下載至瀏覽器 n = browser.find_element_by_xpath("//div[@class='card-body']//p[contains(text(),'人物介紹-2')]") print(n.get_attribute('outerHTML')) print(n.get_attribute('data-author'))
執行結果
<p class="card-text text-center" data-author="author2">人物介紹-2</p> author2
隱藏參數與等待網頁載入
在先前程式設計時,每次就會開啓 Chrome 瀏覽器,顯示所開啟的網頁,若是不喜歡看到開啟網頁,可以增加設定 “headless” 隱藏參數,未來程式執行時,可以不用再開啟瀏覽器。相關實作可以參考下列範例第5-7行。
另外有的程式設計師喜歡在 get(url) 前先使用 implicitly_wait(seconds) 指令,等待網頁載入,再執行 get(url) 。如果參數設定等待5秒,實際只需3秒即可載入網頁,程式也可以在網頁下載完成立即執行 get(url) 指令,相關實作可以參考下列範例第9行。
範例 pythonSelenium-08-7.py : 以重新設計 範例 pythonSelenium-08-6.py ,增加隱藏參數與等待網頁載入設定。
# pythonSelenium-08-7.py from selenium import webdriver driverPath = 'c:\driver\chromedriver.exe' headless = webdriver.ChromeOptions() headless.add_argument('headless') # 隱藏參數 browser = webdriver.Chrome(executable_path=driverPath, options=headless) url = 'F:\GoogleDrive\Coding\CodeIndex\Example-Python\Examples\htmlExampleBS4-02.html' browser.implicitly_wait(5) # 等待網頁載入 browser.get(url) # 網頁下載至瀏覽器 n = browser.find_element_by_xpath("//div[@class='card-body']//p[contains(text(),'人物介紹-2')]") print(n.get_attribute('outerHTML')) print(n.get_attribute('data-author'))
執行結果
結果同範例 pythonSelenium-08-6.py,並且不再出現瀏覽器。
進入Chrome 開發工具觀察 XPath 運作
使用 Chrome 開啟 htmlExampleBS4-02.html 網頁,按 F12 進入開發模式 => 1.點選 Elements => 同時按下 Ctrl + F 鍵,會出現搜尋欄位 => 2. 輸入 : "//section/div[2]",會發現搜尋欄右邊出現搜尋結果的數量,並會指到所蒐尋的第一個元素 => 3.並在左邊有灰階區域顯示、右邊綠色區塊為元素代碼。
Chrome 外掛套件 ChroPath
有了 ChroPath ,當你再開發環境點選一個元素,就會自動產生 XPath,請 Google 搜尋 "chropath extension"
點選他就可以進入chrome 線上應用程式商店 =>按 "加到 Chrome" => 按 "新增擴充功能"
當你在左方網頁或右上方點選元素時,ChroPath 區域框就會出現以下資訊 :
- Rel XPath : 點選元素的相對路徑。
- Abx XPath : 點選元素的絕對路徑。
- CSS Selectors : CSS Selectors 路徑
用 Python 控制點選超連結
使用 尋找 HTML 文件的元素 方式傳回 Web Element 元素時,可以使用 click() 方法,如果執行此方法,相當於我們點選這個傳回的元素,如果傳回的元素是超連結的文字,這樣可以產生按此超連結的結果。
範例 pythonSelenium-09.py : 進入深智數位網頁,經過5秒後(第12行),程式設計自動點選 "深智數位緣起" 超連結,我們設計程式暫停5秒,主要是讓讀者可以體會網頁的變化。
# pythonSelenium-09.py from selenium import webdriver import time driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) url = 'https://deepmind.com.tw/' browser.get(url) # 網頁下載至瀏覽器 eleLink = browser.find_element_by_link_text('深智數位緣起') print(type(eleLink)) # 列印eleLink資料類別 time.sleep(5) # 暫停5秒 eleLink.click()
執行結果
<class 'selenium.webdriver.remote.webelement.WebElement'>
使用 Python 填寫表單和送出
使用 HTML 原始碼
許多網頁有填寫表單欄位,碰上這類問題,我們可以使用 HTML 原始碼分析輸入欄位的相關資訊。
我們可以開啟網頁 HTML 原始碼找尋 <input> 元素 id 元素 或是 name,然後使用 send_keys() 方法,就可以填寫表單。填寫完表單後可以使用 submit() 方法,將表單送出。
以下是以台灣證券交易所網頁 HTML 檔案為實例解說。
從以上可以看到 <input> 元素 name 屬性,是上市公司整合資訊的搜尋的輸入欄位,所以可以用下列方式設計。
範例 pythonSelenium-10.py : 用 Python 填寫表單,所填寫的表單是搜尋 "2330",本程式會經過5秒自動送出,我們在執行結果中印出來填寫表單以及送出的結果 。
# pythonSelenium-10.py from selenium import webdriver import time driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) url = 'https://www.twse.com.tw/zh/' browser.get(url) # 網頁下載至瀏覽器 txtBox = browser.find_element_by_name('stockNo') txtBox.send_keys('2330') # 輸入表單資料 time.sleep(5) # 暫停5秒 txtBox.submit() # 送出表單
執行結果 : 上述表單是自動填寫,經過5秒後可以得到下列結果 :
了解上述自動填寫表單和送出功能,未來熱門的演唱會門票、過年搶破頭的高鐵車票,就讓 Python 處理吧 !
用 Python 處理使用網頁的特殊按鍵
在欣賞、閱讀網頁時,有時往往需要捲動網頁或是使用特殊鍵,這些特殊鍵無法用 Python 輸入,不過 Python 有提供下列模組,可以方便我們操作。
selenium.webdriver.common.keys
使用時的導入語法如下
from selenium.webdriver.common.keys import Keys
經過上述宣告,未來可以使用 Keys 呼叫相關屬性,下列是常見的屬性內容 :
- ENTER/RETURN : 相當於鍵盤的 Enter 和 Return。
- PAGE_DOWN/PAGE_UP/HOME/END : 相當於鍵盤的 PAGE_DOWN,PAGE_UP、HOME、END。
- UP/DOWN/LEFT/RIGHT : 相當於鍵盤的 上、下、左、右 方向鍵。
使用方式是在前面加上 "Keys" ,例如 : Keys.HOME。
範例 pythonSelenium-11.py : 這個程式在執行時,首先顯示最上方的網頁內容,經過3秒後會往下捲動一頁,再過3秒會捲動到最下方,經過3秒可以往上捲動,再過3秒可以將網頁捲動到最上方。程式第10行,先搜尋 “body” ,這是網頁設計主體的開始標籤,相當於在網頁的最上方 。
# pythonSelenium-11.py from selenium import webdriver from selenium.webdriver.common.keys import Keys import time driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) url = 'https://www.twse.com.tw/zh/' browser.get(url) # 網頁下載至瀏覽器 ele = browser.find_element_by_tag_name('body') time.sleep(3) ele.send_keys(Keys.PAGE_DOWN) # 網頁捲動到下一頁 time.sleep(3) ele.send_keys(Keys.END) # 網頁捲動到最底端 time.sleep(3) ele.send_keys(Keys.PAGE_UP) # 網頁捲動到上一頁 time.sleep(3) ele.send_keys(Keys.HOME) # 網頁捲動到最上端
執行結果 : 每次間隔3秒,讀者可以觀察頁面內容的捲動方式。
用 Python 處理瀏覽器運作
常見的運作有下列方法
- forward() : 往前一頁。
- back() : 往後一頁。
- refresh() : 更新網頁。
- quit() : 關閉網頁,相當於關閉瀏覽器。
上述必須用 Firefox 瀏覽器物件啟動,也就是我們本文的變數 browser,例如 : browser.refresh() 可更新網頁,browser.quit() 可以關閉網頁。
範例 pythonSelenium-12.py : 更新網頁與關閉網頁的應用。
# pythonSelenium-12.py from selenium import webdriver from selenium.webdriver.common.keys import Keys import time driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) url = 'https://www.twse.com.tw/zh/' browser.get(url) # 網頁下載至瀏覽器 time.sleep(3) browser.refresh() # 更新網頁 time.sleep(3) browser.quit() # 關閉網頁
執行結果 : 網頁下載後3秒可以更新網頁內容,再過3秒後關閉瀏覽器。
自動進入 Google 系統
Google 有提供免費 Email 與一系列的服務,我們可以藉由輸入帳號與密碼方式進入系統,然後使用 Google 的所有服務,我們將一步一步引導讀者設計程式可以自動進入 Google 的系統,其實這一節主要觀念是我們將帶領讀者練習和網站做互動。
首先請輸入Google 網址 : https://www.google.com/
這時在視窗右上方可以看到 登入 按鈕 => 請將滑鼠移至按鈕再按滑鼠右鍵,可以看到下拉視窗 => 請點選 Inspect 檢查 => 可以看到下列視窗畫面 :
範例 pythonSelenium-13.py : 設計自動登入 Google 的系統。
from selenium import webdriver import time url = 'https://www.google.com' email = input('請輸入你的Google Email的帳號 : ') pwd = input('請輸入你的Google Email的密碼 : ') driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) browser.get(url) # 網頁下載至瀏覽器 browser.find_element_by_link_text('登入').click()
執行結果 : 網頁出現以下畫面。
以上,我們已經進入登入 Google 帳號畫面,接下來需要解析輸入郵件地址 => 將滑鼠移至輸入郵件地址欄位 => 請按滑鼠右鍵,可以看到下拉視窗 => 請點選 Inspect 檢查 => 可以看到下列視窗畫面 如下 :
我們可以看到 <input> 元素內的 id 是 "identifierId"。
範例 pythonSelenium-14.py : 設計自動登入 Google 的系統,繼續 範例 pythonSelenium-13.py ,增加可以輸入Email的帳號。
# pythonSelenium-14.py from selenium import webdriver import time url = 'https://www.google.com' email = input('請輸入你的Google Email的帳號 : ') pwd = input('請輸入你的Google Email的密碼 : ') driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) browser.get(url) # 網頁下載至瀏覽器 browser.find_element_by_link_text('登入').click() browser.find_element_by_id('identifierId').send_keys(email) # 輸入帳號 time.sleep(3)
執行結果 : 網頁出現以下面。
接下來,我們必須解析 "繼續" 按鈕,重複類似以上步驟。
範例 pythonSelenium-15.py : 設計自動登入 Google 的系統,繼續 範例 pythonSelenium-14.py ,增加 "繼續" 按鈕。
# pythonSelenium-15.py from selenium import webdriver import time url = 'https://www.google.com' email = input('請輸入你的Google Email的帳號 : ') pwd = input('請輸入你的Google Email的密碼 : ') driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) browser.get(url) # 網頁下載至瀏覽器 browser.find_element_by_link_text('登入').click() browser.find_element_by_id('identifierId').send_keys(email) # 輸入帳號 time.sleep(3) # 按繼續鈕 browser.find_element_by_xpath("//span[@class='VfPpkd-vQzf8d']").click() time.sleep(3) time.sleep(3)
接下來,我們必須解析輸入 "密碼" 欄位,重複類似以上步驟。
範例 pythonSelenium-16.py : 設計自動登入 Google 的系統,繼續 範例 pythonSelenium-15.py ,增加 輸入 "密碼" 欄位。
# pythonSelenium-16.py from selenium import webdriver import time url = 'https://www.google.com' email = input('請輸入你的Google Email的帳號 : ') pwd = input('請輸入你的Google Email的密碼 : ') driverPath = 'c:\driver\chromedriver.exe' browser = webdriver.Firefox(executable_path=driverPath) browser.get(url) # 網頁下載至瀏覽器 browser.find_element_by_link_text('登入').click() browser.find_element_by_id('identifierId').send_keys(email) # 輸入帳號 time.sleep(3) # 按繼續鈕 browser.find_element_by_xpath("//span[@class='VfPpkd-vQzf8d']").click() time.sleep(3) # 輸入密碼 browser.find_element_by_xpath("//input[@type='password']").send_keys(pwd) time.sleep(3)
接下來,我們必須解析輸入 "密碼" 後的 "繼續" 按紐,重複類似以上步驟。
範例 pythonSelenium-17.py : 設計自動登入 Google 的系統,繼續 範例 pythonSelenium-16.py ,增加 "繼續" 按鈕。
# pythonSelenium-17.py from selenium import webdriver import time url = 'https://www.google.com' email = input('請輸入你的Google Email的帳號 : ') pwd = input('請輸入你的Google Email的密碼 : ') driverPath = 'c:\driver\chromedriver.exe' browser = webdriver.Firefox(executable_path=driverPath) browser.get(url) # 網頁下載至瀏覽器 browser.find_element_by_link_text('登入').click() browser.find_element_by_id('identifierId').send_keys(email) # 輸入帳號 time.sleep(3) # 按繼續鈕 browser.find_element_by_xpath("//span[@class='VfPpkd-vQzf8d']").click() time.sleep(3) # 輸入密碼 browser.find_element_by_xpath("//input[@type='password']").send_keys(pwd) time.sleep(3) # 按繼續鈕 browser.find_element_by_xpath("//span[@class='RveJvd snByac']").click() time.sleep(3)
們就會看到登入 Google 的網頁如下,右上方已經改為我們的名字與圖示。
自動化下載環保署空氣品質資料
範例 pythonSelenium-18.py : 自動化下載環保署空氣品質資料。
# pythonSelenium-18.py from selenium import webdriver import time url = 'https://data.epa.gov.tw/dataset/aqx_p_434/resource/b50c2109-6b1b-4413-9037-658760f7c969' driverPath = 'c:\driver\geckodriver.exe' browser = webdriver.Firefox(executable_path=driverPath) browser.get(url) # 網頁下載至瀏覽器 browser.find_element_by_link_text('JSON').click() # 按JSON鈕 time.sleep(5) browser.find_element_by_link_text('XML').click() # 按XML鈕 time.sleep(5) browser.find_element_by_link_text('CSV').click() # 按CSV鈕 time.sleep(5)
參考資料
特色、摘要,Feature、Summary:
關鍵字、標籤,Keyword、Tag:
- Web-Crawler,Data-Mining,Data-Science,Python,
留言
張貼留言
Aron阿龍,謝謝您的留言互動!