fix bugs for tixcraft.
parent
da3678960e
commit
73ec0403e8
|
@ -656,7 +656,6 @@ def get_driver_by_config(config_dict):
|
|||
driver.delete_cookie("SID")
|
||||
driver.add_cookie({"name":"SID", "value": tixcraft_sid, "path" : "/", "secure":True})
|
||||
|
||||
|
||||
if 'ibon.com' in homepage:
|
||||
if len(config_dict["advanced"]["ibonqware"]) > 1:
|
||||
ibonqware = decryptMe(config_dict["advanced"]["ibonqware"])
|
||||
|
@ -4876,6 +4875,9 @@ def cityline_performance(driver, config_dict):
|
|||
show_debug_message = True # debug.
|
||||
show_debug_message = False # online
|
||||
|
||||
if config_dict["advanced"]["verbose"]:
|
||||
show_debug_message = True
|
||||
|
||||
is_price_assign_by_bot = False
|
||||
is_need_refresh = False
|
||||
|
||||
|
@ -7892,13 +7894,14 @@ def kham_keyin_captcha_code(driver, answer = "", auto_submit = False):
|
|||
|
||||
return is_verifyCode_editing, is_form_sumbited
|
||||
|
||||
def kham_auto_ocr(driver, ocr, away_from_keyboard_enable, previous_answer, Captcha_Browser, ocr_captcha_image_source, model_name):
|
||||
def kham_auto_ocr(driver, config_dict, ocr, away_from_keyboard_enable, previous_answer, Captcha_Browser, ocr_captcha_image_source, model_name):
|
||||
show_debug_message = True # debug.
|
||||
show_debug_message = False # online
|
||||
print("start to ddddocr")
|
||||
|
||||
CONST_OCR_CAPTCH_IMAGE_SOURCE_NON_BROWSER = "NonBrowser"
|
||||
CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS = "canvas"
|
||||
if config_dict["advanced"]["verbose"]:
|
||||
show_debug_message = True
|
||||
|
||||
print("start to ddddocr")
|
||||
|
||||
is_need_redo_ocr = False
|
||||
is_form_sumbited = False
|
||||
|
@ -8001,7 +8004,7 @@ def kham_captcha(driver, config_dict, ocr, Captcha_Browser, model_name):
|
|||
previous_answer = None
|
||||
is_verifyCode_editing = True
|
||||
for redo_ocr in range(999):
|
||||
is_need_redo_ocr, previous_answer, is_form_sumbited = kham_auto_ocr(driver, ocr, away_from_keyboard_enable, previous_answer, Captcha_Browser, ocr_captcha_image_source, model_name)
|
||||
is_need_redo_ocr, previous_answer, is_form_sumbited = kham_auto_ocr(driver, config_dict, ocr, away_from_keyboard_enable, previous_answer, Captcha_Browser, ocr_captcha_image_source, model_name)
|
||||
|
||||
# TODO: must ensure the answer is corrent...
|
||||
is_cpatcha_sent = True
|
||||
|
@ -8149,6 +8152,486 @@ def kham_main(driver, url, config_dict, ocr, Captcha_Browser):
|
|||
if len(account) > 4:
|
||||
kham_login(driver, account, decryptMe(config_dict["advanced"]["kham_password"]))
|
||||
|
||||
def ticketplus_date_auto_select(driver, config_dict):
|
||||
show_debug_message = True # debug.
|
||||
show_debug_message = False # online
|
||||
|
||||
if config_dict["advanced"]["verbose"]:
|
||||
show_debug_message = True
|
||||
|
||||
# read config.
|
||||
auto_select_mode = config_dict["tixcraft"]["date_auto_select"]["mode"]
|
||||
date_keyword = config_dict["tixcraft"]["date_auto_select"]["date_keyword"].strip()
|
||||
# TODO: implement this feature.
|
||||
date_keyword_and = ""
|
||||
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"]
|
||||
|
||||
if show_debug_message:
|
||||
print("date_auto_select_mode:", auto_select_mode)
|
||||
print("date_keyword:", date_keyword)
|
||||
|
||||
area_list = None
|
||||
try:
|
||||
area_list = driver.find_elements(By.CSS_SELECTOR, 'div#buyTicket > div.sesstion-item')
|
||||
except Exception as exc:
|
||||
print("find #gameList fail")
|
||||
|
||||
find_ticket_text_list = ['立即購票']
|
||||
sold_out_text_list = ['銷售一空','尚未開賣']
|
||||
|
||||
matched_blocks = None
|
||||
formated_area_list = None
|
||||
|
||||
if area_list is not None:
|
||||
area_list_count = len(area_list)
|
||||
if show_debug_message:
|
||||
print("date_list_count:", area_list_count)
|
||||
|
||||
if area_list_count > 0:
|
||||
formated_area_list = []
|
||||
row_index = 0
|
||||
for row in area_list:
|
||||
row_index += 1
|
||||
row_is_enabled=True
|
||||
try:
|
||||
if not row.is_enabled():
|
||||
row_is_enabled=False
|
||||
|
||||
row_text = ""
|
||||
# check buy button.
|
||||
if row_is_enabled:
|
||||
row_text = row.text
|
||||
if row_text is None:
|
||||
row_text = ""
|
||||
|
||||
row_is_enabled=False
|
||||
for text_item in find_ticket_text_list:
|
||||
if text_item in row_text:
|
||||
row_is_enabled = True
|
||||
break
|
||||
|
||||
# check sold out text.
|
||||
if row_is_enabled:
|
||||
if pass_date_is_sold_out_enable:
|
||||
for sold_out_item in sold_out_text_list:
|
||||
if sold_out_item in row_text:
|
||||
row_is_enabled = False
|
||||
if show_debug_message:
|
||||
print("match sold out text: %s, skip this row." % (sold_out_item))
|
||||
break
|
||||
|
||||
except Exception as exc:
|
||||
if show_debug_message:
|
||||
print(exc)
|
||||
pass
|
||||
|
||||
if row_is_enabled:
|
||||
formated_area_list.append(row)
|
||||
|
||||
if show_debug_message:
|
||||
print("formated_area_list count:", len(formated_area_list))
|
||||
|
||||
if len(date_keyword) == 0:
|
||||
matched_blocks = formated_area_list
|
||||
else:
|
||||
# match keyword.
|
||||
date_keyword = format_keyword_string(date_keyword)
|
||||
if show_debug_message:
|
||||
print("start to match formated keyword:", date_keyword)
|
||||
matched_blocks = []
|
||||
|
||||
row_index = 0
|
||||
for row in formated_area_list:
|
||||
row_index += 1
|
||||
row_is_enabled=True
|
||||
if row_is_enabled:
|
||||
row_text = ""
|
||||
try:
|
||||
row_text = row.text
|
||||
except Exception as exc:
|
||||
print("get text fail")
|
||||
break
|
||||
|
||||
if row_text is None:
|
||||
row_text = ""
|
||||
|
||||
if len(row_text) > 0:
|
||||
row_text = format_keyword_string(row_text)
|
||||
if show_debug_message:
|
||||
print("row_text:", row_text)
|
||||
|
||||
is_match_area = False
|
||||
match_area_code = 0
|
||||
|
||||
if date_keyword in row_text:
|
||||
if len(date_keyword_and) == 0:
|
||||
if show_debug_message:
|
||||
print('keyword_and # is empty, directly match.')
|
||||
# keyword #2 is empty, direct append.
|
||||
is_match_area = True
|
||||
match_area_code = 2
|
||||
else:
|
||||
if date_keyword_and in row_text:
|
||||
if show_debug_message:
|
||||
print('match keyword_and')
|
||||
is_match_area = True
|
||||
match_area_code = 3
|
||||
else:
|
||||
if show_debug_message:
|
||||
print('not match keyword_and')
|
||||
pass
|
||||
|
||||
if is_match_area:
|
||||
matched_blocks.append(row)
|
||||
|
||||
if show_debug_message:
|
||||
if not matched_blocks is None:
|
||||
print("after match keyword, found count:", len(matched_blocks))
|
||||
else:
|
||||
print("not found date-time-position")
|
||||
pass
|
||||
else:
|
||||
print("date date-time-position is None")
|
||||
pass
|
||||
|
||||
target_area = None
|
||||
if matched_blocks is not None:
|
||||
if len(matched_blocks) > 0:
|
||||
target_row_index = 0
|
||||
|
||||
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
|
||||
pass
|
||||
|
||||
if auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
|
||||
target_row_index = len(matched_blocks)-1
|
||||
|
||||
if auto_select_mode == CONST_RANDOM:
|
||||
target_row_index = random.randint(0,len(matched_blocks)-1)
|
||||
|
||||
target_area = matched_blocks[target_row_index]
|
||||
|
||||
is_date_clicked = False
|
||||
if target_area is not None:
|
||||
target_button = None
|
||||
try:
|
||||
target_button = target_area.find_element(By.CSS_SELECTOR, 'button')
|
||||
if not target_button is None:
|
||||
if target_button.is_enabled():
|
||||
if show_debug_message:
|
||||
print("start to press button...")
|
||||
target_button.click()
|
||||
is_date_clicked = True
|
||||
else:
|
||||
if show_debug_message:
|
||||
print("target_button in target row is None.")
|
||||
except Exception as exc:
|
||||
if show_debug_message:
|
||||
print("find or press button fail:", exc)
|
||||
|
||||
if not target_button is None:
|
||||
print("try to click button fail, force click by js.")
|
||||
try:
|
||||
driver.execute_script("arguments[0].click();", target_button)
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
# [PS]: current reload condition only when
|
||||
if auto_reload_coming_soon_page_enable:
|
||||
if not is_date_clicked:
|
||||
if not formated_area_list is None:
|
||||
if len(formated_area_list) == 0:
|
||||
try:
|
||||
driver.refresh()
|
||||
time.sleep(0.3)
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
return is_date_clicked
|
||||
|
||||
def ticketplus_order(driver, config_dict, ocr, Captcha_Browser):
|
||||
ticket_number_div = None
|
||||
try:
|
||||
ticket_number_div = driver.find_element(By.CSS_SELECTOR, 'div.count-button > div')
|
||||
except Exception as exc:
|
||||
print("find ticket_number_div fail")
|
||||
|
||||
ticket_number = config_dict["ticket_number"]
|
||||
if not ticket_number_div is None:
|
||||
ticket_number_text = ""
|
||||
ticket_number_text_int = 0
|
||||
try:
|
||||
ticket_number_text = ticket_number_div.text
|
||||
except Exception as exc:
|
||||
print("get ticket_number_text fail")
|
||||
pass
|
||||
|
||||
if ticket_number_text is None:
|
||||
ticket_number_text = ""
|
||||
if len(ticket_number_text) > 0:
|
||||
ticket_number_text_int = int(ticket_number_text)
|
||||
if ticket_number_text_int < ticket_number:
|
||||
ticket_number_plus = None
|
||||
try:
|
||||
ticket_number_plus = driver.find_element(By.CSS_SELECTOR, 'button > span > i.mid-plus')
|
||||
except Exception as exc:
|
||||
print("find ticket_number_plus fail")
|
||||
|
||||
# add
|
||||
add_count = ticket_number - ticket_number_text_int
|
||||
for i in range(add_count):
|
||||
if not ticket_number_plus is None:
|
||||
try:
|
||||
if ticket_number_plus.is_enabled():
|
||||
ticket_number_plus.click()
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
|
||||
ocr_captcha_enable = config_dict["ocr_captcha"]["enable"]
|
||||
away_from_keyboard_enable = config_dict["ocr_captcha"]["force_submit"]
|
||||
if not ocr_captcha_enable:
|
||||
away_from_keyboard_enable = False
|
||||
ocr_captcha_image_source = config_dict["ocr_captcha"]["image_source"]
|
||||
|
||||
is_cpatcha_sent = False
|
||||
previous_answer = None
|
||||
is_verifyCode_editing = True
|
||||
for redo_ocr in range(999):
|
||||
is_need_redo_ocr, previous_answer, is_form_sumbited = ticketplus_auto_ocr(driver, config_dict, ocr, away_from_keyboard_enable, previous_answer, Captcha_Browser, ocr_captcha_image_source)
|
||||
|
||||
# TODO: must ensure the answer is corrent...
|
||||
is_cpatcha_sent = True
|
||||
|
||||
if is_form_sumbited:
|
||||
break
|
||||
|
||||
if not away_from_keyboard_enable:
|
||||
break
|
||||
|
||||
if not is_need_redo_ocr:
|
||||
break
|
||||
|
||||
def ticketplus_auto_ocr(driver, config_dict, ocr, away_from_keyboard_enable, previous_answer, Captcha_Browser, ocr_captcha_image_source):
|
||||
show_debug_message = True # debug.
|
||||
show_debug_message = False # online
|
||||
|
||||
if config_dict["advanced"]["verbose"]:
|
||||
show_debug_message = True
|
||||
|
||||
print("start to ddddocr")
|
||||
|
||||
is_need_redo_ocr = False
|
||||
is_form_sumbited = False
|
||||
|
||||
ocr_answer = None
|
||||
if not ocr is None:
|
||||
if show_debug_message:
|
||||
print("away_from_keyboard_enable:", away_from_keyboard_enable)
|
||||
print("previous_answer:", previous_answer)
|
||||
print("ocr_captcha_image_source:", ocr_captcha_image_source)
|
||||
|
||||
ocr_start_time = time.time()
|
||||
|
||||
img_base64 = None
|
||||
if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_NON_BROWSER:
|
||||
if not Captcha_Browser is None:
|
||||
img_base64 = base64.b64decode(Captcha_Browser.Request_Captcha())
|
||||
if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS:
|
||||
image_id = 'span.captcha-img'
|
||||
try:
|
||||
form_verifyCode_base64 = driver.execute_async_script("""
|
||||
function svgToPng(svg, callback) {
|
||||
const url = getSvgUrl(svg);
|
||||
svgUrlToPng(url, (imgData) => {
|
||||
callback(imgData);
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
}
|
||||
function getSvgUrl(svg) {
|
||||
return URL.createObjectURL(new Blob([svg], {
|
||||
type: 'image/svg+xml'
|
||||
}));
|
||||
}
|
||||
function svgUrlToPng(svgUrl, callback) {
|
||||
const svgImage = document.createElement('img');
|
||||
document.body.appendChild(svgImage);
|
||||
svgImage.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = svgImage.clientWidth;
|
||||
canvas.height = svgImage.clientHeight;
|
||||
const canvasCtx = canvas.getContext('2d');
|
||||
canvasCtx.drawImage(svgImage, 0, 0);
|
||||
const imgData = canvas.toDataURL('image/png');
|
||||
callback(imgData);
|
||||
};
|
||||
svgImage.src = svgUrl;
|
||||
}
|
||||
const img=document.querySelector('%s');
|
||||
const svg=img.innerHTML;
|
||||
svgToPng(svg, (imgData) => {
|
||||
callback = arguments[arguments.length - 1];
|
||||
callback(imgData);
|
||||
});
|
||||
""" % (image_id))
|
||||
img_base64 = base64.b64decode(form_verifyCode_base64.split(',')[1])
|
||||
except Exception as exc:
|
||||
if show_debug_message:
|
||||
print("canvas exception:", str(exc))
|
||||
pass
|
||||
if not img_base64 is None:
|
||||
try:
|
||||
ocr_answer = ocr.classification(img_base64)
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
ocr_done_time = time.time()
|
||||
ocr_elapsed_time = ocr_done_time - ocr_start_time
|
||||
print("ocr elapsed time:", "{:.3f}".format(ocr_elapsed_time))
|
||||
else:
|
||||
print("ddddocr is None")
|
||||
|
||||
if not ocr_answer is None:
|
||||
ocr_answer = ocr_answer.strip()
|
||||
print("ocr_answer:", ocr_answer)
|
||||
if len(ocr_answer)==4:
|
||||
who_care_var, is_form_sumbited = ticketplus_keyin_captcha_code(driver, answer = ocr_answer, auto_submit = away_from_keyboard_enable)
|
||||
else:
|
||||
if not away_from_keyboard_enable:
|
||||
ticketplus_keyin_captcha_code(driver)
|
||||
#tixcraft_toast(driver, "※ OCR辨識失敗Q_Q,驗證碼請手動輸入...")
|
||||
else:
|
||||
is_need_redo_ocr = True
|
||||
if previous_answer != ocr_answer:
|
||||
previous_answer = ocr_answer
|
||||
print("refresh captcha...")
|
||||
refresh_btn = None
|
||||
try:
|
||||
my_css_selector = 'i.v-icon.mdi.mdi-refresh'
|
||||
refresh_btn = driver.find_element(By.CSS_SELECTOR, my_css_selector)
|
||||
if not refresh_btn is None:
|
||||
refresh_btn.click()
|
||||
time.sleep(0.3)
|
||||
except Exception as exc:
|
||||
print("find refresh_btn fail")
|
||||
|
||||
else:
|
||||
print("ocr_answer is None")
|
||||
print("previous_answer:", previous_answer)
|
||||
if previous_answer is None:
|
||||
ticketplus_keyin_captcha_code(driver)
|
||||
else:
|
||||
# page is not ready, retry again.
|
||||
# PS: usually occur in async script get captcha image.
|
||||
is_need_redo_ocr = True
|
||||
|
||||
return is_need_redo_ocr, previous_answer, is_form_sumbited
|
||||
|
||||
|
||||
def ticketplus_keyin_captcha_code(driver, answer = "", auto_submit = False):
|
||||
is_verifyCode_editing = False
|
||||
is_form_sumbited = False
|
||||
|
||||
# manually keyin verify code.
|
||||
# start to input verify code.
|
||||
form_verifyCode = None
|
||||
try:
|
||||
my_css_selector = 'input[placeholder="請輸入驗證碼"]'
|
||||
form_verifyCode = driver.find_element(By.CSS_SELECTOR, my_css_selector)
|
||||
except Exception as exc:
|
||||
print("find captcha input fail")
|
||||
|
||||
if form_verifyCode is not None:
|
||||
inputed_value = None
|
||||
try:
|
||||
inputed_value = form_verifyCode.get_attribute('value')
|
||||
except Exception as exc:
|
||||
print("find verify code fail")
|
||||
pass
|
||||
|
||||
if inputed_value is None:
|
||||
inputed_value = ""
|
||||
|
||||
if inputed_value == "請輸入驗證碼":
|
||||
try:
|
||||
form_verifyCode.clear()
|
||||
except Exception as exc:
|
||||
print("clear verify code fail")
|
||||
pass
|
||||
else:
|
||||
if len(inputed_value) > 0:
|
||||
print("captcha text inputed.")
|
||||
form_verifyCode = None
|
||||
is_verifyCode_editing = True
|
||||
|
||||
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()
|
||||
is_verifyCode_editing = True
|
||||
except Exception as exc:
|
||||
pass
|
||||
|
||||
#print("start to fill answer.")
|
||||
try:
|
||||
if len(answer) > 0:
|
||||
answer=answer.upper()
|
||||
form_verifyCode.clear()
|
||||
form_verifyCode.send_keys(answer)
|
||||
if auto_submit:
|
||||
form_verifyCode.send_keys(Keys.ENTER)
|
||||
is_verifyCode_editing = False
|
||||
is_form_sumbited = True
|
||||
else:
|
||||
print("select all captcha text")
|
||||
driver.execute_script("arguments[0].select();", form_verifyCode)
|
||||
if len(answer) > 0:
|
||||
#tixcraft_toast(driver, "※ 按 Enter 如果答案是: " + answer)
|
||||
pass
|
||||
except Exception as exc:
|
||||
print("send_keys ocr answer fail.")
|
||||
|
||||
return is_verifyCode_editing, is_form_sumbited
|
||||
|
||||
def ticketplus_main(driver, url, config_dict, ocr, Captcha_Browser):
|
||||
home_url_list = ['https://ticketplus.com.tw/']
|
||||
for each_url in home_url_list:
|
||||
if each_url == url.lower():
|
||||
if config_dict["ocr_captcha"]["enable"]:
|
||||
domain_name = url.split('/')[2]
|
||||
if not Captcha_Browser is None:
|
||||
Captcha_Browser.Set_cookies(driver.get_cookies())
|
||||
Captcha_Browser.Set_Domain(domain_name)
|
||||
break
|
||||
|
||||
# https://ticketplus.com.tw/activity/XXX
|
||||
if '/activity/' in url.lower():
|
||||
is_event_page = False
|
||||
if len(url.split('/'))==5:
|
||||
is_event_page = True
|
||||
|
||||
if is_event_page:
|
||||
date_auto_select_enable = config_dict["tixcraft"]["date_auto_select"]["enable"]
|
||||
if date_auto_select_enable:
|
||||
ticketplus_date_auto_select(driver, config_dict)
|
||||
|
||||
#https://ticketplus.com.tw/order/XXX/OOO
|
||||
if '/order/' in url.lower():
|
||||
is_event_page = False
|
||||
if len(url.split('/'))==6:
|
||||
is_event_page = True
|
||||
|
||||
if is_event_page:
|
||||
ticketplus_order(driver, config_dict, ocr, Captcha_Browser)
|
||||
|
||||
|
||||
def main(args):
|
||||
config_dict = get_config_dict(args)
|
||||
|
||||
|
@ -8188,7 +8671,9 @@ def main(args):
|
|||
Captcha_Browser = None
|
||||
try:
|
||||
if config_dict["ocr_captcha"]["enable"]:
|
||||
ocr = ddddocr.DdddOcr(show_ad=False, beta=True)
|
||||
ocr_beta_mode = True
|
||||
#ocr_beta_mode = False
|
||||
ocr = ddddocr.DdddOcr(show_ad=False, beta=ocr_beta_mode)
|
||||
Captcha_Browser = NonBrowser()
|
||||
|
||||
if len(config_dict["advanced"]["tixcraft_sid"]) > 1:
|
||||
|
@ -8339,6 +8824,9 @@ def main(args):
|
|||
if 'kham.com' in url:
|
||||
kham_main(driver, url, config_dict, ocr, Captcha_Browser)
|
||||
|
||||
if 'ticketplus.com' in url:
|
||||
ticketplus_main(driver, url, config_dict, ocr, Captcha_Browser)
|
||||
|
||||
if 'urbtix.hk' in url:
|
||||
urbtix_main(driver, url, config_dict)
|
||||
|
||||
|
|
|
@ -1382,6 +1382,7 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X):
|
|||
,"https://www.famiticket.com.tw (全網)"
|
||||
,"https://ticket.ibon.com.tw/"
|
||||
,"https://kham.com.tw/ (寬宏)"
|
||||
,"https://ticketplus.com.tw/ (遠大)"
|
||||
,"http://www.urbtix.hk/ (城市)"
|
||||
,"https://www.cityline.com/ (買飛)"
|
||||
,"https://premier.hkticketing.com/ (快達票)"
|
||||
|
|
Loading…
Reference in New Issue