Selenium

      在〈Selenium〉中尚無留言

Selenium

[səˋlinɪəm] : 硒, 一種化學元素

每次想看某檔股票的股價, 總是要打開瀏覽器
1. 輸入網址 http://tw.yahoo.com
2. 點選股市
3. 輸入股票代號
4. 得到股票的目前股價
以上經過這一連串的點選及輸入, 才會顯示出我們所要的資料.

如果能把上述這些步驟記錄起來, 日後只需執行播放這些記錄步驟, 就會自動的帶到我們所要的網頁, 這將大大減少重複性的工作. Selenium就是為了達成此功能而生的.

Selenium 執行「真實的瀏覽器」進行網站操作自動化, 能夠直接獲取即時的內容, 包括被 JavaScript 修改過的 DOM 內容, 讓程式可以直接與網頁元素即時互動、執行 JavaScript 程式,

Selenium 是許多網頁測試工具的核心, 利用 Selenium 操作網頁表單資料、點選按鈕或連結、取得網頁內容並進行檢驗, 可以滿足相當多測試的需求.

安裝

pip install selenium packaging

下載webDriver

每個瀏覽器都有自已的無頭驅動程式(headless driver), 稱為webDriver. webDriver可以被Selenium支援, 是一個沒有任何介面的瀏覽器. 也就是說, 瀏覽器分為有介面的一般瀏覽器,  及無介面的無頭瀏覽器. webdriver是從Google發跡的, 所以Chrome的webDriver支援度會比較好.

請到 https://chromedriver.chromium.org/ 下載相對應版本的ChromeDriver, 然後放在Python專案的資料夾裏.

下載的版本需與本機安裝的Chrome相同版本. 如果下載不同的版本, 將導致Python程式閃退.

簡易開啟瀏覽器測試

下面代碼中, options 可設定為 headless 無頭模式. 開發期間把 headless 註解掉, 就可看到有UI介面的瀏覽器, 待開發完成, 再把無頭模式打開.

新版 selenium 要使用 Service(“chromedriver.exe”) 建立一個 service物件,然後再將 service 置入 webdriver.Chrome 中開啟 browser 物件。

另外新版 selenium 會自動關閉瀏覽器,如果開發中不想自動關閉,需加入 如下選項
opt.add_experimental_option(‘detach’, True) 。

瀏覽器其實分三階段,
1. 取得 html。
2. 執行 javascript。
3. 渲染瀏覽器。

requests.get() 是直接取得第一階段的 html。而下面代碼使用 WebDriverWait 方法,這是為了等待瀏覽器執行完畢 javascript,並渲染後,產生某個標籤或 id 才繼續進行下一個動作。通常網頁資料如果是由 Javascript 或是 Ajax 產生時,就需要等待。這是因為瀏覽器接收層到執行層,再到渲染層需花費一段時間,如果不等待,只會抓到接收層的 html。

WebDriverWait 有三個參數,分別為 WebDriverWait(browser, 等待時間, 檢查頻率)。如果在等待時間後還沒出現想要的目標,就會產生 except 例外。而檢查頻率是指每隔多久檢查一次,如果沒有此參數,預設為 0.5秒 (500ms)。

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
opt = Options()
#options.add_argument('--headless')#啟動無頭模式
opt.add_argument('--disable-gpu')

#防止瀏覽器自動關閉
opt.add_experimental_option('detach', True)
service = Service("chromedriver.exe")
browser = webdriver.Chrome(service=service,options=opt)
browser.get("http://localhost/web/99.html")
try:
    WebDriverWait(browser, 20).until(EC.presence_of_element_located((By.TAG_NAME, "td")))
    soup = BeautifulSoup(browser.page_source, 'html.parser')
    print(soup.prettify)
except:
    print("Connection Error")

自動下載 webdriver

Chrome 瀏覽器常常在更新,導致也需手動更換 webdriver.exe 的版本。使用 webdriver-manager 可以自動下載最合適的 chromedriver.exe。下載後的儲存位置在
C:\Users\登入名稱\.wdm\drivers\chromedriver\win32\103.0.5060.53\chromedriver.exe

請先安裝如下套件

pip install webdriver-manager packaging

然後產生 Service 時,不使用 “chromedriver.exe”,取代而之的是 ChromeDriverManager().install()

from webdriver_manager.chrome import ChromeDriverManager
service = Service(ChromeDriverManager().install())
browser = webdriver.Chrome(service=service,options=opt)

不過自從 Chrome 115之後,ChromeDriverManager().install() 無法使用了,需手動到如下網址下載

Windows : https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5790.170/win64/chromedriver-win64.zip

Linux : https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5790.170/linux64/chromedriver-linux64.zip

下載完後,解開把 chromedriver.exe copy  到專案之下

完整代碼如下

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from bs4 import BeautifulSoup
from webdriver_manager.chrome import ChromeDriverManager

opt = Options()
#options.add_argument('--headless')
opt.add_argument('--disable-gpu')

#防止瀏覽器自動關閉
opt.add_experimental_option('detach', True)
#service = Service(ChromeDriverManager().install())
service = Service("chromedriver.exe")
browser = webdriver.Chrome(service=service,options=opt)
browser.get("http://localhost/web/99.html")
try:
    WebDriverWait(browser, 20).until(EC.presence_of_element_located((By.TAG_NAME, "td")))
    soup = BeautifulSoup(browser.page_source, 'html.parser')
    print(soup.prettify)
except:
    print("Connection Error")

控制視窗

常用變數

name : 瀏覽器名稱
title : 標題
current_url : 網頁url
page_source : html原始碼
session_id : 連線id

視窗大小位置

get_window_position() : 取得視窗左上角位置
set_window_position(x, y) : 設定視窗左上角位置
get_window_size() : 取得視窗大小
set_window_size(x, y) : 設定視窗大小
maximize_window() : 最大化視窗
minimize_window() : 最小化視窗

瀏覽器按鈕

back() : 上一頁
forward() : 下一頁
refresh() : 重新整理
quit() : 關閉瀏覽器, 同時關閉驅動程式
close() : 關閉瀏覽器
save_screenshot(filename) : 瀏覽器快照

控制網頁元素

from selenium.webdriver.common.by import By
ls=browser.find_elements(By.TAG_NAME, 'tr')
print(f'共有{len(ls}列')

有By.ID, By.LINK_TEXT, By.CLASS_NAME, By.CSS_SELECTOR, By.NAME, By_TAG_NAME.
以上, 會傳回WebElement物件或List

Linux注意事項

在Linux之下,需先安裝google-chrome-stable套件,然後再安裝webdriver

安裝google-chrome-stable的指令如下

sudo su
curl -sS -o - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add
echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list
exit
sudo apt-get -y update
sudo apt-get -y install google-chrome-stable
sudo apt-get install python3-pip
sudo pip install selenium webdriver-manager mysql-connector-python beautifulsoup4

然後再手動下載 webDriver for Linux 64 到專案之下,即可開始執行。如果是使用 webdriver-manager ,則會自動下載合適的 webDriver 版本,可以省略手動下載。

Linux自動執行

如果要讓 Linux 自動執行爬蟲程式,可以使用 cron.d 指定何時自動執行 .py 檔。請在 /etc/cron.d 內新增一個檔案,比如 autostock

sudo vim /etc/cron.d/autostock

然後在檔案裏撰寫如下指令

#每日 14:00自動執行
00 14 * * * thomas /data/server/auto/crawler/twstock.py >> /data/server/auto/log_stock.txt

儲存後,重新啟動 cron.d service 即可

sudo service cron restart

遠傳會員登入

為什麼要找遠傳下手呢? 因為遠傳以前是爛到還可以用 SQL Injection下手。到了2022年初才改版,不過只是用了簡單的cid key 來驗証,所以超級好下手的。

底下的代碼,只要修改電話號碼及密碼,就可以輕易登入了。

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
tel = '電話號碼'
password = '登入密碼'
opt = Options()
#ops.add_argument('--headless')#啟動無頭模式
opt.add_argument('--disable-gpu')
opt.add_experimental_option('detach', True)
service = Service(ChromeDriverManager().install())
browser = webdriver.Chrome(service=service,options=opt)
browser.get("https://login2.fetnet.net/k8slogin/eaiapp/loginForm", )
phone_text=browser.find_element(By.ID,"UserID")
phone_text.send_keys(tel)
btn=browser.find_element(By.ID,"login_btn")
btn.click()

try:
    WebDriverWait(browser, 20).until(EC.presence_of_element_located((By.ID, 'password-field')))
except:
    print("連線有問題喔")

password_text=browser.find_element(By.ID,"password-field")
password_text.send_keys(password)
btn=browser.find_element(By.ID,"loginBtn")
btn.click()

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *