2023-07-06, check kham remaining ticket count before click.

master
CHUN YU YAO 2023-07-15 01:39:48 +08:00
parent cf412ec6be
commit eb815d9efb
5 changed files with 168 additions and 206 deletions

View File

@ -53,7 +53,7 @@ import webbrowser
import argparse import argparse
import itertools import itertools
CONST_APP_VERSION = "MaxBot (2023.07.05)" CONST_APP_VERSION = "MaxBot (2023.07.06)"
CONST_MAXBOT_CONFIG_FILE = "settings.json" CONST_MAXBOT_CONFIG_FILE = "settings.json"
CONST_MAXBOT_LAST_URL_FILE = "MAXBOT_LAST_URL.txt" CONST_MAXBOT_LAST_URL_FILE = "MAXBOT_LAST_URL.txt"
@ -510,9 +510,8 @@ def load_chromdriver_uc(config_dict):
try: try:
driver = uc.Chrome(driver_executable_path=chromedriver_path, options=options, desired_capabilities=caps, headless=config_dict["advanced"]["headless"]) driver = uc.Chrome(driver_executable_path=chromedriver_path, options=options, desired_capabilities=caps, headless=config_dict["advanced"]["headless"])
except Exception as exc: except Exception as exc:
print(exc)
error_message = str(exc) error_message = str(exc)
if show_debug_message:
print(exc)
left_part = None left_part = None
if "Stacktrace:" in error_message: if "Stacktrace:" in error_message:
left_part = error_message.split("Stacktrace:")[0] left_part = error_message.split("Stacktrace:")[0]
@ -528,9 +527,8 @@ def load_chromdriver_uc(config_dict):
try: try:
driver = uc.Chrome(options=options, desired_capabilities=caps, headless=config_dict["advanced"]["headless"]) driver = uc.Chrome(options=options, desired_capabilities=caps, headless=config_dict["advanced"]["headless"])
except Exception as exc: except Exception as exc:
print(exc)
error_message = str(exc) error_message = str(exc)
if show_debug_message:
print(exc)
left_part = None left_part = None
if "Stacktrace:" in error_message: if "Stacktrace:" in error_message:
left_part = error_message.split("Stacktrace:")[0] left_part = error_message.split("Stacktrace:")[0]
@ -576,21 +574,17 @@ def get_driver_by_config(config_dict):
driver_type = config_dict["webdriver_type"] driver_type = config_dict["webdriver_type"]
# output config: # output config:
print("maxbot app version", CONST_APP_VERSION) print("maxbot app version:", CONST_APP_VERSION)
print("python version", platform.python_version()) print("python version:", platform.python_version())
print("platform", platform.platform()) print("platform:", platform.platform())
print("homepage", homepage) print("homepage:", homepage)
print("browser", browser) print("browser:", browser)
print("ticket_number", str(config_dict["ticket_number"])) print("ticket_number:", str(config_dict["ticket_number"]))
print("pass_1_seat_remaining", config_dict["pass_1_seat_remaining"])
print("==[kktix]==")
print(config_dict["kktix"])
print("==[tixcraft]==")
print(config_dict["tixcraft"]) print(config_dict["tixcraft"])
print("==[advanced]==") print("==[advanced config]==")
print(config_dict["advanced"]) print(config_dict["advanced"])
print("webdriver_type", driver_type) print("webdriver_type:", driver_type)
# entry point # entry point
if homepage is None: if homepage is None:
@ -1576,9 +1570,6 @@ def tixcraft_date_auto_select(driver, url, config_dict, domain_name):
row_index += 1 row_index += 1
row_is_enabled=True row_is_enabled=True
try: try:
if not row.is_enabled():
row_is_enabled=False
row_text = "" row_text = ""
# check buy button. # check buy button.
if row_is_enabled: if row_is_enabled:
@ -1587,7 +1578,8 @@ def tixcraft_date_auto_select(driver, url, config_dict, domain_name):
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
row_is_enabled=False row_is_enabled=False
if len(row_text) > 0: if len(row_text) > 0:
@ -1691,6 +1683,11 @@ def tixcraft_date_auto_select(driver, url, config_dict, domain_name):
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
# only need first row.
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
if not matched_blocks is None: if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -1888,6 +1885,9 @@ def ticketmaster_date_auto_select(driver, url, config_dict, domain_name):
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
if not matched_blocks is None: if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -1944,6 +1944,8 @@ def ticketmaster_date_auto_select(driver, url, config_dict, domain_name):
return is_date_clicked return is_date_clicked
def reset_row_text_if_match_keyword_exclude(config_dict, row_text): def reset_row_text_if_match_keyword_exclude(config_dict, row_text):
reset_flag = False
# clean stop word. # clean stop word.
row_text = format_keyword_string(row_text) row_text = format_keyword_string(row_text)
@ -1965,11 +1967,15 @@ def reset_row_text_if_match_keyword_exclude(config_dict, row_text):
is_match_all_exclude = False is_match_all_exclude = False
if is_match_all_exclude: if is_match_all_exclude:
row_text = "" row_text = ""
reset_flag = True
break
else: else:
exclude_item = format_keyword_string(exclude_item_list) exclude_item = format_keyword_string(exclude_item_list)
if exclude_item in row_text: if exclude_item in row_text:
row_text = "" row_text = ""
return row_text reset_flag = True
break
return reset_flag
# PURPOSE: get target area list. # PURPOSE: get target area list.
# RETURN: # RETURN:
@ -1985,7 +1991,6 @@ def get_tixcraft_target_area(el, config_dict, area_keyword_item):
# read config. # read config.
area_auto_select_mode = config_dict["area_auto_select"]["mode"] area_auto_select_mode = config_dict["area_auto_select"]["mode"]
pass_1_seat_remaining_enable = config_dict["pass_1_seat_remaining"]
is_need_refresh = False is_need_refresh = False
matched_blocks = None matched_blocks = None
@ -2029,7 +2034,8 @@ def get_tixcraft_target_area(el, config_dict, area_keyword_item):
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
# clean stop word. # clean stop word.
@ -2051,9 +2057,7 @@ def get_tixcraft_target_area(el, config_dict, area_keyword_item):
is_append_this_row = True is_append_this_row = True
if is_append_this_row: if is_append_this_row:
if show_debug_message: if config_dict["ticket_number"] > 1:
print("pass_1_seat_remaining_enable:", pass_1_seat_remaining_enable)
if pass_1_seat_remaining_enable:
area_item_font_el = None area_item_font_el = None
try: try:
#print('try to find font tag at row:', row_text) #print('try to find font tag at row:', row_text)
@ -2105,7 +2109,6 @@ def get_ticketmaster_target_area(config_dict, area_keyword_item, zone_info):
# read config. # read config.
area_auto_select_mode = config_dict["area_auto_select"]["mode"] area_auto_select_mode = config_dict["area_auto_select"]["mode"]
pass_1_seat_remaining_enable = config_dict["pass_1_seat_remaining"]
is_need_refresh = False is_need_refresh = False
matched_blocks = None matched_blocks = None
@ -2142,7 +2145,8 @@ def get_ticketmaster_target_area(config_dict, area_keyword_item, zone_info):
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
# clean stop word. # clean stop word.
@ -2196,11 +2200,7 @@ def tixcraft_area_auto_select(driver, url, config_dict):
area_keyword = config_dict["area_auto_select"]["area_keyword"].strip() area_keyword = config_dict["area_auto_select"]["area_keyword"].strip()
area_auto_select_mode = config_dict["area_auto_select"]["mode"] area_auto_select_mode = config_dict["area_auto_select"]["mode"]
pass_1_seat_remaining_enable = config_dict["pass_1_seat_remaining"]
# disable pass 1 seat remaining when target ticket number is 1.
ticket_number = config_dict["ticket_number"] ticket_number = config_dict["ticket_number"]
if ticket_number == 1:
pass_1_seat_remaining_enable = False
if show_debug_message: if show_debug_message:
print("area_keyword:", area_keyword) print("area_keyword:", area_keyword)
@ -2949,7 +2949,8 @@ def get_tixcraft_ticket_select_by_keyword(driver, config_dict, area_keyword_item
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
# clean stop word. # clean stop word.
@ -3286,11 +3287,7 @@ def kktix_travel_price_list(driver, config_dict, kktix_area_keyword):
if config_dict["advanced"]["verbose"]: if config_dict["advanced"]["verbose"]:
show_debug_message = True show_debug_message = True
pass_1_seat_remaining_enable = config_dict["pass_1_seat_remaining"]
# disable pass 1 seat remaining when target ticket number is 1.
ticket_number = config_dict["ticket_number"] ticket_number = config_dict["ticket_number"]
if ticket_number == 1:
pass_1_seat_remaining_enable = False
areas = None areas = None
is_ticket_number_assigned = False is_ticket_number_assigned = False
@ -3358,7 +3355,8 @@ def kktix_travel_price_list(driver, config_dict, kktix_area_keyword):
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
# clean stop word. # clean stop word.
@ -3401,9 +3399,9 @@ def kktix_travel_price_list(driver, config_dict, kktix_area_keyword):
pass pass
if is_danger_notice: if is_danger_notice:
# skip this row, because assign will fail, or fill ticket number as 1. # PS: not ALL danger notice are "only 1 seat remaining"...
if pass_1_seat_remaining_enable: # TODO: check real remaining value instead of check css style.
continue continue
if is_visible: if is_visible:
is_match_area = False is_match_area = False
@ -3465,11 +3463,7 @@ def kktix_assign_ticket_number(driver, config_dict, kktix_area_keyword):
show_debug_message = True show_debug_message = True
ticket_number_str = str(config_dict["ticket_number"]) ticket_number_str = str(config_dict["ticket_number"])
pass_1_seat_remaining_enable = config_dict["pass_1_seat_remaining"]
# disable pass 1 seat remaining when target ticket number is 1.
ticket_number = config_dict["ticket_number"] ticket_number = config_dict["ticket_number"]
if ticket_number == 1:
pass_1_seat_remaining_enable = False
kktix_area_auto_select_mode = config_dict["area_auto_select"]["mode"] kktix_area_auto_select_mode = config_dict["area_auto_select"]["mode"]
is_ticket_number_assigned, areas = kktix_travel_price_list(driver, config_dict, kktix_area_keyword) is_ticket_number_assigned, areas = kktix_travel_price_list(driver, config_dict, kktix_area_keyword)
@ -4440,7 +4434,8 @@ def get_fami_target_area(driver, config_dict, area_keyword_item):
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
# check date. # check date.
@ -4799,6 +4794,11 @@ def urbtix_date_auto_select(driver, auto_select_mode, date_keyword, auto_reload_
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
print("only need first item, break area list loop.")
break
if show_debug_message: if show_debug_message:
if not matched_blocks is None: if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -4934,7 +4934,8 @@ def urbtix_area_auto_select(driver, config_dict, area_keyword_item):
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if row_text == "": if row_text == "":
row_is_enabled=False row_is_enabled=False
@ -5022,6 +5023,10 @@ def urbtix_area_auto_select(driver, config_dict, area_keyword_item):
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -5393,6 +5398,9 @@ def cityline_date_auto_select(driver, auto_select_mode, date_keyword, auto_reloa
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
if not matched_blocks is None: if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -5539,7 +5547,8 @@ def cityline_area_auto_select(driver, config_dict, area_keyword_item):
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = format_keyword_string(row_text) row_text = format_keyword_string(row_text)
@ -5564,6 +5573,9 @@ def cityline_area_auto_select(driver, config_dict, area_keyword_item):
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -5946,7 +5958,8 @@ def ibon_date_auto_select(driver, config_dict):
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = format_keyword_string(row_text) row_text = format_keyword_string(row_text)
@ -5977,6 +5990,9 @@ def ibon_date_auto_select(driver, config_dict):
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
if not matched_blocks is None: if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -6116,7 +6132,8 @@ def ibon_area_auto_select(driver, config_dict, area_keyword_item):
row_text="" row_text=""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
# check ticket count when amount is few, because of it spent a lot of time at parsing element. # check ticket count when amount is few, because of it spent a lot of time at parsing element.
if len(row_text) > 0: if len(row_text) > 0:
@ -6230,6 +6247,10 @@ def ibon_area_auto_select(driver, config_dict, area_keyword_item):
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -8418,6 +8439,9 @@ def hkticketing_date_assign(driver, config_dict):
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
if not matched_blocks is None: if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -8687,7 +8711,8 @@ def hkticketing_area_auto_select(driver, config_dict, area_keyword_item):
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = format_keyword_string(row_text) row_text = format_keyword_string(row_text)
@ -8713,6 +8738,9 @@ def hkticketing_area_auto_select(driver, config_dict, area_keyword_item):
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -9283,7 +9311,8 @@ def hkam_date_auto_select(driver, domain_name, config_dict):
row_text="" row_text=""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if '立即訂購' in row_text: if '立即訂購' in row_text:
try: try:
@ -9365,6 +9394,9 @@ def hkam_date_auto_select(driver, domain_name, config_dict):
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
if not matched_blocks is None: if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -9464,7 +9496,7 @@ def kham_area_auto_select(driver, domain_name, config_dict, area_keyword_item):
area_list = None area_list = None
try: try:
# for kham.com # for kham.com
my_css_selector = "table#salesTable > tbody > tr.status_tr" my_css_selector = "table#salesTable > tbody > tr[class='status_tr']"
if "ticket.com.tw" in domain_name: if "ticket.com.tw" in domain_name:
my_css_selector = "li.main" my_css_selector = "li.main"
print("my_css_selector:",my_css_selector) print("my_css_selector:",my_css_selector)
@ -9497,44 +9529,7 @@ def kham_area_auto_select(driver, domain_name, config_dict, area_keyword_item):
row_index = 0 row_index = 0
for row in area_list: for row in area_list:
row_index += 1 row_index += 1
formated_area_list.append(row)
row_is_enabled=True
row_text = ""
try:
row_text = row.text
except Exception as exc:
pass
if row_text is None:
row_text = ""
if '售完' in row_text:
row_text = ""
if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text)
if len(row_text) == 0:
row_is_enabled = False
if row_is_enabled:
pass
# too many rows, too slow, disable to check.
'''
try:
is_row_with_id = False
tr_id_string = str(row.get_attribute('id'))
if len(tr_id_string) > 1:
is_row_with_id = True
if is_row_with_id:
row_is_enabled=True
except Exception as exc:
pass
'''
if row_is_enabled:
formated_area_list.append(row)
else: else:
if show_debug_message: if show_debug_message:
print("area_list_count is empty.") print("area_list_count is empty.")
@ -9551,47 +9546,77 @@ def kham_area_auto_select(driver, domain_name, config_dict, area_keyword_item):
if area_list_count > 0: if area_list_count > 0:
matched_blocks = [] matched_blocks = []
if len(area_keyword_item) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
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_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 '售完' in row_text:
row_text = ""
if len(row_text) > 0:
if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = "" row_text = ""
if len(row_text) > 0: # check ticket_number and available count.
row_text = format_keyword_string(row_text) if len(row_text) > 0:
if show_debug_message: if config_dict["ticket_number"] > 1:
print("row_text:", row_text) maybe_ticket_count = row_text[-1:]
if maybe_ticket_count.isdigit():
ticket_count_element = None
try:
my_css_selector = "td:nth-child(4)"
ticket_count_element = row.find_element(By.CSS_SELECTOR, my_css_selector)
if not ticket_count_element is None:
ticket_count_text = ticket_count_element.text
if ticket_count_text.isdigit():
if int(ticket_count_text) < config_dict["ticket_number"]:
if show_debug_message:
print("skip this row, because ticket_count available only:", ticket_count_text)
# skip this row.
row_text = ""
except Exception as exc:
if show_debug_message:
print(exc)
is_match_area = False
if len(area_keyword_item) > 0: if len(row_text) > 0:
# must match keyword. row_text = format_keyword_string(row_text)
is_match_area = True if show_debug_message:
area_keyword_array = area_keyword_item.split(' ') print("row_text:", row_text)
for area_keyword in area_keyword_array:
area_keyword = format_keyword_string(area_keyword) # default add row.
if not area_keyword in row_text: is_match_area = True
is_match_area = False if len(area_keyword_item) == 0:
break # without keyword.
else: pass
# without keyword. else:
is_match_area = True # match keyword.
area_keyword_array = area_keyword_item.split(' ')
for area_keyword in area_keyword_array:
area_keyword = format_keyword_string(area_keyword)
if not area_keyword in row_text:
is_match_area = False
break
if is_match_area:
matched_blocks.append(row)
# only need first row.
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if is_match_area:
matched_blocks.append(row)
if show_debug_message: if show_debug_message:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -10207,7 +10232,7 @@ def ticketplus_date_auto_select(driver, config_dict):
try: try:
area_list = driver.find_elements(By.CSS_SELECTOR, 'div#buyTicket > div.sesstion-item') area_list = driver.find_elements(By.CSS_SELECTOR, 'div#buyTicket > div.sesstion-item')
except Exception as exc: except Exception as exc:
print("find #gameList fail") print("find #buyTicket fail")
find_ticket_text_list = ['立即購票'] find_ticket_text_list = ['立即購票']
sold_out_text_list = ['銷售一空','尚未開賣'] sold_out_text_list = ['銷售一空','尚未開賣']
@ -10238,7 +10263,8 @@ def ticketplus_date_auto_select(driver, config_dict):
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
row_is_enabled=False row_is_enabled=False
if len(row_text) > 0: if len(row_text) > 0:
@ -10325,6 +10351,9 @@ def ticketplus_date_auto_select(driver, config_dict):
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
if not matched_blocks is None: if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -10516,7 +10545,8 @@ def ticketplus_order_expansion_auto_select(driver, config_dict, area_keyword_ite
row_text = "" row_text = ""
if len(row_text) > 0: if len(row_text) > 0:
row_text = reset_row_text_if_match_keyword_exclude(config_dict, row_text) if reset_row_text_if_match_keyword_exclude(config_dict, row_text):
row_text = ""
if row_text == "": if row_text == "":
row_is_enabled=False row_is_enabled=False
@ -10581,6 +10611,9 @@ def ticketplus_order_expansion_auto_select(driver, config_dict, area_keyword_ite
if is_match_area: if is_match_area:
matched_blocks.append(row) matched_blocks.append(row)
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
break
if show_debug_message: if show_debug_message:
print("after match keyword, found count:", len(matched_blocks)) print("after match keyword, found count:", len(matched_blocks))
@ -11250,12 +11283,7 @@ def main(args):
driver = None driver = None
if not config_dict is None: if not config_dict is None:
for i in range(3): driver = get_driver_by_config(config_dict)
driver = get_driver_by_config(config_dict)
if not driver is None:
break
else:
time.sleep(0.05)
else: else:
print("Load config error!") print("Load config error!")
@ -11485,13 +11513,3 @@ if __name__ == "__main__":
image_bytes = f.read() image_bytes = f.read()
res = ocr.classification(image_bytes) res = ocr.classification(image_bytes)
print(res) print(res)
# for urbtix survey.
# PS: urttix use "open-end" qustion, must use external database to answer...
question_text = "「6- -V- -U - n--s- -z - j」由右起第三個數字/字母是甚麼?"
question_text = "「6---2 - 3 _ 8- -8 _ 4 - 1--4 _ 7」中有多少個「二」?"
question_answer_char, question_direction = get_urbtix_survey_answer_by_question(question_text)
#print("question_text:", question_text)
#print("question_answer_char:", question_answer_char)
#print("question_text:", question_direction)

View File

@ -22,7 +22,7 @@ import base64
import threading import threading
import subprocess import subprocess
CONST_APP_VERSION = "MaxBot (2023.07.05)" CONST_APP_VERSION = "MaxBot (2023.07.06)"
CONST_MAXBOT_LAUNCHER_FILE = "config_launcher.json" CONST_MAXBOT_LAUNCHER_FILE = "config_launcher.json"
CONST_MAXBOT_CONFIG_FILE = "settings.json" CONST_MAXBOT_CONFIG_FILE = "settings.json"

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, "beta": true, "force_submit": true, "image_source": "canvas"}, "webdriver_type": "undetected_chromedriver", "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true}, "tixcraft": {"date_auto_select": {"enable": true, "date_keyword": "", "mode": "from top to bottom"}, "pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true}, "area_auto_select": {"enable": true, "mode": "from top to bottom", "area_keyword": "", "area_keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\""}, "advanced": {"play_captcha_sound": {"enable": true, "filename": "ding-dong.wav"}, "tixcraft_sid": "", "ibonqware": "", "facebook_account": "", "kktix_account": "", "cityline_account": "", "urbtix_account": "", "hkticketing_account": "", "kham_account": "", "ticketplus_account": "", "facebook_password": "", "kktix_password": "", "cityline_password": "", "urbtix_password": "", "hkticketing_password": "", "kham_password": "", "ticketplus_password": "", "adblock_plus_enable": false, "disable_adjacent_seat": false, "headless": false, "verbose": false, "auto_guess_options": true, "user_guess_string": "", "online_dictionary_url": "", "auto_reload_page_interval": 1.0, "auto_reload_random_delay": false}} {"homepage": "https://tixcraft.com", "browser": "chrome", "language": "\u7e41\u9ad4\u4e2d\u6587", "ticket_number": 2, "auto_check_agree": true, "ocr_captcha": {"enable": true, "beta": true, "force_submit": true, "image_source": "canvas"}, "webdriver_type": "undetected_chromedriver", "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true}, "tixcraft": {"date_auto_select": {"enable": true, "date_keyword": "", "mode": "from top to bottom"}, "pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true}, "area_auto_select": {"enable": true, "mode": "from top to bottom", "area_keyword": "", "area_keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\""}, "advanced": {"play_captcha_sound": {"enable": true, "filename": "ding-dong.wav"}, "tixcraft_sid": "", "ibonqware": "", "facebook_account": "", "kktix_account": "", "cityline_account": "", "urbtix_account": "", "hkticketing_account": "", "kham_account": "", "ticketplus_account": "", "facebook_password": "", "kktix_password": "", "cityline_password": "", "urbtix_password": "", "hkticketing_password": "", "kham_password": "", "ticketplus_password": "", "adblock_plus_enable": false, "disable_adjacent_seat": false, "headless": false, "verbose": false, "auto_guess_options": true, "user_guess_string": "", "online_dictionary_url": "", "auto_reload_page_interval": 1.0, "auto_reload_random_delay": false}}

View File

@ -32,7 +32,7 @@ warnings.simplefilter('ignore',InsecureRequestWarning)
import ssl import ssl
ssl._create_default_https_context = ssl._create_unverified_context ssl._create_default_https_context = ssl._create_unverified_context
CONST_APP_VERSION = "MaxBot (2023.07.05)" CONST_APP_VERSION = "MaxBot (2023.07.06)"
CONST_MAXBOT_CONFIG_FILE = "settings.json" CONST_MAXBOT_CONFIG_FILE = "settings.json"
CONST_MAXBOT_LAST_URL_FILE = "MAXBOT_LAST_URL.txt" CONST_MAXBOT_LAST_URL_FILE = "MAXBOT_LAST_URL.txt"
@ -133,7 +133,6 @@ def load_translate():
en_us["area_keyword_exclude"] = 'Date/Area Keyword Exclude' en_us["area_keyword_exclude"] = 'Date/Area Keyword Exclude'
en_us["area_keyword_usage"] = 'Each keyword need double quotes, separated by comma,\nUse space in keyword as AND logic.\nAppend ,\"\" to match all.' en_us["area_keyword_usage"] = 'Each keyword need double quotes, separated by comma,\nUse space in keyword as AND logic.\nAppend ,\"\" to match all.'
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_ddddocr_beta"] = 'ddddocr beta' en_us["ocr_captcha_ddddocr_beta"] = 'ddddocr beta'
en_us["ocr_captcha_force_submit"] = 'Away from keyboard' en_us["ocr_captcha_force_submit"] = 'Away from keyboard'
@ -230,7 +229,6 @@ def load_translate():
zh_tw["area_keyword_exclude"] = '排除日期/區域關鍵字' zh_tw["area_keyword_exclude"] = '排除日期/區域關鍵字'
zh_tw["area_keyword_usage"] = '每組關鍵字需要雙引號, 用逗號分隔, \n在關鍵字中使用空格作為 AND 邏輯。.\n加入 ,\"\" 代表符合所有關鍵字' zh_tw["area_keyword_usage"] = '每組關鍵字需要雙引號, 用逗號分隔, \n在關鍵字中使用空格作為 AND 邏輯。.\n加入 ,\"\" 代表符合所有關鍵字'
zh_tw["pass_1_seat_remaining"] = '避開「剩餘 1」的區域'
zh_tw["ocr_captcha"] = '猜測驗證碼' zh_tw["ocr_captcha"] = '猜測驗證碼'
zh_tw["ocr_captcha_ddddocr_beta"] = 'ddddocr beta' zh_tw["ocr_captcha_ddddocr_beta"] = 'ddddocr beta'
zh_tw["ocr_captcha_force_submit"] = '掛機模式' zh_tw["ocr_captcha_force_submit"] = '掛機模式'
@ -326,7 +324,6 @@ def load_translate():
zh_cn["area_keyword_exclude"] = '排除日期/区域关键字' zh_cn["area_keyword_exclude"] = '排除日期/区域关键字'
zh_cn["area_keyword_usage"] = '每組關鍵字需要雙引號, 用逗號分隔, \n在關鍵字中使用空格作為 AND 邏輯。\n附加 ,\"\" 以匹配所有結果。' zh_cn["area_keyword_usage"] = '每組關鍵字需要雙引號, 用逗號分隔, \n在關鍵字中使用空格作為 AND 邏輯。\n附加 ,\"\" 以匹配所有結果。'
zh_cn["pass_1_seat_remaining"] = '避开“剩余 1”的区域'
zh_cn["ocr_captcha"] = '猜测验证码' zh_cn["ocr_captcha"] = '猜测验证码'
zh_cn["ocr_captcha_ddddocr_beta"] = 'ddddocr beta' zh_cn["ocr_captcha_ddddocr_beta"] = 'ddddocr beta'
zh_cn["ocr_captcha_force_submit"] = '挂机模式' zh_cn["ocr_captcha_force_submit"] = '挂机模式'
@ -423,7 +420,6 @@ def load_translate():
ja_jp["area_keyword_exclude"] = '除外日付/エリア キーワード' ja_jp["area_keyword_exclude"] = '除外日付/エリア キーワード'
ja_jp["area_keyword_usage"] = '各キーワードはカンマで区切られた二重引用符が必要です。\nキーワード内のスペースを AND ロジックとして使用します。\nすべてに一致するように ,\"\" を追加します。' ja_jp["area_keyword_usage"] = '各キーワードはカンマで区切られた二重引用符が必要です。\nキーワード内のスペースを AND ロジックとして使用します。\nすべてに一致するように ,\"\" を追加します。'
ja_jp["pass_1_seat_remaining"] = '「1 席残り」エリアは避ける'
ja_jp["ocr_captcha"] = 'キャプチャを推測する' ja_jp["ocr_captcha"] = 'キャプチャを推測する'
ja_jp["ocr_captcha_ddddocr_beta"] = 'ddddocr beta' ja_jp["ocr_captcha_ddddocr_beta"] = 'ddddocr beta'
ja_jp["ocr_captcha_force_submit"] = 'キーボードから離れて' ja_jp["ocr_captcha_force_submit"] = 'キーボードから離れて'
@ -568,7 +564,6 @@ def get_default_config():
config_dict["browser"] = "chrome" config_dict["browser"] = "chrome"
config_dict["language"] = "English" config_dict["language"] = "English"
config_dict["ticket_number"] = 2 config_dict["ticket_number"] = 2
config_dict["pass_1_seat_remaining"] = True
config_dict["auto_check_agree"] = True config_dict["auto_check_agree"] = True
config_dict["ocr_captcha"] = {} config_dict["ocr_captcha"] = {}
config_dict["ocr_captcha"]["enable"] = True config_dict["ocr_captcha"]["enable"] = True
@ -707,7 +702,6 @@ def btn_save_act(language_code, slience_mode=False):
global combo_browser global combo_browser
global combo_language global combo_language
global combo_ticket_number global combo_ticket_number
global chk_state_pass_1_seat_remaining
global chk_state_auto_check_agree global chk_state_auto_check_agree
global chk_state_auto_press_next_step_button global chk_state_auto_press_next_step_button
@ -796,7 +790,6 @@ def btn_save_act(language_code, slience_mode=False):
config_dict["ticket_number"] = int(combo_ticket_number.get().strip()) config_dict["ticket_number"] = int(combo_ticket_number.get().strip())
if is_all_data_correct: if is_all_data_correct:
config_dict["pass_1_seat_remaining"] = bool(chk_state_pass_1_seat_remaining.get())
config_dict["auto_check_agree"] = bool(chk_state_auto_check_agree.get()) config_dict["auto_check_agree"] = bool(chk_state_auto_check_agree.get())
config_dict["kktix"]["auto_press_next_step_button"] = bool(chk_state_auto_press_next_step_button.get()) config_dict["kktix"]["auto_press_next_step_button"] = bool(chk_state_auto_press_next_step_button.get())
@ -1120,9 +1113,6 @@ def btn_help_clicked():
def btn_copy_clicked(): def btn_copy_clicked():
pyperclip.copy(CONST_ADBLOCK_PLUS_ADVANCED_FILTER_DEFAULT) pyperclip.copy(CONST_ADBLOCK_PLUS_ADVANCED_FILTER_DEFAULT)
def callbackTicketNumberOnChange(event):
showHidePass1SeatRemaining()
def callbackLanguageOnChange(event): def callbackLanguageOnChange(event):
applyNewLanguage() applyNewLanguage()
@ -1149,7 +1139,6 @@ def applyNewLanguage():
global lbl_browser global lbl_browser
global lbl_language global lbl_language
global lbl_ticket_number global lbl_ticket_number
global lbl_pass_1_seat_remaining
global lbl_auto_check_agree global lbl_auto_check_agree
# for kktix # for kktix
@ -1183,7 +1172,6 @@ def applyNewLanguage():
global lbl_maxbot_last_url global lbl_maxbot_last_url
# for checkbox # for checkbox
global chk_pass_1_seat_remaining
global chk_auto_check_agree global chk_auto_check_agree
global chk_auto_press_next_step_button global chk_auto_press_next_step_button
@ -1222,7 +1210,6 @@ def applyNewLanguage():
lbl_browser.config(text=translate[language_code]["browser"]) lbl_browser.config(text=translate[language_code]["browser"])
lbl_language.config(text=translate[language_code]["language"]) lbl_language.config(text=translate[language_code]["language"])
lbl_ticket_number.config(text=translate[language_code]["ticket_number"]) lbl_ticket_number.config(text=translate[language_code]["ticket_number"])
lbl_pass_1_seat_remaining.config(text=translate[language_code]["pass_1_seat_remaining"])
lbl_auto_check_agree.config(text=translate[language_code]["auto_check_agree"]) lbl_auto_check_agree.config(text=translate[language_code]["auto_check_agree"])
lbl_auto_press_next_step_button.config(text=translate[language_code]["auto_press_next_step_button"]) lbl_auto_press_next_step_button.config(text=translate[language_code]["auto_press_next_step_button"])
@ -1259,7 +1246,6 @@ def applyNewLanguage():
lbl_maxbot_status.config(text=translate[language_code]["running_status"]) lbl_maxbot_status.config(text=translate[language_code]["running_status"])
lbl_maxbot_last_url.config(text=translate[language_code]["running_url"]) lbl_maxbot_last_url.config(text=translate[language_code]["running_url"])
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"])
chk_auto_press_next_step_button.config(text=translate[language_code]["enable"]) chk_auto_press_next_step_button.config(text=translate[language_code]["enable"])
chk_auto_fill_ticket_number.config(text=translate[language_code]["enable"]) chk_auto_fill_ticket_number.config(text=translate[language_code]["enable"])
@ -1398,7 +1384,6 @@ def showHideBlocks():
frame_group_kktix.grid_forget() frame_group_kktix.grid_forget()
showHideTixcraftBlocks() showHideTixcraftBlocks()
showHidePass1SeatRemaining()
def showHideOcrCaptchaWithSubmit(): def showHideOcrCaptchaWithSubmit():
global chk_state_ocr_captcha global chk_state_ocr_captcha
@ -1426,23 +1411,6 @@ def showHideOcrCaptchaWithSubmit():
lbl_ocr_captcha_ddddocr_beta.grid_forget() lbl_ocr_captcha_ddddocr_beta.grid_forget()
chk_ocr_captcha_ddddocr_beta.grid_forget() chk_ocr_captcha_ddddocr_beta.grid_forget()
def showHidePass1SeatRemaining():
global combo_ticket_number
ticket_number_int = int(combo_ticket_number.get().strip())
global pass_1_seat_remaining_index
global lbl_pass_1_seat_remaining
global chk_pass_1_seat_remaining
if ticket_number_int > 1:
# show.
lbl_pass_1_seat_remaining.grid(column=0, row=pass_1_seat_remaining_index, sticky = E)
chk_pass_1_seat_remaining.grid(column=1, row=pass_1_seat_remaining_index, sticky = W)
else:
# hide
lbl_pass_1_seat_remaining.grid_forget()
chk_pass_1_seat_remaining.grid_forget()
# purpose: show detail blocks if master field is enable. # purpose: show detail blocks if master field is enable.
def showHideTixcraftBlocks(): def showHideTixcraftBlocks():
# for tixcraft show/hide enable. # for tixcraft show/hide enable.
@ -1573,28 +1541,10 @@ def PreferenctTab(root, config_dict, language_code, UI_PADDING_X):
combo_ticket_number['values']= ("1","2","3","4","5","6","7","8","9","10","11","12") combo_ticket_number['values']= ("1","2","3","4","5","6","7","8","9","10","11","12")
#combo_ticket_number.current(0) #combo_ticket_number.current(0)
combo_ticket_number.set(str(config_dict["ticket_number"])) combo_ticket_number.set(str(config_dict["ticket_number"]))
combo_ticket_number.bind("<<ComboboxSelected>>", callbackTicketNumberOnChange)
combo_ticket_number.grid(column=1, row=group_row_count, sticky = W) combo_ticket_number.grid(column=1, row=group_row_count, sticky = W)
group_row_count+=1 group_row_count+=1
global pass_1_seat_remaining_index
pass_1_seat_remaining_index = group_row_count
global lbl_pass_1_seat_remaining
lbl_pass_1_seat_remaining = Label(frame_group_header, text=translate[language_code]['pass_1_seat_remaining'])
lbl_pass_1_seat_remaining.grid(column=0, row=group_row_count, sticky = E)
global chk_state_pass_1_seat_remaining
chk_state_pass_1_seat_remaining = BooleanVar()
chk_state_pass_1_seat_remaining.set(config_dict["pass_1_seat_remaining"])
global chk_pass_1_seat_remaining
chk_pass_1_seat_remaining = Checkbutton(frame_group_header, text=translate[language_code]['enable'], variable=chk_state_pass_1_seat_remaining)
chk_pass_1_seat_remaining.grid(column=1, row=group_row_count, sticky = W)
group_row_count+=1
global lbl_auto_check_agree global lbl_auto_check_agree
lbl_auto_check_agree = Label(frame_group_header, text=translate[language_code]['auto_check_agree']) lbl_auto_check_agree = Label(frame_group_header, text=translate[language_code]['auto_check_agree'])
lbl_auto_check_agree.grid(column=0, row=group_row_count, sticky = E) lbl_auto_check_agree.grid(column=0, row=group_row_count, sticky = E)
@ -1810,12 +1760,6 @@ def AdvancedTab(root, config_dict, language_code, UI_PADDING_X):
frame_group_header = Frame(root) frame_group_header = Frame(root)
group_row_count = 0 group_row_count = 0
# for advanced
print("==[advanced]==")
print("browser", config_dict['browser'])
print("language", config_dict['language'])
print(config_dict["advanced"])
# assign default value. # assign default value.
captcha_sound_filename = config_dict["advanced"]["play_captcha_sound"]["filename"].strip() captcha_sound_filename = config_dict["advanced"]["play_captcha_sound"]["filename"].strip()
if captcha_sound_filename is None: if captcha_sound_filename is None:

View File

@ -28,7 +28,7 @@ import asyncio
import tornado import tornado
from tornado.web import Application from tornado.web import Application
CONST_APP_VERSION = "MaxBot (2023.07.05)" CONST_APP_VERSION = "MaxBot (2023.07.06)"
CONST_MAXBOT_QUESTION_FILE = "MAXBOT_QUESTION.txt" CONST_MAXBOT_QUESTION_FILE = "MAXBOT_QUESTION.txt"