### 課程:進階程式設計1A 最後更新:2024/06/14
### 分工表
:::warning
|組員 | 學號 | 分工 |
| -------- | -------- | -------- |
| 藍家鎧 | 112021003 | 程式編寫(驗證碼、高鐵第一頁and座位偏好、車廂、高鐵第三頁) 60% 、報告 |
| 謝秉宏 | 112021014 | 內容統整,參與討論、報告 |
| 賴以宸 | 112021134 | 程式編寫(post請求、防反爬蟲、表格列印、高鐵第一頁)40%,報告製作 、報告 |
| 游嘉旭 | 112021031 | 資料查詢,參與討論、報告 |
| 童承逸 | 112021139 | 報告,參與討論 |
:::
---
# **實行目標**
1. 依照填入資料實現列印高鐵時刻表
> 這邊的基本資料如站點、抵達站等,可以順便引用至2.selenium的部分
2. selenium自動填入資料
> 使用Selenium進行自動化操作的基本流程:準備WebDriver、與頁面交互、處理驗證碼、填寫表單信息、最終提交。考慮頁面加載時間、元素查找的穩定性等因素,以提高自動化腳本的可靠性和穩定性。
# 程式部分
**引用套件**
```
import requests
import json
import os
from selenium.webdriver.chrome.service import Service
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support.select import Select
from selenium.common.exceptions import NoSuchElementException
import time
import prettytable as pt
from prettytable import PrettyTable
import tkinter as tk
from tkinter import simpledialog
from selenium.webdriver.common.by import By
import cv2
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
from selenium.common.exceptions import NoSuchWindowException
```
> requests, json, os:用於發送HTTP請求、處理JSON數據和文件操作。
selenium相關模組:用於操作瀏覽器進行自動化。
cv2:OpenCV,用於圖像處理。
sklearn:機器學習庫,用於多項式回歸。
numpy, PIL, matplotlib:分別用於數值運算、圖像處理和繪圖。
tkinter:用於顯示簡單的對話框。
**定義一些圖像處理和匹配的函數**
```
def mse(imageA, imageB):
imageB = cv2.cvtColor(imageB, cv2.COLOR_GRAY2RGB)
err = np.sum((imageA.astype("float") - imageB.astype("float")) ** 2)
err /= float(imageA.shape[0] * imageA.shape[1])
return err
def getNumber(pic):
min_a = 9999999999
min_png = None
for png in os.listdir('A-Z1'):
ref = cv2.imread("A-Z1/" + png)
if mse(ref, pic) < min_a:
min_a = mse(ref, pic)
min_png = png
return min_png, min_a
```
> mse(imageA, imageB):計算兩幅圖像之間的均方誤差,用於衡量圖像相似度。
getNumber(pic):在指定目錄中尋找與給定圖像最相似的參考圖像。
>這邊會用到之後處理完的圖片去比對(後續程式有)
**讀取車站數據**
```
# 指定要讀取的檔案路徑
file_path = "THSrjson/output.json"
# 以 'r' 模式開啟檔案
with open(file_path, 'r') as file:
# 讀取 JSON 資料
dataT = json.load(file)
def find_station(name):
for station in dataT:
if station['StationName']['Zh_tw'] == name:
return station['StationID'], station['StationCode'], station['StationName']['En']
return None, None, None
```
> 從文件THSrjson/output.json中讀取車站數據,並定義find_station(name)函數用於查找車站ID和代碼。
> 有關THSrjson/output.json需要去url = "https://www.thsrc.com.tw/TimeTable/Search"抓所需的資料
**發送查詢請求並處理結果**
```
url = "https://www.thsrc.com.tw/TimeTable/Search"
data = {
'SearchType': 'S',
'Lang': 'TW',
'StartStation': start_station_nameEN,
'EndStation': to_station_nameEN,
'OutWardSearchDate': time2,
'OutWardSearchTime': date,
'ReturnSearchDate': time2,
'ReturnSearchTime': date,
'DiscountType': ''
}
# 發送 POST 請求
response = requests.post(url, data=data)
# 將回應的內容轉換為 JSON 格式
json_data = response.json()
# 創建新的資料夾
folder_name = "THSrjson"
if not os.path.exists(folder_name):
os.makedirs(folder_name)
# 將 JSON 資料寫入檔案
file_path = os.path.join(folder_name, "output.json")
with open(file_path, "w") as file:
json.dump(json_data, file)
result = json.loads(response.text)
```
> 這邊選擇的方式是利用post請求網頁,下載到本地處理
* > 會這樣選擇是因為之前嘗試直接發送請求,就算嘗試寫偽裝與payload,會回報一些奇怪的資訊而不是我想要的json檔(這邊猜測他會防這種請求)以下是錯誤的請求方式

**用戶輸入**
```
# 讓使用者輸入資訊
"""出發站點"""
start_station_nameEN = input("1.南港 - NanGang\n2.台北 - TaiPei\n3.板橋 - BanQiao\n4.桃園 - TaoYuan\n5.新竹 - XinZhu\n6.苗栗 - MiaoLi\n7.台中 - TaiZhong\n8.彰化 - ZhangHua\n9.雲林 - YunLin\n10.嘉義 - JiaYi\n11.台南 - TaiNan\n12.左營 - ZuoYing\n選擇起程站(請輸入英文):")
"""抵達站點"""
to_station_nameEN = input("1.南港 - NanGang\n2.台北 - TaiPei\n3.板橋 - BanQiao\n4.桃園 - TaoYuan\n5.新竹 - XinZhu\n6.苗栗 - MiaoLi\n7.台中 - TaiZhong\n8.彰化 - ZhangHua\n9.雲林 - YunLin\n10.嘉義 - JiaYi\n11.台南 - TaiNan\n12.左營 - ZuoYing\n選擇到達站(請輸入英文):")
"""日期"""
time2 = input("請輸入出發日期(EX:2024/06/11)還是需要手動修改:")
"""時間"""
date = input("請輸入出發時間(EX:16:00):")
departure_time=str(date)
'''車種'''
car = int(input("選擇車廂 1.標準車廂 2.商務車廂 (請輸入數字):"))
if car==2:
car='商務車廂'
else:
car='標準車廂'
'''座位偏好'''
seatlike = int(input("選擇座位偏好 1.無座位偏好 2.靠窗 3.靠走道 (請輸入數字):"))
if seatlike==2:
seatlike='靠窗優先'
elif seatlike ==3:
seatlike='走道優先'
else:
seatlike='無座位偏好'
Adult_ticket=str(input("幾張全票:"))
child_ticket=str(input("幾張孩童票(6~11):"))
Adult_child_ticket=int(Adult_ticket)+int(child_ticket)
love_ticket=str(input("幾張愛心票:"))
love_tickets = []
if int(love_ticket) > 0:
for i in range(1, int(love_ticket) + 1):
id_number = input(f"愛心票{i}身分證字號: ")
love_tickets.append(id_number)
old_ticket=str(input("幾張敬老票(65+):"))
if int(old_ticket) > 0:
for i in range(1, int(old_ticket) + 1):
id_number = input(f"敬老票{i}身分證字號: ")
love_tickets.append(id_number)
IDch=int(input("選擇 1.身分證字號 2.護照/居留證/入出境許可證號碼(輸入數字):"))
if IDch==2:
ID=str(input("護照/居留證/入出境許可證號碼:"))
IDch="護照/居留證/入出境許可證號碼"
else:
ID=str(input("身分證字號:"))
IDch="身分證字號"
membership=int(input("選擇 1.非高鐵會員 TGo/企業會員 2.有高鐵會員 TGo 帳號 3.企業會員統編(請輸入數字):"))
cheak=1
TGo=""
Compiled=""
if membership==2:
cheak=int(input("TGo帳號是否同取票人身分證字號 1.是 2.否(輸入數字):"))
if cheak==2:
TGo=str(input("身分證字號/會員卡號/手機號碼(已認證):"))
else:
cheak=1
elif membership==3:
Compiled=input("企業統一編號:")
else:
pass
```
> 此處無難點,找到位置操作即可
> 但發現一個小問題有關time2 的,在請求網頁內容時可以正常操作,但到後面selenium,改以網站接受的aria_labele格式輸入,會有問題,後續會有程式碼。
**列印高鐵時刻表展示部分**
```
page = 0
tb =pt.PrettyTable()
for t in result['data']['DepartureTable']['TrainItem']:
if t['DepartureTime'] >= time2:
Train_Num = t['TrainNumber']
Departure_Time = t['DepartureTime']
Destination_Time = t['DestinationTime']
Duration = t['Duration']
NonRC = t["NonReservedCar"]
if t['Discount'] !=[]:
for k in t['Discount']:
discount = k['Name'] + k['Value']
else:
discount = "-"
tb.field_names = ['序列','車號','出發時間','抵達時間','預計耗時','自由座車廂','優惠類型']
tb.add_row([page, Train_Num, Departure_Time, Destination_Time, Duration, NonRC, discount])
page +=1
if page == 10:
break
print("\n","高鐵時刻表(目標時間後十筆資料)")
print(tb, "\n")
```
效果圖:
**列印票價查詢表展示部分**
```
tb1 = PrettyTable()
# 設定表格的欄位名稱
tb1.field_names = [' ', '全票', '孩童票/敬老票/愛心票','團體票']
# 添加行到表格中
tb1.add_row(['標準車廂', result['data']['PriceTable']['Coach'][0],result['data']['PriceTable']['Coach'][1],result['data']['PriceTable']['Coach'][2]])
tb1.add_row(['商務車廂'] + result['data']['PriceTable']['Business'])
tb1.add_row(['自由座車廂'] + result['data']['PriceTable']['Unreserved'])
# 如果有優惠票價,則添加到表格中
if result['data']['PriceTable']['Column'] != []:
for column in result['data']['PriceTable']['Column']:
tb1.add_column(column['ColumnName'], [column['CoachPrice'], column['BusinessPrice'], column['Unreserved']])
print('票價查詢')
print(tb1)
```
效果圖:
**selenium.開啟網站**
```
driverPath = "/**自己放路徑**/(記得改斜線喔)"
url = "https://irs.thsrc.com.tw/IMINT/?utm_source=thsrc&utm_medium=btnlink&utm_term=booking"
chrome_options = Options()
chrome_options.add_argument("--start-maximized")
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option("useAutomationExtension", False)
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
service = Service(driverPath)
driver = webdriver.Chrome(service=service, options=chrome_options)
driver.get(url)
driver.implicitly_wait(10)
```
> 這邊特別去除了headline,因為我們在執行原本的程式發現只要是自動操作的selenium都會檔,(微笑)。去除headline即可
> 
> 去除這個
**selenium.點選接受cookie**
```
button = driver.find_element(By.ID,"cookieAccpetBtn")
button.click()
```
> 就點他
> 
**selenium.選擇座位**
```
#填入選擇車廂
select_element0 = driver.find_element(By.NAME, "trainCon:trainRadioGroup")
select0 = Select(select_element0)
select0.select_by_visible_text(car)
#填入座位偏好
select_element01 = driver.find_element(By.NAME, "seatCon:seatRadioGroup")
select01 = Select(select_element01)
select01.select_by_visible_text(seatlike)
```
> 簡單來說car:value0標準車廂value1有錢人做的商務,
> seatlike:value0沒差的人value1靠窗的人value2靠走道的人
> 
>
**selenium.填入基本資料**
```
station_name_map = {
"NanGang": "南港",
"TaiPei": "台北",
"BanQiao": "板橋",
"TaoYuan": "桃園",
"XinZhu": "新竹",
"MiaoLi": "苗栗",
"TaiZhong": "台中",
"ZhangHua": "彰化",
"YunLin": "雲林",
"JiaYi": "嘉義",
"TaiNan": "台南",
"ZuoYing": "左營"
}
# 獲取中文站名
start_station_nameCN = station_name_map[start_station_nameEN]
to_station_nameCN = station_name_map[to_station_nameEN]
# 選擇下拉選單的選項
select_element1 = driver.find_element(By.NAME, "selectStartStation")
Select(select_element1).select_by_visible_text(start_station_nameCN)
select_element2 = driver.find_element(By.NAME, "selectDestinationStation")
# 使用Select類來選擇下拉選單中的選項
select2 = Select(select_element2)
select2.select_by_visible_text(to_station_nameCN)
departure_time_select = Select(driver.find_element(By.NAME, "toTimeTable"))
departure_time_select.select_by_visible_text(departure_time)
#未解決的選日期問題(暫時用手點)
"""
driver.find_element(By.XPATH,"//input[@class='uk-input' and @readonly='readonly']").click()
time.sleep(2)
#替換成aria-label內可以接受的格式
year , month , day = time2.split("/")
month_dict = {"01": "一月", "02": "二月", "03": "三月", "04": "四月", "05": "五月", "06": "六月", "07": "七月", "08": "八月", "09": "九月", "10": "十月", "11": "十一月", "12": "十二月"}
ppp = month_dict[month]
# 根據輸入日期找到對應的日期並點擊#class會變環不知道怎麼抓
date_xpath = f"//div[@class='flatpickr-months']//span[@aria-label='{month} {day},{year}' and @tabindex='-1']"
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, date_xpath))).click()
"""
#填入全票票數
select_element3 = driver.find_element(By.NAME, "ticketPanel:rows:0:ticketAmount")
select3 = Select(select_element3)
select3.select_by_visible_text(Adult_ticket)
#填入孩童票票數
select_element4 = driver.find_element(By.NAME, "ticketPanel:rows:1:ticketAmount")
select4 = Select(select_element4)
select4.select_by_visible_text(child_ticket)
#填入愛心票票數
select_element5 = driver.find_element(By.NAME, "ticketPanel:rows:2:ticketAmount")
select5 = Select(select_element5)
select5.select_by_visible_text(love_ticket)
#填入敬老票票數
select_element6 = driver.find_element(By.NAME, "ticketPanel:rows:3:ticketAmount")
select6 = Select(select_element6)
select6.select_by_visible_text(old_ticket)
#填入大學生票票數
#select_element7 = driver.find_element(By.NAME, "ticketPanel:rows:4:ticketAmount")
#select7 = Select(select_element7)
#select7.select_by_visible_text(College_student_tickets)
```
> 我自己觀察標籤的變化,就需要@class=flatday跟@aria-label
> 先講@aria-label,這個他的格式是{月份(中文)} {日期},{年}
> 所以我先寫一個字典讓程式對照中文的月份,但問題可能出在@class=flatday,很酷的是他是一個會變的標籤,選中後會變成@class=flatday_select(?嗎我記得
> 我不會選這個,而且找不到,也還在找怎麼解決,所以暫時用手點的
**selenium.驗證碼**
```
'''驗證碼'''
while True:
driver.save_screenshot('test.png') # 儲存當前網頁截圖為 test.png
element = driver.find_element(By.ID, "BookingS1Form_homeCaptcha_passCode")# 查找驗證碼元素
# 獲取驗證碼元素的位置和大小
left = element.location['x']
right = element.location['x'] + element.size['width']
top = element.location['y']
bottom = element.location['y'] + element.size['height']
# 裁剪驗證碼圖像
img = Image.open('test.png') # 打開截取的網頁截圖
img = img.crop((left, top, right, bottom))# 根據位置裁剪驗證碼圖像
img = img.resize((119, 47))# 調整裁剪後的驗證碼圖像大小為 119x47 像素
captcha_filename = os.path.join(folder_name, 'captcha.png') # 儲存裁剪後的驗證碼圖像
img.save(captcha_filename, 'png')
# 圖像處理
img = cv2.imread(captcha_filename)# 讀取裁剪後的驗證碼圖像
dst = cv2.fastNlMeansDenoisingColored(img, None, 30, 30, 7, 21) # 降噪處理
gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)# 將圖像轉換為灰度圖像
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)# 二值化圖像,反轉顏色
imgarr = thresh.copy() # 複製二值化圖像數組
imgarr[:, 5:115] = 0# 將5到115的像素值設置為 0
# 提取白色像素座標
imagedata = np.where(imgarr == 255)
X = np.array([imagedata[1]])# 提取白色像素的 X 坐標
Y = 47 - imagedata[0]# 計算白色像素的 Y 坐標,並調整座標系統
# 使用多項式回歸進行擬合
poly_reg = PolynomialFeatures(degree=2)# 創建二次多項式特徵
X_ = poly_reg.fit_transform(X.T) # 將 X 轉換為多項式特徵
regr = LinearRegression()# 創建線性回歸模型
regr.fit(X_, Y) # 對白色像素進行多項式回歸擬合
X2 = np.array([[i for i in range(0, 119)]])# 創建新的 X 值範圍
X2_ = poly_reg.fit_transform(X2.T)# 將 X2 轉換為多項式特徵
# 圖像標記預測結果
newimg = thresh.copy()# 複製二值化圖像
for ele in np.column_stack([regr.predict(X2_).round(0), X2[0]]):
pos = 47 - int(ele[0])# 計算標記位置
newimg[pos-3:pos+3, int(ele[1])] = 255 - newimg[pos-3:pos+3, int(ele[1])]# 標記像素位置
# 保存图像
plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.imshow(thresh, cmap='gray')
plt.title('Threshold Image')# 顯示原始二值化圖像
plt.subplot(122)
plt.imshow(newimg, cmap='gray')
plt.title('Processed Image')# 顯示處理後的圖像
plt.tight_layout()
processed_image_filename = os.path.join(folder_name, 'processed_images.png')# 儲存處理後的圖像
plt.savefig(processed_image_filename)# 保存處理後的圖像
plt.close()# 關閉圖像視窗
# 切割圖像
height, width = newimg.shape# 獲取處理後圖像的高度和寬度
for cut_point in cut_points:# 切割點
#print(cut_point)
if 0 < cut_point < width:# 確認切割點在圖像範圍內
cv2.line(newimg, (cut_point, 0), (cut_point, height), (0, 0, 0), 1)# 在圖像上繪製切割線
cut_images = []
for i, cut_point in enumerate(cut_points):# 遍歷切割點
#print(i)
if i == 0:
cut_images.append(newimg[:, :cut_point])# 切割第一個圖像區域
elif i == len(cut_points) - 1:
cut_images.append(newimg[:, cut_points[i-1]:])# 切割最後一個圖像區域
else:
cut_images.append(newimg[:, cut_points[i-1]:cut_point])# 切割中間的圖像區域
# 移動 if 條件至外層循環
for i, cut_image in enumerate(cut_images): # 切割後的圖像區域
# 跳過 cut_image_0 和 cut_image_5
if i == 0 or i == 5:# 跳過第一個和第五個圖像區域
continue
# 调整图像大小为 50x50 像素
resized_cut_image = cv2.resize(cut_image, (50, 50))# 調整切割後的圖像大小為 50x50 像素
# 保存处理后的切割图像
cut_image_filename = os.path.join(folder_name, f'cut_image_{i}.png')# 儲存切割圖像
cv2.imwrite(cut_image_filename, resized_cut_image) # 保存處理後的切割圖像
number, error = getNumber(resized_cut_image)
"""print(f'Predicted Number for cut_image_{i}: {number}, Error: {error}')"""
if i == 1:
c1 = number[0]
elif i == 2:
c2 = number[0]
elif i == 3:
c3 = number[0]
elif i == 4:
c4 = number[0]
c1234 = c1 + c2 + c3 + c4
input_element = driver.find_element(By.ID, "securityCode") # 根據ID查找<input>元素
input_element.send_keys(c1234)# 輸入拼接後的驗證碼
time.sleep(5)# 等待一段時間以便修改日期
submit_button = driver.find_element(By.ID, "SubmitButton")# 查找提交按鈕元素
# 點擊提交按鈕
submit_button.click()
time.sleep(3)
error_elements = driver.find_elements(By.CLASS_NAME, "feedbackPanelERROR")# 查找錯誤信息元素
# 檢查是否存在錯誤信息元素
try:
if error_elements:
for element in error_elements:
if "檢測碼輸入錯誤,請確認後重新輸入,謝謝!" in element.text:
print("檢測碼輸入錯誤,將重新輸入,謝謝!")
break
else:
print("驗證碼檢測成功")
pass1 = False # 設置標誌變量以終止循環
except NoSuchWindowException:
pass
finally:
if pass1==False:# 如果標誌變量為 False,則退出循環
break
else:
continue # 否則繼續下一輪循環
'''驗證碼'''
print("continue")
```
> 擷取圖片+處理圖片講解
> driver.save_screenshot('test.png')
> 會得到
> element = driver.find_element(By.ID,"BookingS1Form_homeCaptcha_passCode")
> left = element.location['x']
> right = element.location['x'] + element.size['width']
> top = element.location['y']
> bottom = element.location['y'] + element.size['height']
> # 裁剪驗證碼圖像
> img = Image.open('test.png') # 確保文件名以 .png 結尾
> img = img.crop((left, top, right, bottom))
> img = img.resize((119, 47))
> captcha_filename = os.path.join(folder_name, f'captcha{A}.png') # 改變擴展名為 .png
> img.save(captcha_filename, 'png')
> 得到
> img = cv2.imread(captcha_filename)
> dst = cv2.fastNlMeansDenoisingColored(img, None, 30, 30, 7, 21)
> 
> cv2.imwrite(processed_image_filename, dst)
> gray = cv2.cvtColor(dst, cv2.COLOR_BGR2GRAY)
> ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
> 
>
> cv2.imwrite(processed_image_filename, thresh)
> imgarr = thresh.copy()
> imgarr[:, 5:115] = 0
> # 提取白色像素座標
> imagedata = np.where(imgarr == 255)
> # 檢查是否找到了有效的像素座標
> if imagedata[0].size == 0:
> print("未找到白色像素,請檢查圖像處理步驟")
> continue # 跳過這一輪迭代
> X = np.array([imagedata[1]])
> Y = 47 - imagedata[0]
> # 使用多項式回歸進行擬合
> poly_reg = PolynomialFeatures(degree=2)
> X_ = poly_reg.fit_transform(X.T)
> regr = LinearRegression()
> regr.fit(X_, Y)
> X2 = np.array([[i for i in range(0, 119)]])
> X2_ = poly_reg.fit_transform(X2.T)
> # 圖像標記預測結果
> newimg = thresh.copy()
> for ele in np.column_stack([regr.predict(X2_).round(0), X2[0]]):
> pos = 47 - int(ele[0])
> newimg[pos-3:pos+3, int(ele[1])] = 255 - newimg[pos-3:pos+3, int(ele[1])]
> 
> cv2.imwrite(processed_image_filename, newimg)
> # 保存图像
> plt.figure(figsize=(10, 5))
> plt.subplot(121)
> plt.imshow(thresh, cmap='gray')
> plt.title('Threshold Image')
> plt.subplot(122)
> plt.imshow(newimg, cmap='gray')
> plt.title('Processed Image')
> plt.tight_layout()
> 
> height, width = newimg.shape
> for cut_point in cut_points:
> if 0 < cut_point < width:
> cv2.line(newimg, (cut_point, 0), (cut_point, height), (0, 0, 0), 1)
> cut_images = []
> for i, cut_point in enumerate(cut_points):
> if i == 0:
> cut_images.append(newimg[:, :cut_point])
> elif i == len(cut_points) - 1:
> cut_images.append(newimg[:, cut_points[i-1]:])
> else:
> cut_images.append(newimg[:, cut_points[i-1]:cut_point])
> # 移動 if 條件至外層循環
> for i, cut_image in enumerate(cut_images):
> # 跳過 cut_image_0 和 cut_image_5
> if i == 0 or i == 5:
> continue
> # 调整图像大小为 50x50 像素
> resized_cut_image = cv2.resize(cut_image, (50, 50))
> # 保存处理后的切割图像
> cut_image_filename = os.path.join(folder_name, f'cut_image_{i}.png')
> cv2.imwrite(cut_image_filename, resized_cut_image)
> 
> (四張切割的)
**等一下第二頁的內容**
```
time.sleep(10)#暫停10秒
```
**填入資料**
```
select_element8 = driver.find_element(By.NAME, "idInputRadio")#選擇身分證字號或護照/居留證/入出境許可證號碼
select8 = Select(select_element8)
select8.select_by_visible_text(IDch)
input_element1 = driver.find_element(By.ID, "idNumber")#輸入身分證字號
input_element1.send_keys(ID)
loveandlodid0='BookingS3Form_TicketPassengerInfoInputPanel_passengerDataView__passengerDataView2_passengerDataIdNumber'#輸入愛心票及敬老票的身分證字號
for idx, ticket in enumerate(range(Adult_child_ticket, Adult_child_ticket + len(love_tickets))):
# 在這裡處理每個票的操作,ticket 是從 Adult_child_ticket 開始的連續整數
loveandlodid1=loveandlodid0.find("BookingS3Form_TicketPassengerInfoInputPanel_passengerDataView_")+len('BookingS3Form_TicketPassengerInfoInputPanel_passengerDataView_')
loveandlodid2 = loveandlodid0[:loveandlodid1]+str(ticket)+loveandlodid0[loveandlodid1:]
input_element1 = driver.find_element(By.ID, loveandlodid2)
input_element1.send_keys(love_tickets[idx])
if membership==2:
# 找到高鐵會員 TGo 帳號的 radio 按鈕,並點擊它
driver.find_element(By.ID, "memberSystemRadio1").click()
if cheak==2:
input_element1 = driver.find_element(By.ID, "msNumber")
input_element1.send_keys(TGo)
else:
time.sleep(1)
checkbox = driver.find_element(By.ID, "memberShipCheckBox")# 點選TGo帳號是否同取票人身分證字號
checkbox.click()
elif membership==3:
# 找到企業會員統編的 radio 按鈕,並點擊它
driver.find_element(By.ID, "memberSystemRadio2").click()
input_element1 = driver.find_element(By.ID, "guNumber") #輸入企業會員統編
input_element1.send_keys(Compiled)
checkbox = driver.find_element(By.NAME, "agree")# 查找同意和取方塊
checkbox.click()
submit_button = driver.find_element(By.ID, "isSubmit")# 查找提交按鈕元素
# 點擊提交按鈕
submit_button.click()
```
### 參考資料
headline去除、表格演示
> [高鐵自動訂票(Python) - HackMD](https://hackmd.io/@easonlai0707/Syh7UKdBA)
>
部分思路大概架構
> [超简单,Python实现12306查票抢票](https://www.bilibili.com/video/BV1pM411V7Lp/?vd_source=004dfa4d7c2d18194ea4fdfdf9d2afaa)