2023-01-11, tixcraft ocr verify code by ddddocr
parent
cf4707fc93
commit
b2ead02346
|
@ -20,6 +20,7 @@ from selenium.webdriver.support.ui import WebDriverWait
|
|||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support.ui import Select
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
# for selenium 4
|
||||
from selenium.webdriver.chrome.service import Service
|
||||
from selenium.webdriver.common.action_chains import ActionChains
|
||||
|
@ -37,6 +38,10 @@ import warnings
|
|||
from urllib3.exceptions import InsecureRequestWarning
|
||||
warnings.simplefilter('ignore',InsecureRequestWarning)
|
||||
|
||||
# ocr
|
||||
import base64
|
||||
import ddddocr
|
||||
|
||||
import ssl
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
|
@ -907,7 +912,6 @@ def tixcraft_redirect(driver, url):
|
|||
game_name = ""
|
||||
|
||||
# get game_name from url
|
||||
if "/activity/detail/" in url:
|
||||
url_split = url.split("/")
|
||||
if len(url_split) >= 6:
|
||||
game_name = url_split[5]
|
||||
|
@ -915,7 +919,6 @@ def tixcraft_redirect(driver, url):
|
|||
if "/activity/detail/%s" % (game_name,) in url:
|
||||
# to support teamear
|
||||
entry_url = url.replace("/activity/detail/","/activity/game/")
|
||||
#entry_url = "tixcraft.com/activity/game/%s" % (game_name,)
|
||||
print("redirec to new url:", entry_url)
|
||||
try:
|
||||
driver.get(entry_url)
|
||||
|
@ -927,7 +930,7 @@ def tixcraft_redirect(driver, url):
|
|||
|
||||
def tixcraft_date_auto_select(driver, url, config_dict):
|
||||
show_debug_message = True # debug.
|
||||
show_debug_message = False # online
|
||||
#show_debug_message = False # online
|
||||
|
||||
# read config.
|
||||
date_auto_select_mode = config_dict["tixcraft"]["date_auto_select"]["mode"]
|
||||
|
@ -935,8 +938,6 @@ def tixcraft_date_auto_select(driver, url, config_dict):
|
|||
pass_date_is_sold_out_enable = config_dict["tixcraft"]["pass_date_is_sold_out"]
|
||||
auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"]
|
||||
|
||||
is_date_selected = False
|
||||
|
||||
# PS: for big events, check sold out text maybe not helpful, due to database is too busy.
|
||||
sold_out_text_list = ["選購一空","No tickets available","空席なし"]
|
||||
|
||||
|
@ -962,15 +963,19 @@ def tixcraft_date_auto_select(driver, url, config_dict):
|
|||
print("date keyword:", date_keyword)
|
||||
check_game_detail = True
|
||||
|
||||
if check_game_detail:
|
||||
date_list = None
|
||||
if check_game_detail:
|
||||
try:
|
||||
date_list = driver.find_elements(By.CSS_SELECTOR, '#gameList > table > tbody > tr')
|
||||
except Exception as exc:
|
||||
print("find #gameList fail")
|
||||
|
||||
button_list = []
|
||||
is_coming_soon = False
|
||||
coming_soon_condictions_list = ['開賣','剩餘','天','小時','分鐘','秒','0',':','/']
|
||||
|
||||
button_list = None
|
||||
if date_list is not None:
|
||||
button_list = []
|
||||
for row in date_list:
|
||||
# step 1: check keyword.
|
||||
is_match_keyword_row = False
|
||||
|
@ -987,6 +992,15 @@ def tixcraft_date_auto_select(driver, url, config_dict):
|
|||
row_text = ""
|
||||
|
||||
if len(row_text) > 0:
|
||||
is_match_all_coming_soon_condiction = True
|
||||
for condiction_string in coming_soon_condictions_list:
|
||||
if not condiction_string in row_text:
|
||||
is_match_all_coming_soon_condiction = False
|
||||
break
|
||||
if is_match_all_coming_soon_condiction:
|
||||
is_coming_soon = True
|
||||
break
|
||||
|
||||
if len(date_keyword) == 0:
|
||||
# no keyword, match all.
|
||||
is_match_keyword_row = True
|
||||
|
@ -1029,7 +1043,8 @@ def tixcraft_date_auto_select(driver, url, config_dict):
|
|||
print("match date row, only need first row, start to break")
|
||||
break
|
||||
|
||||
|
||||
is_date_selected = False
|
||||
if button_list is not None:
|
||||
if len(button_list) > 0:
|
||||
# default first row.
|
||||
target_row_index = 0
|
||||
|
@ -1040,10 +1055,10 @@ def tixcraft_date_auto_select(driver, url, config_dict):
|
|||
if date_auto_select_mode == CONST_RANDOM:
|
||||
target_row_index = random.randint(0,len(button_list)-1)
|
||||
|
||||
try:
|
||||
if show_debug_message:
|
||||
print("clicking row number:", target_row_index)
|
||||
|
||||
try:
|
||||
el = button_list[target_row_index]
|
||||
el.click()
|
||||
is_date_selected = True
|
||||
|
@ -1058,9 +1073,17 @@ def tixcraft_date_auto_select(driver, url, config_dict):
|
|||
# (A)user input keywords, with matched text, but no hyperlink to click.
|
||||
# (B)user input keywords, but not no matched text with hyperlink to click.
|
||||
|
||||
# [PS]: current reload condition only when No hyperlink button.
|
||||
if auto_reload_coming_soon_page_enable and not is_date_selected:
|
||||
# auto refresh for date list page.
|
||||
# [PS]: current reload condition only when
|
||||
if auto_reload_coming_soon_page_enable:
|
||||
if is_coming_soon:
|
||||
# case 2: match one row is coming soon.
|
||||
try:
|
||||
driver.refresh()
|
||||
except Exception as exc:
|
||||
pass
|
||||
else:
|
||||
if not is_date_selected:
|
||||
# case 1: No hyperlink button.
|
||||
el_list = None
|
||||
try:
|
||||
el_list = driver.find_elements(By.CSS_SELECTOR, '.btn-next')
|
||||
|
@ -1071,7 +1094,6 @@ def tixcraft_date_auto_select(driver, url, config_dict):
|
|||
driver.refresh()
|
||||
except Exception as exc:
|
||||
pass
|
||||
#print("find .btn-next fail:", exc)
|
||||
|
||||
return is_date_selected
|
||||
|
||||
|
@ -1576,9 +1598,81 @@ def tixcraft_verify(driver, presale_code):
|
|||
|
||||
return ret
|
||||
|
||||
def tixcraft_ticket_main(driver, config_dict):
|
||||
def tixcraft_manully_keyin_verify_code(driver, ocr_answer = ""):
|
||||
is_verifyCode_editing = False
|
||||
|
||||
# manually keyin verify code.
|
||||
# start to input verify code.
|
||||
form_verifyCode = None
|
||||
try:
|
||||
form_verifyCode = driver.find_element(By.ID, 'TicketForm_verifyCode')
|
||||
except Exception as exc:
|
||||
print("find form_verifyCode fail")
|
||||
|
||||
if form_verifyCode is not None:
|
||||
is_visible = False
|
||||
try:
|
||||
if form_verifyCode.is_enabled():
|
||||
is_visible = True
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
if is_visible:
|
||||
try:
|
||||
form_verifyCode.click()
|
||||
if len(ocr_answer)==4:
|
||||
#print("start to auto submit.")
|
||||
form_verifyCode.send_keys(ocr_answer)
|
||||
form_verifyCode.send_keys(Keys.ENTER)
|
||||
is_verifyCode_editing = True
|
||||
except Exception as exc:
|
||||
print("click form_verifyCode fail, tring to use javascript.")
|
||||
# plan B
|
||||
try:
|
||||
driver.execute_script("document.getElementById(\"TicketForm_verifyCode\").focus();")
|
||||
is_verifyCode_editing = True
|
||||
except Exception as exc:
|
||||
print("click form_verifyCode fail")
|
||||
pass
|
||||
pass
|
||||
return is_verifyCode_editing
|
||||
|
||||
#PS: credit to LinShihJhang's share
|
||||
def tixcraft_auto_ocr(driver, ocr):
|
||||
print("start to ddddocr")
|
||||
try:
|
||||
row_text = select_obj.first_selected_option.text
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
form_verifyCode_base64 = driver.execute_async_script("""
|
||||
var canvas = document.createElement('canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
var img = document.getElementById('yw0');
|
||||
canvas.height = img.naturalHeight;
|
||||
canvas.width = img.naturalWidth;
|
||||
context.drawImage(img, 0, 0);
|
||||
|
||||
callback = arguments[arguments.length - 1];
|
||||
callback(canvas.toDataURL());
|
||||
""")
|
||||
img_base64 = base64.b64decode(form_verifyCode_base64.split(',')[1])
|
||||
orc_answer = ocr.classification(img_base64)
|
||||
if not orc_answer is None:
|
||||
print("orc_answer:", orc_answer)
|
||||
if len(orc_answer)==4:
|
||||
tixcraft_manully_keyin_verify_code(driver, orc_answer)
|
||||
else:
|
||||
tixcraft_manully_keyin_verify_code(driver, "")
|
||||
|
||||
def tixcraft_ticket_main(driver, config_dict, ocr):
|
||||
is_finish_checkbox_click = False
|
||||
auto_check_agree = config_dict["auto_check_agree"]
|
||||
|
||||
#auto_verify_code = config_dict["auto_verify_code"]
|
||||
auto_verify_code = False
|
||||
auto_verify_code = True
|
||||
|
||||
if auto_check_agree:
|
||||
tixcraft_ticket_agree(driver)
|
||||
|
||||
|
@ -1606,7 +1700,6 @@ def tixcraft_ticket_main(driver, config_dict):
|
|||
except Exception as exc:
|
||||
pass
|
||||
|
||||
is_verifyCode_editing = False
|
||||
is_ticket_number_assigned = False
|
||||
if not select_obj is None:
|
||||
row_text = None
|
||||
|
@ -1620,6 +1713,8 @@ def tixcraft_ticket_main(driver, config_dict):
|
|||
# ticket assign.
|
||||
is_ticket_number_assigned = True
|
||||
|
||||
is_verifyCode_editing = False
|
||||
|
||||
# must wait select object ready to assign ticket number.
|
||||
if not is_ticket_number_assigned:
|
||||
# only this case:"ticket number changed by bot" to play sound!
|
||||
|
@ -1631,36 +1726,11 @@ def tixcraft_ticket_main(driver, config_dict):
|
|||
|
||||
# must wait ticket number assign to focus captcha.
|
||||
if is_ticket_number_assigned:
|
||||
# only this case to focus()
|
||||
# start to input verify code.
|
||||
form_verifyCode = None
|
||||
try:
|
||||
form_verifyCode = driver.find_element(By.ID, 'TicketForm_verifyCode')
|
||||
except Exception as exc:
|
||||
print("find form_verifyCode fail")
|
||||
|
||||
if form_verifyCode is not None:
|
||||
is_visible = False
|
||||
try:
|
||||
if form_verifyCode.is_enabled():
|
||||
is_visible = True
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
if is_visible:
|
||||
try:
|
||||
form_verifyCode.click()
|
||||
if not auto_verify_code:
|
||||
is_verifyCode_editing = tixcraft_manully_keyin_verify_code(driver)
|
||||
else:
|
||||
tixcraft_auto_ocr(driver, ocr)
|
||||
is_verifyCode_editing = True
|
||||
except Exception as exc:
|
||||
print("click form_verifyCode fail, tring to use javascript.")
|
||||
# plan B
|
||||
try:
|
||||
driver.execute_script("document.getElementById(\"TicketForm_verifyCode\").focus();")
|
||||
is_verifyCode_editing = True
|
||||
except Exception as exc:
|
||||
print("click form_verifyCode fail")
|
||||
pass
|
||||
pass
|
||||
|
||||
print("is_finish_checkbox_click:", is_finish_checkbox_click)
|
||||
|
||||
|
@ -4804,21 +4874,24 @@ def list_all_cookies(driver):
|
|||
cookies_dict[cookie['name']] = cookie['value']
|
||||
print(cookies_dict)
|
||||
|
||||
def tixcraft_main(driver, url, config_dict, is_verifyCode_editing):
|
||||
def tixcraft_main(driver, url, config_dict, is_verifyCode_editing, ocr):
|
||||
if url == 'https://tixcraft.com/':
|
||||
tixcraft_home(driver)
|
||||
|
||||
if url == 'https://indievox.com/':
|
||||
tixcraft_home(driver)
|
||||
|
||||
if "/activity/detail/" in url:
|
||||
is_redirected = tixcraft_redirect(driver, url)
|
||||
|
||||
is_date_selected = False
|
||||
if "/activity/game/" in url:
|
||||
date_auto_select_enable = config_dict["tixcraft"]["date_auto_select"]["enable"]
|
||||
if date_auto_select_enable:
|
||||
is_date_selected = tixcraft_date_auto_select(driver, url, config_dict)
|
||||
|
||||
# choose area
|
||||
if '/ticket/area/' in url:
|
||||
area_auto_select_enable = config_dict["tixcraft"]["area_auto_select"]["enable"]
|
||||
if area_auto_select_enable:
|
||||
tixcraft_area_auto_select(driver, url, config_dict)
|
||||
|
@ -4830,7 +4903,7 @@ def tixcraft_main(driver, url, config_dict, is_verifyCode_editing):
|
|||
# main app, to select ticket number.
|
||||
if '/ticket/ticket/' in url:
|
||||
if not is_verifyCode_editing:
|
||||
is_verifyCode_editing = tixcraft_ticket_main(driver, config_dict)
|
||||
is_verifyCode_editing = tixcraft_ticket_main(driver, config_dict, ocr)
|
||||
else:
|
||||
is_verifyCode_editing = False
|
||||
|
||||
|
@ -4884,7 +4957,7 @@ def famiticket_main(driver, url, config_dict):
|
|||
|
||||
def urbtix_main(driver, url, config_dict):
|
||||
# http://msg.urbtix.hk
|
||||
waiting_for_access_url = ['/session/landing-timer/0/?type=busy','msg.urbtix.hk','busy.urbtix.hk']
|
||||
waiting_for_access_url = ['/session/landing-timer/','msg.urbtix.hk','busy.urbtix.hk']
|
||||
for waiting_url in waiting_for_access_url:
|
||||
if waiting_url in url:
|
||||
# delay to avoid ip block.
|
||||
|
@ -5050,6 +5123,8 @@ def main():
|
|||
if debugMode:
|
||||
print("Start to looping, detect browser url...")
|
||||
|
||||
ocr = ddddocr.DdddOcr()
|
||||
|
||||
while True:
|
||||
time.sleep(0.1)
|
||||
|
||||
|
@ -5177,7 +5252,7 @@ def main():
|
|||
tixcraft_family = True
|
||||
|
||||
if tixcraft_family:
|
||||
is_verifyCode_editing = tixcraft_main(driver, url, config_dict, is_verifyCode_editing)
|
||||
is_verifyCode_editing = tixcraft_main(driver, url, config_dict, is_verifyCode_editing, ocr)
|
||||
|
||||
# for kktix.cc and kktix.com
|
||||
if 'kktix.c' in url:
|
||||
|
@ -5210,6 +5285,7 @@ if __name__ == "__main__":
|
|||
CONST_MODE_CLI = 1
|
||||
mode = CONST_MODE_GUI
|
||||
#mode = CONST_MODE_CLI
|
||||
|
||||
if mode == CONST_MODE_GUI:
|
||||
main()
|
||||
else:
|
||||
|
@ -5218,7 +5294,14 @@ if __name__ == "__main__":
|
|||
#captcha_text_div_text = u"請在下方空白處輸入引號內文字:「abc」"
|
||||
#captcha_text_div_text = u"請在下方空白處輸入引號內文字:「0118eveconcert」(請以半形小寫作答。)"
|
||||
#captcha_text_div_text = "在《DEEP AWAKENING見過深淵的人》專輯中,哪一首為合唱曲目? 【V6】深淵 、【Z5】浮木、【J8】無聲、【C1】以上皆非 (請以半形輸入法作答,大小寫/阿拉伯數字需要一模一樣,範例:A2)"
|
||||
#captcha_text_div_text = "Super Junior 的隊長是以下哪位? 【v】神童 【w】藝聲 【x】利特 【y】始源 若你覺得答案為 a,請輸入 a (英文為半形小寫)"
|
||||
captcha_text_div_text = "Super Junior 的隊長是以下哪位? 【v】神童 【w】藝聲 【x】利特 【y】始源 若你覺得答案為 a,請輸入 a (英文為半形小寫)"
|
||||
inferred_answer_string, answer_list = get_answer_list_from_question_string(None, captcha_text_div_text)
|
||||
print("inferred_answer_string:", inferred_answer_string)
|
||||
print("answer_list:", answer_list)
|
||||
|
||||
ocr = ddddocr.DdddOcr()
|
||||
with open('captcha-oapi.png', 'rb') as f:
|
||||
image_bytes = f.read()
|
||||
res = ocr.classification(image_bytes)
|
||||
print(res)
|
||||
|
||||
|
|
|
@ -2,8 +2,12 @@ certifi
|
|||
chardet
|
||||
cryptography
|
||||
idna
|
||||
selenium
|
||||
selenium>=4.0.0
|
||||
selenium-stealth
|
||||
undetected-chromedriver
|
||||
playsound
|
||||
pyperclip
|
||||
ddddocr
|
||||
urllib3>=1.21.1
|
||||
numpy==1.21
|
||||
daal==2021.4.0
|
|
@ -19,7 +19,7 @@ import json
|
|||
import webbrowser
|
||||
import pyperclip
|
||||
|
||||
CONST_APP_VERSION = u"MaxBot (2023.01.10)"
|
||||
CONST_APP_VERSION = u"MaxBot (2023.01.11)"
|
||||
|
||||
CONST_FROM_TOP_TO_BOTTOM = u"from top to bottom"
|
||||
CONST_FROM_BOTTOM_TO_TOP = u"from bottom to top"
|
||||
|
|
Loading…
Reference in New Issue