Merge branch 'master' into master

master
Max 2023-01-13 07:23:19 +08:00 committed by GitHub
commit db2dd72277
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 143 additions and 63 deletions

View File

@ -7,6 +7,11 @@ MaxBot is a FREE and open source bot program. Good luck getting your expected ti
https://github.com/max32002/tixcraft_bot/releases https://github.com/max32002/tixcraft_bot/releases
# Demo (示範影片) # Demo (示範影片)
Max搶票機器人 (2023-01-12) tixcraft 猜測驗證碼後不送出
https://youtu.be/mVzyDUV8Mao
Max搶票機器人 (2023-01-11) tixcraft 自動輸入驗證碼 Max搶票機器人 (2023-01-11) tixcraft 自動輸入驗證碼
https://youtu.be/t1k0CvmBNhQ (macOS) https://youtu.be/t1k0CvmBNhQ (macOS)

View File

@ -1389,6 +1389,7 @@ def tixcraft_ticket_agree(driver):
try: try:
# TODO: check the status: checked. # TODO: check the status: checked.
if form_checkbox.is_enabled(): if form_checkbox.is_enabled():
if not form_checkbox.is_selected():
form_checkbox.click() form_checkbox.click()
is_finish_checkbox_click = True is_finish_checkbox_click = True
except Exception as exc: except Exception as exc:
@ -1623,8 +1624,9 @@ def tixcraft_toast(driver, message):
except Exception as exc: except Exception as exc:
print("find toast element fail") print("find toast element fail")
def tixcraft_manully_keyin_verify_code(driver, answer = "", auto_submit = False): def tixcraft_keyin_captcha_code(driver, answer = "", auto_submit = False):
is_verifyCode_editing = False is_verifyCode_editing = False
is_form_sumbited = False
# manually keyin verify code. # manually keyin verify code.
# start to input verify code. # start to input verify code.
@ -1645,14 +1647,6 @@ def tixcraft_manully_keyin_verify_code(driver, answer = "", auto_submit = False)
if is_visible: if is_visible:
try: try:
form_verifyCode.click() form_verifyCode.click()
#print("start to fill answer.")
form_verifyCode.send_keys(answer)
if auto_submit:
form_verifyCode.send_keys(Keys.ENTER)
else:
driver.execute_script("document.getElementById(\"TicketForm_verifyCode\").select();")
tixcraft_toast(driver, "※ Press Enter if answer is: " + answer)
is_verifyCode_editing = True is_verifyCode_editing = True
except Exception as exc: except Exception as exc:
print("click form_verifyCode fail, tring to use javascript.") print("click form_verifyCode fail, tring to use javascript.")
@ -1661,65 +1655,93 @@ def tixcraft_manully_keyin_verify_code(driver, answer = "", auto_submit = False)
driver.execute_script("document.getElementById(\"TicketForm_verifyCode\").focus();") driver.execute_script("document.getElementById(\"TicketForm_verifyCode\").focus();")
is_verifyCode_editing = True is_verifyCode_editing = True
except Exception as exc: except Exception as exc:
print("click form_verifyCode fail") print("click form_verifyCode fail.")
pass
pass #print("start to fill answer.")
return is_verifyCode_editing try:
if len(answer) > 0:
form_verifyCode.send_keys(answer)
if auto_submit:
form_verifyCode.send_keys(Keys.ENTER)
is_verifyCode_editing = False
is_form_sumbited = True
else:
driver.execute_script("document.getElementById(\"TicketForm_verifyCode\").select();")
if len(answer) > 0:
tixcraft_toast(driver, "※ 按 Enter 如果答案是: " + answer)
except Exception as exc:
print("send_keys ocr answer fail.")
return is_verifyCode_editing, is_form_sumbited
def tixcraft_reload_captcha(driver):
# manually keyin verify code.
# start to input verify code.
ret = False
form_captcha = None
try:
form_captcha = driver.find_element(By.ID, 'yw0')
if not form_captcha is None:
form_captcha.click()
ret = True
except Exception as exc:
print("find form_captcha fail")
return ret
#PS: credit to LinShihJhang's share #PS: credit to LinShihJhang's share
def tixcraft_auto_ocr(driver, ocr, ocr_captcha_with_submit): def tixcraft_auto_ocr(driver, ocr, ocr_captcha_with_submit, ocr_captcha_force_submit, previous_answer):
print("start to ddddocr") print("start to ddddocr")
from NonBrowser import NonBrowser from NonBrowser import NonBrowser
is_need_redo_ocr = False
is_form_sumbited = False
orc_answer = None
if not ocr is None:
Non_Browser = NonBrowser() Non_Browser = NonBrowser()
Non_Browser.Set_cookies(driver.get_cookies()) Non_Browser.Set_cookies(driver.get_cookies())
ocr_count = 0 #ocr 次數
ocr_total_count = 0 #ocr 總次數
orc_answer = None
while True:
if ocr_total_count >= 6: #如果總次數大於6次, 直接手動介入
orc_answer = None
break
if ocr_count >= 3: #如果次數大於3次, 取得新的Captcha
print("Get New Captcha")
new_captcha_url = Non_Browser.Request_Refresh_Captcha() #取得新的CAPTCHA
if new_captcha_url != "": #如果capthca取得成功繼續OCR, 失敗直接手動介入
ocr_count = 0
tixcraft_change_captcha(driver,new_captcha_url) #更改CAPTCHA圖
continue
else:
orc_answer = None
break
ocr_count += 1
ocr_total_count += 1
img_base64 = base64.b64decode(Non_Browser.Request_Captcha()) img_base64 = base64.b64decode(Non_Browser.Request_Captcha())
if not ocr is None:
try: try:
orc_answer = ocr.classification(img_base64) orc_answer = ocr.classification(img_base64)
if not orc_answer is None:
if len(orc_answer)==4:
break
except Exception as exc: except Exception as exc:
pass pass
else: else:
print("ddddocr is None") print("ddddocr is None")
break
print("ocr_total_count:",ocr_total_count)
if not orc_answer is None: if not orc_answer is None:
orc_answer = orc_answer.strip()
print("orc_answer:", orc_answer) print("orc_answer:", orc_answer)
if len(orc_answer)==4: if len(orc_answer)==4:
tixcraft_manully_keyin_verify_code(driver, answer = orc_answer) who_care_var, is_form_sumbited = tixcraft_keyin_captcha_code(driver, answer = orc_answer, auto_submit = ocr_captcha_with_submit)
else: else:
tixcraft_manully_keyin_verify_code(driver) if not ocr_captcha_force_submit:
tixcraft_keyin_captcha_code(driver)
tixcraft_toast(driver, "※ Ocr fail...") tixcraft_toast(driver, "※ Ocr fail...")
else: else:
tixcraft_manully_keyin_verify_code(driver) is_need_redo_ocr = True
if previous_answer != orc_answer:
previous_answer = orc_answer
print("click captcha again")
tixcraft_reload_captcha(driver)
time.sleep(0.3)
else:
print("orc_answer is None")
print("previous_answer:", previous_answer)
if previous_answer is None:
tixcraft_keyin_captcha_code(driver)
else:
# page is not ready, retry again.
is_need_redo_ocr = True
return is_need_redo_ocr, previous_answer, is_form_sumbited
def tixcraft_ticket_main(driver, config_dict, ocr): def tixcraft_ticket_main(driver, config_dict, ocr):
is_finish_checkbox_click = False
auto_check_agree = config_dict["auto_check_agree"] auto_check_agree = config_dict["auto_check_agree"]
ocr_captcha_enable = config_dict["ocr_captcha"]["enable"] ocr_captcha_enable = config_dict["ocr_captcha"]["enable"]
ocr_captcha_with_submit = config_dict["ocr_captcha"]["auto_submit"] ocr_captcha_with_submit = config_dict["ocr_captcha"]["auto_submit"]
ocr_captcha_force_submit = config_dict["ocr_captcha"]["force_submit"]
if auto_check_agree: if auto_check_agree:
tixcraft_ticket_agree(driver) tixcraft_ticket_agree(driver)
@ -1775,12 +1797,20 @@ def tixcraft_ticket_main(driver, config_dict, ocr):
# must wait ticket number assign to focus captcha. # must wait ticket number assign to focus captcha.
if is_ticket_number_assigned: if is_ticket_number_assigned:
if not ocr_captcha_enable: if not ocr_captcha_enable:
is_verifyCode_editing = tixcraft_manully_keyin_verify_code(driver) is_verifyCode_editing = tixcraft_keyin_captcha_code(driver)
else: else:
tixcraft_auto_ocr(driver, ocr, ocr_captcha_with_submit) previous_answer = None
is_verifyCode_editing = True is_verifyCode_editing = True
for redo_ocr in range(999):
print("is_finish_checkbox_click:", is_finish_checkbox_click) is_need_redo_ocr, previous_answer, is_form_sumbited = tixcraft_auto_ocr(driver, ocr, ocr_captcha_with_submit, ocr_captcha_force_submit, previous_answer)
if is_form_sumbited:
# start next loop.
is_verifyCode_editing = False
break
if not ocr_captcha_force_submit:
break
if not is_need_redo_ocr:
break
if is_verifyCode_editing: if is_verifyCode_editing:
print("goto is_verifyCode_editing == True") print("goto is_verifyCode_editing == True")
@ -5174,7 +5204,7 @@ def main():
ocr = None ocr = None
try: try:
if config_dict["ocr_captcha"]["enable"]: if config_dict["ocr_captcha"]["enable"]:
ocr = ddddocr.DdddOcr() ocr = ddddocr.DdddOcr(show_ad=False, beta=True)
except Exception as exc: except Exception as exc:
pass pass
@ -5352,8 +5382,8 @@ if __name__ == "__main__":
print("inferred_answer_string:", inferred_answer_string) print("inferred_answer_string:", inferred_answer_string)
print("answer_list:", answer_list) print("answer_list:", answer_list)
ocr = ddddocr.DdddOcr() ocr = ddddocr.DdddOcr(show_ad=False, beta=True)
with open('captcha-oapi.png', 'rb') as f: with open('captcha-xxxx.png', 'rb') as f:
image_bytes = f.read() image_bytes = f.read()
res = ocr.classification(image_bytes) res = ocr.classification(image_bytes)
print(res) print(res)

View File

@ -1 +1 @@
{"homepage": "https://tixcraft.com", "browser": "chrome", "language": "\u7e41\u9ad4\u4e2d\u6587", "ticket_number": 2, "pass_1_seat_remaining": true, "auto_check_agree": true, "ocr_captcha": {"enable": true, "auto_submit": false}, "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true, "area_mode": "from top to bottom", "area_keyword_1": "", "area_keyword_1_and": "", "area_keyword_2": "", "area_keyword_2_and": "", "auto_guess_options": false, "user_guess_string": ""}, "tixcraft": {"date_auto_select": {"enable": true, "date_keyword": "", "mode": "from top to bottom"}, "area_auto_select": {"enable": true, "area_keyword_1": "", "area_keyword_2": "", "area_keyword_3": "", "area_keyword_4": "", "mode": "from top to bottom"}, "pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true, "presale_code": ""}, "advanced": {"play_captcha_sound": {"enable": true, "filename": "ding-dong.wav"}, "facebook_account": "", "kktix_account": "", "adblock_plus_enable": true}, "debug": false} {"homepage": "https://tixcraft.com", "browser": "chrome", "language": "\u7e41\u9ad4\u4e2d\u6587", "ticket_number": 2, "pass_1_seat_remaining": true, "auto_check_agree": true, "ocr_captcha": {"enable": true, "auto_submit": true, "force_submit": true}, "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true, "area_mode": "from top to bottom", "area_keyword_1": "", "area_keyword_1_and": "", "area_keyword_2": "", "area_keyword_2_and": "", "auto_guess_options": false, "user_guess_string": ""}, "tixcraft": {"date_auto_select": {"enable": true, "date_keyword": "", "mode": "from top to bottom"}, "area_auto_select": {"enable": true, "area_keyword_1": "", "area_keyword_2": "", "area_keyword_3": "", "area_keyword_4": "", "mode": "from top to bottom"}, "pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true, "presale_code": ""}, "advanced": {"play_captcha_sound": {"enable": true, "filename": "ding-dong.wav"}, "facebook_account": "", "kktix_account": "", "adblock_plus_enable": false}, "debug": false}

View File

@ -19,7 +19,7 @@ import json
import webbrowser import webbrowser
import pyperclip import pyperclip
CONST_APP_VERSION = u"MaxBot (2023.01.12)3版" CONST_APP_VERSION = u"MaxBot (2023.01.13)"
CONST_FROM_TOP_TO_BOTTOM = u"from top to bottom" CONST_FROM_TOP_TO_BOTTOM = u"from top to bottom"
CONST_FROM_BOTTOM_TO_TOP = u"from bottom to top" CONST_FROM_BOTTOM_TO_TOP = u"from bottom to top"
@ -78,6 +78,7 @@ def load_translate():
en_us["pass_1_seat_remaining"] = 'Pass 1 seat remaining' en_us["pass_1_seat_remaining"] = 'Pass 1 seat remaining'
en_us["ocr_captcha"] = 'OCR captcha' en_us["ocr_captcha"] = 'OCR captcha'
en_us["ocr_captcha_with_submit"] = 'After guess auto submit' en_us["ocr_captcha_with_submit"] = 'After guess auto submit'
en_us["ocr_captcha_force_submit"] = 'Allow submit wrong answer'
en_us["preference"] = 'Preference' en_us["preference"] = 'Preference'
en_us["advanced"] = 'Advanced' en_us["advanced"] = 'Advanced'
@ -135,6 +136,7 @@ def load_translate():
zh_tw["pass_1_seat_remaining"] = '避開「剩餘 1」的區域' zh_tw["pass_1_seat_remaining"] = '避開「剩餘 1」的區域'
zh_tw["ocr_captcha"] = '猜測驗證碼' zh_tw["ocr_captcha"] = '猜測驗證碼'
zh_tw["ocr_captcha_with_submit"] = '猜測後自動送出' zh_tw["ocr_captcha_with_submit"] = '猜測後自動送出'
zh_tw["ocr_captcha_force_submit"] = '允許送出錯的驗證碼'
zh_tw["preference"] = '偏好設定' zh_tw["preference"] = '偏好設定'
zh_tw["advanced"] = '進階設定' zh_tw["advanced"] = '進階設定'
@ -192,6 +194,7 @@ def load_translate():
zh_cn["pass_1_seat_remaining"] = '避开“剩余 1”的区域' zh_cn["pass_1_seat_remaining"] = '避开“剩余 1”的区域'
zh_cn["ocr_captcha"] = '猜测验证码' zh_cn["ocr_captcha"] = '猜测验证码'
zh_cn["ocr_captcha_with_submit"] = '猜测后自动送出' zh_cn["ocr_captcha_with_submit"] = '猜测后自动送出'
zh_cn["ocr_captcha_force_submit"] = '允许送出错的验证码'
zh_cn["preference"] = '偏好设定' zh_cn["preference"] = '偏好设定'
zh_cn["advanced"] = '進階設定' zh_cn["advanced"] = '進階設定'
@ -250,6 +253,7 @@ def load_translate():
ja_jp["pass_1_seat_remaining"] = '「1 席残り」エリアは避ける' ja_jp["pass_1_seat_remaining"] = '「1 席残り」エリアは避ける'
ja_jp["ocr_captcha"] = 'キャプチャを推測する' ja_jp["ocr_captcha"] = 'キャプチャを推測する'
ja_jp["ocr_captcha_with_submit"] = '提出で推測した後' ja_jp["ocr_captcha_with_submit"] = '提出で推測した後'
zh_cn["ocr_captcha_force_submit"] = '間違った回答の送信を許可する'
ja_jp["preference"] = '設定' ja_jp["preference"] = '設定'
ja_jp["advanced"] = '高度な設定' ja_jp["advanced"] = '高度な設定'
@ -303,6 +307,7 @@ def get_default_config():
config_dict["ocr_captcha"] = {} config_dict["ocr_captcha"] = {}
config_dict["ocr_captcha"]["enable"] = True config_dict["ocr_captcha"]["enable"] = True
config_dict["ocr_captcha"]["auto_submit"] = False config_dict["ocr_captcha"]["auto_submit"] = False
config_dict["ocr_captcha"]["force_submit"] = False
config_dict['kktix']={} config_dict['kktix']={}
config_dict["kktix"]["auto_press_next_step_button"] = True config_dict["kktix"]["auto_press_next_step_button"] = True
@ -425,6 +430,7 @@ def btn_save_act(language_code, slience_mode=False):
global chk_state_adblock_plus global chk_state_adblock_plus
global chk_state_ocr_captcha global chk_state_ocr_captcha
global chk_state_ocr_captcha_with_submit global chk_state_ocr_captcha_with_submit
global chk_state_ocr_captcha_force_submit
is_all_data_correct = True is_all_data_correct = True
@ -500,6 +506,7 @@ def btn_save_act(language_code, slience_mode=False):
config_dict["ocr_captcha"] = {} config_dict["ocr_captcha"] = {}
config_dict["ocr_captcha"]["enable"] = bool(chk_state_ocr_captcha.get()) config_dict["ocr_captcha"]["enable"] = bool(chk_state_ocr_captcha.get())
config_dict["ocr_captcha"]["auto_submit"] = bool(chk_state_ocr_captcha_with_submit.get()) config_dict["ocr_captcha"]["auto_submit"] = bool(chk_state_ocr_captcha_with_submit.get())
config_dict["ocr_captcha"]["force_submit"] = bool(chk_state_ocr_captcha_force_submit.get())
# save config. # save config.
if is_all_data_correct: if is_all_data_correct:
@ -661,6 +668,7 @@ def applyNewLanguage():
global lbl_presale_code global lbl_presale_code
global lbl_ocr_captcha global lbl_ocr_captcha
global lbl_ocr_captcha_with_submit global lbl_ocr_captcha_with_submit
global lbl_ocr_captcha_force_submit
# for checkbox # for checkbox
global chk_pass_1_seat_remaining global chk_pass_1_seat_remaining
@ -677,6 +685,7 @@ def applyNewLanguage():
global chk_adblock_plus global chk_adblock_plus
global chk_ocr_captcha global chk_ocr_captcha
global chk_ocr_captcha_with_sumit global chk_ocr_captcha_with_sumit
global chk_ocr_captcha_force_sumit
global tabControl global tabControl
@ -720,6 +729,7 @@ def applyNewLanguage():
lbl_presale_code.config(text=translate[language_code]["user_guess_string"]) lbl_presale_code.config(text=translate[language_code]["user_guess_string"])
lbl_ocr_captcha.config(text=translate[language_code]["ocr_captcha"]) lbl_ocr_captcha.config(text=translate[language_code]["ocr_captcha"])
lbl_ocr_captcha_with_submit.config(text=translate[language_code]["ocr_captcha_with_submit"]) lbl_ocr_captcha_with_submit.config(text=translate[language_code]["ocr_captcha_with_submit"])
lbl_ocr_captcha_force_submit.config(text=translate[language_code]["ocr_captcha_force_submit"])
chk_pass_1_seat_remaining.config(text=translate[language_code]["enable"]) chk_pass_1_seat_remaining.config(text=translate[language_code]["enable"])
chk_auto_check_agree.config(text=translate[language_code]["enable"]) chk_auto_check_agree.config(text=translate[language_code]["enable"])
@ -734,6 +744,7 @@ def applyNewLanguage():
chk_adblock_plus.config(text=translate[language_code]["enable"]) chk_adblock_plus.config(text=translate[language_code]["enable"])
chk_ocr_captcha.config(text=translate[language_code]["enable"]) chk_ocr_captcha.config(text=translate[language_code]["enable"])
chk_ocr_captcha_with_sumit.config(text=translate[language_code]["enable"]) chk_ocr_captcha_with_sumit.config(text=translate[language_code]["enable"])
chk_ocr_captcha_force_sumit.config(text=translate[language_code]["enable"])
tabControl.tab(0, text=translate[language_code]["preference"]) tabControl.tab(0, text=translate[language_code]["preference"])
tabControl.tab(1, text=translate[language_code]["advanced"]) tabControl.tab(1, text=translate[language_code]["advanced"])
@ -825,6 +836,22 @@ def showHideOcrCaptchaWithSubmit():
lbl_ocr_captcha_with_submit.grid_forget() lbl_ocr_captcha_with_submit.grid_forget()
chk_ocr_captcha_with_sumit.grid_forget() chk_ocr_captcha_with_sumit.grid_forget()
global chk_state_ocr_captcha_with_submit
is_ocr_captcha_auto_submit_enable = bool(chk_state_ocr_captcha_with_submit.get())
global ocr_captcha_force_submit_index
global lbl_ocr_captcha_force_submit
global chk_ocr_captcha_force_sumit
if is_ocr_captcha_auto_submit_enable:
# show.
lbl_ocr_captcha_force_submit.grid(column=0, row=ocr_captcha_force_submit_index, sticky = E)
chk_ocr_captcha_force_sumit.grid(column=1, row=ocr_captcha_force_submit_index, sticky = W)
else:
# hide
lbl_ocr_captcha_force_submit.grid_forget()
chk_ocr_captcha_force_sumit.grid_forget()
def showHidePass1SeatRemaining(): def showHidePass1SeatRemaining():
global combo_ticket_number global combo_ticket_number
ticket_number_int = int(combo_ticket_number.get().strip()) ticket_number_int = int(combo_ticket_number.get().strip())
@ -1501,9 +1528,27 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X):
chk_state_ocr_captcha_with_submit.set(config_dict['ocr_captcha']["auto_submit"]) chk_state_ocr_captcha_with_submit.set(config_dict['ocr_captcha']["auto_submit"])
global chk_ocr_captcha_with_sumit global chk_ocr_captcha_with_sumit
chk_ocr_captcha_with_sumit = Checkbutton(frame_group_tixcraft, text=translate[language_code]['enable'], variable=chk_state_ocr_captcha_with_submit) chk_ocr_captcha_with_sumit = Checkbutton(frame_group_tixcraft, text=translate[language_code]['enable'], variable=chk_state_ocr_captcha_with_submit, command=showHideOcrCaptchaWithSubmit)
chk_ocr_captcha_with_sumit.grid(column=1, row=group_row_count, sticky = W) chk_ocr_captcha_with_sumit.grid(column=1, row=group_row_count, sticky = W)
group_row_count+=1
global ocr_captcha_force_submit_index
ocr_captcha_force_submit_index = group_row_count
global lbl_ocr_captcha_force_submit
lbl_ocr_captcha_force_submit = Label(frame_group_tixcraft, text=translate[language_code]['ocr_captcha_force_submit'])
lbl_ocr_captcha_force_submit.grid(column=0, row=ocr_captcha_force_submit_index, sticky = E)
global chk_state_ocr_captcha_force_submit
chk_state_ocr_captcha_force_submit = BooleanVar()
chk_state_ocr_captcha_force_submit.set(config_dict['ocr_captcha']["force_submit"])
global chk_ocr_captcha_force_sumit
chk_ocr_captcha_force_sumit = Checkbutton(frame_group_tixcraft, text=translate[language_code]['enable'], variable=chk_state_ocr_captcha_force_submit)
chk_ocr_captcha_force_sumit.grid(column=1, row=group_row_count, sticky = W)
# final flush.
global frame_group_tixcraft_index global frame_group_tixcraft_index
frame_group_tixcraft_index = row_count frame_group_tixcraft_index = row_count
#PS: don't need show when onload(), because show/hide block will load again. #PS: don't need show when onload(), because show/hide block will load again.
@ -1816,7 +1861,7 @@ def main():
load_GUI(root, config_dict) load_GUI(root, config_dict)
GUI_SIZE_WIDTH = 460 GUI_SIZE_WIDTH = 460
GUI_SIZE_HEIGHT = 594 GUI_SIZE_HEIGHT = 615
GUI_SIZE_MACOS = str(GUI_SIZE_WIDTH) + 'x' + str(GUI_SIZE_HEIGHT) GUI_SIZE_MACOS = str(GUI_SIZE_WIDTH) + 'x' + str(GUI_SIZE_HEIGHT)
GUI_SIZE_WINDOWS=str(GUI_SIZE_WIDTH-60) + 'x' + str(GUI_SIZE_HEIGHT-90) GUI_SIZE_WINDOWS=str(GUI_SIZE_WIDTH-60) + 'x' + str(GUI_SIZE_HEIGHT-90)