今天要把發文自動化完成,首先要先講到如何用 json 存取檔案。
json 是把資料呈現成JavaScript的標準格式,它的架構是由大括號組合而成。以下用存放網站的帳號密碼做舉例:
{
"webA": {
"id": 123
"password": 456
},
"webB": {
"id": 789
"password": 012
}
}
像這樣透過一個又一個的大括號包裝起來,而我們的結構如下:
{
"subject": "(文章標題)",
"article": "(文章內容)"
}
首先要先 import json,這個部分在昨天和前天載入環境變數的時候已經有使用過了
import json
再來要讀取 json 檔案,我們打開 json 檔案並讀取它:
with open('irondata.json', 'r', encoding='utf-8') as file:
irondata = json.load(file)
day10_subject = irondata["subjevt"]
day10_article = irondata["article"]
這樣就完成讀取了,再來我們繼續往下實作,首先我們先把元素定位出來:
# 輸入文章主旨
subject = browser.find_element(By.XPATH, "//input[@class='form-control post-header__title']")
# 輸入文章內容
article = browser.find_element(By.CSS_SELECTOR, ".CodeMirror")
# 點擊倒三角 icon
more_icon = browser.find_element(By.XPATH, "//button[contains(@class, 'btn')]/span[@class='caret']")
# 點擊發表文章
send_article = browser.find_element(By.XPATH, "//button[text()='發表文章']")
這邊可以發現 more_icon 的 XPATH 寫法不太一樣,原因是我們原本要定位的 span 會有重複的元素,所以我們從上面一個節點開始往下找 span 即可定位到我們要的元素。
再來是輸入文章與發表
# 輸入文章標題和內容
subject.send_keys(day10_subject)
actions.click(article).perform()
actions.send_keys(day10_article).perform()
browser.execute_script("arguments[0].scrollIntoView();", more_icon)
more_icon.click()
send_article.click()
可以看到這邊輸入文章多了一點步驟,而這就要提到 CodeMirror 這個東西。
這是一個 JS 的套件,可以在網頁端編輯 code,而 iT 邦幫忙在文章內文就有使用這個套件,而它無法用一般 text 或是 textfield 的方式去輸入,這個時候只能靠 Action Chains
它負責鼠標的所有操作,基本上我們能做到的他都能夠實現,它強大的部分是可以把鼠標的功能像鎖鏈一樣連起來,以實現各種複雜的操作(例如拖拉物件等等)。
而我們在 Action Chains 操作的點擊與輸入,與 selenium 相較之下模擬的更加逼真,所以我們的操作才能被 CodeMirror 捕捉到。
把這些搞定後,自動化發文終於到一段落。
CodeMirror的操作: How do I edit CodeMirror with Selenium in Python?
import json
import os
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from dotenv import load_dotenv
# 設定 ChromeDriver 的路徑
browesr_path = "c:\Program Files\chromedriver-win64\chromedriver-win64\chromedriver.exe"
service = Service(browesr_path)
# 設定 Chrome 的啟動參數
options = Options()
# 設定瀏覽器語言為中文
options.add_argument("--lang=zh-TW")
# 全螢幕模式
options.add_argument("--kiosk")
browser = webdriver.Chrome(service=service, options=options)
browser.get("https://ithelp.ithome.com.tw/")
# 設定 action chain
actions = ActionChains(browser)
# 前往登入頁面
login_page_button = browser.find_element(By.XPATH, "//a[@class='menu__item-link']")
login_page_button.click()
# 登入帳號密碼
account = browser.find_element(By.ID, "account")
password = browser.find_element(By.ID, "password")
login_button = browser.find_element(By.ID, "loginBtn")
load_dotenv()
ITHOMELOGIN = json.loads(os.getenv("ITHOMELOGIN"))
account.send_keys(ITHOMELOGIN["account"])
password.send_keys(ITHOMELOGIN["password"])
login_button.click()
# 進到鐵人發文頁面
iron_button = browser.find_element(By.XPATH, "//button[@class='menu__ironman-btn']")
select_topic_button = browser.find_element(By.XPATH, "//a[@class='ir-modal__list-link']")
iron_button.click()
time.sleep(1)
select_topic_button.click()
# 貼上文章並發文
with open('irondata.json', 'r', encoding='utf-8') as file:
irondata = json.load(file)
day10_subject = irondata["subject"]
day10_article = irondata["article"]
# 等待網頁載入
time.sleep(1)
subject = browser.find_element(By.XPATH, "//input[@class='form-control post-header__title']")
article = browser.find_element(By.CSS_SELECTOR, ".CodeMirror")
more_icon = browser.find_element(By.XPATH, "//button[contains(@class, 'btn')]/span[@class='caret']")
send_article = browser.find_element(By.XPATH, "//button[text()='發表文章']")
# 輸入文章標題和內容
subject.send_keys(day10_subject)
actions.click(article).perform()
actions.send_keys(day10_article).perform()
browser.execute_script("arguments[0].scrollIntoView();", more_icon)
more_icon.click()
send_article.click()
time.sleep(5)
以上是整個自動化發文的 code ,可以發現隨著專案的擴大,看 code 會越來越辛苦,因此明天預計會介紹 POM(Page Object Model)的形式,讓 code 不會擠成一團難以閱讀與維護外,也能夠讓專案符合物件導向的精神。