diff --git a/chrome_tixcraft.py b/chrome_tixcraft.py index 91fe2c3..f4a3e98 100644 --- a/chrome_tixcraft.py +++ b/chrome_tixcraft.py @@ -9,18 +9,16 @@ import base64 import json import logging import os -import pathlib import platform import random -import re import ssl +import subprocess import sys +import threading import time import warnings import webbrowser from datetime import datetime -import subprocess -import threading import chromedriver_autoinstaller_max import requests @@ -37,6 +35,7 @@ from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import Select, WebDriverWait from urllib3.exceptions import InsecureRequestWarning +import util from NonBrowser import NonBrowser try: @@ -45,7 +44,7 @@ except Exception as exc: print(exc) pass -CONST_APP_VERSION = "MaxBot (2024.03.19)" +CONST_APP_VERSION = "MaxBot (2024.03.20)" CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" CONST_MAXBOT_CONFIG_FILE = "settings.json" @@ -104,7 +103,6 @@ CONST_FROM_TOP_TO_BOTTOM = "from top to bottom" CONST_FROM_BOTTOM_TO_TOP = "from bottom to top" CONST_CENTER = "center" CONST_RANDOM = "random" -CONST_SELECT_ORDER_DEFAULT = CONST_FROM_TOP_TO_BOTTOM CONT_STRING_1_SEATS_REMAINING = ['@1 seat(s) remaining','剩餘 1@','@1 席残り'] @@ -123,62 +121,8 @@ ssl._create_default_https_context = ssl._create_unverified_context logging.basicConfig() logger = logging.getLogger('logger') -def t_or_f(arg): - ret = False - ua = str(arg).upper() - if 'TRUE'.startswith(ua): - ret = True - elif 'YES'.startswith(ua): - ret = True - return ret - -def format_config_keyword_for_json(user_input): - if len(user_input) > 0: - if not ('\"' in user_input): - user_input = '"' + user_input + '"' - if user_input[:1]=="{" and user_input[-1:]=="}": - user_input=user_input[1:] - user_input=user_input[:-1] - if user_input[:1]=="[" and user_input[-1:]=="]": - user_input=user_input[1:] - user_input=user_input[:-1] - return user_input - -def remove_html_tags(text): - ret = "" - if not text is None: - clean = re.compile('<.*?>') - ret = re.sub(clean, '', text) - ret = ret.strip() - return ret - -def sx(s1): - key=18 - return ''.join(chr(ord(a) ^ key) for a in s1) - -def decryptMe(b): - s="" - if(len(b)>0): - s=sx(base64.b64decode(b).decode("UTF-8")) - return s - -def encryptMe(s): - data="" - if(len(s)>0): - data=base64.b64encode(sx(s).encode('UTF-8')).decode("UTF-8") - return data - -def get_app_root(): - app_root = "" - if hasattr(sys, 'frozen'): - basis = sys.executable - app_root = os.path.dirname(basis) - else: - app_root = os.getcwd() - return app_root - def get_config_dict(args): - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_CONFIG_FILE) # allow assign config by command line. @@ -193,7 +137,7 @@ def get_config_dict(args): config_dict = json.load(json_data) if not args.headless is None: - config_dict["advanced"]["headless"] = t_or_f(args.headless) + config_dict["advanced"]["headless"] = util.t_or_f(args.headless) if not args.homepage is None: if len(args.homepage) > 0: @@ -237,25 +181,15 @@ def get_config_dict(args): return config_dict -def write_string_to_file(filename, data): - outfile = None - if platform.system() == 'Windows': - outfile = open(filename, 'w', encoding='UTF-8') - else: - outfile = open(filename, 'w') - - if not outfile is None: - outfile.write("%s" % data) - def write_question_to_file(question_text): working_dir = os.path.dirname(os.path.realpath(__file__)) target_path = os.path.join(working_dir, CONST_MAXBOT_QUESTION_FILE) - write_string_to_file(target_path, question_text) + util.write_string_to_file(target_path, question_text) def write_last_url_to_file(url): working_dir = os.path.dirname(os.path.realpath(__file__)) target_path = os.path.join(working_dir, CONST_MAXBOT_LAST_URL_FILE) - write_string_to_file(target_path, url) + util.write_string_to_file(target_path, url) def read_last_url_from_file(): ret = "" @@ -263,145 +197,6 @@ def read_last_url_from_file(): ret = text_file.readline() return ret -def format_keyword_string(keyword): - if not keyword is None: - if len(keyword) > 0: - keyword = keyword.replace('/','/') - keyword = keyword.replace(' ','') - keyword = keyword.replace(',','') - keyword = keyword.replace(',','') - keyword = keyword.replace('$','') - keyword = keyword.replace(' ','').lower() - return keyword - -def format_quota_string(formated_html_text): - formated_html_text = formated_html_text.replace('「','【') - formated_html_text = formated_html_text.replace('『','【') - formated_html_text = formated_html_text.replace('〔','【') - formated_html_text = formated_html_text.replace('﹝','【') - formated_html_text = formated_html_text.replace('〈','【') - formated_html_text = formated_html_text.replace('《','【') - formated_html_text = formated_html_text.replace('[','【') - formated_html_text = formated_html_text.replace('〖','【') - formated_html_text = formated_html_text.replace('[','【') - formated_html_text = formated_html_text.replace('(','【') - formated_html_text = formated_html_text.replace('(','【') - - formated_html_text = formated_html_text.replace('」','】') - formated_html_text = formated_html_text.replace('』','】') - formated_html_text = formated_html_text.replace('〕','】') - formated_html_text = formated_html_text.replace('﹞','】') - formated_html_text = formated_html_text.replace('〉','】') - formated_html_text = formated_html_text.replace('》','】') - formated_html_text = formated_html_text.replace(']','】') - formated_html_text = formated_html_text.replace('〗','】') - formated_html_text = formated_html_text.replace(']','】') - formated_html_text = formated_html_text.replace(')','】') - formated_html_text = formated_html_text.replace(')','】') - return formated_html_text - - -def full2half(keyword): - n = "" - if not keyword is None: - if len(keyword) > 0: - for char in keyword: - num = ord(char) - if num == 0x3000: - num = 32 - elif 0xFF01 <= num <= 0xFF5E: - num -= 0xfee0 - n += chr(num) - return n - -def get_chinese_numeric(): - my_dict = {} - my_dict['0']=['0','0','zero','零'] - my_dict['1']=['1','1','one','一','壹','①','❶','⑴'] - my_dict['2']=['2','2','two','二','貳','②','❷','⑵'] - my_dict['3']=['3','3','three','三','叁','③','❸','⑶'] - my_dict['4']=['4','4','four','四','肆','④','❹','⑷'] - my_dict['5']=['5','5','five','五','伍','⑤','❺','⑸'] - my_dict['6']=['6','6','six','六','陸','⑥','❻','⑹'] - my_dict['7']=['7','7','seven','七','柒','⑦','❼','⑺'] - my_dict['8']=['8','8','eight','八','捌','⑧','❽','⑻'] - my_dict['9']=['9','9','nine','九','玖','⑨','❾','⑼'] - return my_dict - -# 同義字 -def synonym_dict(char): - ret = [] - my_dict = get_chinese_numeric() - if char in my_dict: - ret = my_dict[char] - else: - ret.append(char) - return ret - -def chinese_numeric_to_int(char): - ret = None - my_dict = get_chinese_numeric() - for i in my_dict: - for item in my_dict[i]: - if char.lower() == item: - ret = int(i) - break - if not ret is None: - break - return ret - -def normalize_chinese_numeric(keyword): - ret = "" - for char in keyword: - converted_int = chinese_numeric_to_int(char) - if not converted_int is None: - ret += str(converted_int) - return ret - -def find_continuous_number(text): - chars = "0123456789" - return find_continuous_pattern(chars, text) - -def find_continuous_text(text): - chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - return find_continuous_pattern(chars, text) - -def find_continuous_pattern(allowed_char, text): - ret = "" - is_allowed_char_start = False - for char in text: - #print("char:", char) - if char in allowed_char: - if len(ret)==0 and not is_allowed_char_start: - is_allowed_char_start = True - if is_allowed_char_start: - ret += char - else: - # make not continuous - is_allowed_char_start = False - return ret - -def is_all_alpha_or_numeric(text): - ret = False - alpha_count = 0 - numeric_count = 0 - for char in text: - try: - if char.encode('UTF-8').isalpha(): - alpha_count += 1 - except Exception as exc: - pass - - #if char.isnumeric(): - if char.isdigit(): - numeric_count += 1 - - if (alpha_count + numeric_count) == len(text): - ret = True - - #print("text/is_all_alpha_or_numeric:",text,ret) - return ret - def get_favoriate_extension_path(webdriver_path, config_dict): #print("webdriver_path:", webdriver_path) extension_list = [] @@ -415,25 +210,6 @@ def get_chromedriver_path(webdriver_path): chromedriver_path = os.path.join(webdriver_path,"chromedriver.exe") return chromedriver_path -def get_brave_bin_path(): - brave_path = "" - if platform.system() == 'Windows': - brave_path = "C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe" - if not os.path.exists(brave_path): - brave_path = os.path.expanduser('~') + "\\AppData\\Local\\BraveSoftware\\Brave-Browser\\Application\\brave.exe" - if not os.path.exists(brave_path): - brave_path = "C:\\Program Files (x86)\\BraveSoftware\\Brave-Browser\\Application\\brave.exe" - if not os.path.exists(brave_path): - brave_path = "D:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe" - - if platform.system() == 'Linux': - brave_path = "/usr/bin/brave-browser" - - if platform.system() == 'Darwin': - brave_path = '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser' - - return brave_path - def get_chrome_options(webdriver_path, config_dict): chrome_options = webdriver.ChromeOptions() if config_dict["browser"]=="edge": @@ -487,7 +263,7 @@ def get_chrome_options(webdriver_path, config_dict): chrome_options.add_argument('--proxy-server=%s' % config_dict["advanced"]["proxy_server_port"]) if config_dict["browser"]=="brave": - brave_path = get_brave_bin_path() + brave_path = util.get_brave_bin_path() if os.path.exists(brave_path): chrome_options.binary_location = brave_path @@ -506,7 +282,7 @@ def load_chromdriver_normal(config_dict, driver_type): driver = None - Root_Dir = get_app_root() + Root_Dir = util.get_app_root() webdriver_path = os.path.join(Root_Dir, "webdriver") chromedriver_path = get_chromedriver_path(webdriver_path) @@ -563,110 +339,6 @@ def load_chromdriver_normal(config_dict, driver_type): return driver -def clean_uc_exe_cache(): - exe_name = "chromedriver%s" - - platform = sys.platform - if platform.endswith("win32"): - exe_name %= ".exe" - if platform.endswith(("linux", "linux2")): - exe_name %= "" - if platform.endswith("darwin"): - exe_name %= "" - - d = "" - if platform.endswith("win32"): - d = "~/appdata/roaming/undetected_chromedriver" - elif "LAMBDA_TASK_ROOT" in os.environ: - d = "/tmp/undetected_chromedriver" - elif platform.startswith(("linux", "linux2")): - d = "~/.local/share/undetected_chromedriver" - elif platform.endswith("darwin"): - d = "~/Library/Application Support/undetected_chromedriver" - else: - d = "~/.undetected_chromedriver" - data_path = os.path.abspath(os.path.expanduser(d)) - - is_cache_exist = False - p = pathlib.Path(data_path) - files = list(p.rglob("*chromedriver*?")) - for file in files: - if os.path.exists(str(file)): - is_cache_exist = True - try: - os.unlink(str(file)) - except Exception as exc2: - print(exc2) - pass - - return is_cache_exist - -def dump_settings_to_maxbot_plus_extension(ext, config_dict): - # sync config. - target_path = ext - target_path = os.path.join(target_path, "data") - target_path = os.path.join(target_path, CONST_MAXBOT_CONFIG_FILE) - #print("save as to:", target_path) - if os.path.isfile(target_path): - try: - #print("remove file:", target_path) - os.unlink(target_path) - except Exception as exc: - pass - with open(target_path, 'w') as outfile: - json.dump(config_dict, outfile) - - # add host_permissions - target_path = ext - target_path = os.path.join(target_path, "manifest.json") - - manifest_dict = None - if os.path.isfile(target_path): - with open(target_path) as json_data: - manifest_dict = json.load(json_data) - - local_remote_url_array = [] - local_remote_url = config_dict["advanced"]["remote_url"] - if len(local_remote_url) > 0: - try: - temp_remote_url_array = json.loads("["+ local_remote_url +"]") - for remote_url in temp_remote_url_array: - remote_url_final = remote_url + "*" - local_remote_url_array.append(remote_url_final) - except Exception as exc: - pass - - if len(local_remote_url_array) > 0: - is_manifest_changed = False - for remote_url_final in local_remote_url_array: - if not remote_url_final in manifest_dict["host_permissions"]: - #print("local remote_url not in manifest:", remote_url_final) - manifest_dict["host_permissions"].append(remote_url_final) - is_manifest_changed = True - - if is_manifest_changed: - json_str = json.dumps(manifest_dict, indent=4) - with open(target_path, 'w') as outfile: - outfile.write(json_str) - -def dump_settings_to_maxblock_plus_extension(ext, config_dict): - # sync config. - target_path = ext - target_path = os.path.join(target_path, "data") - # special case, due to data folder is empty, sometime will be removed. - if not os.path.exists(target_path): - os.mkdir(target_path) - target_path = os.path.join(target_path, CONST_MAXBOT_CONFIG_FILE) - #print("save as to:", target_path) - if os.path.isfile(target_path): - try: - #print("remove file:", target_path) - os.unlink(target_path) - except Exception as exc: - pass - with open(target_path, 'w') as outfile: - config_dict["domain_filter"]=CONST_MAXBLOCK_EXTENSION_FILTER - json.dump(config_dict, outfile) def get_uc_options(uc, config_dict, webdriver_path): options = uc.ChromeOptions() @@ -694,9 +366,9 @@ def get_uc_options(uc, config_dict, webdriver_path): if os.path.exists(ext): # sync config. if CONST_MAXBOT_EXTENSION_NAME in ext: - dump_settings_to_maxbot_plus_extension(ext, config_dict) + util.dump_settings_to_maxbot_plus_extension(ext, config_dict, CONST_MAXBOT_CONFIG_FILE) if CONST_MAXBLOCK_EXTENSION_NAME in ext: - dump_settings_to_maxblock_plus_extension(ext, config_dict) + util.dump_settings_to_maxblock_plus_extension(ext, config_dict, CONST_MAXBOT_CONFIG_FILE, CONST_MAXBLOCK_EXTENSION_FILTER) load_extension_path += ("," + os.path.abspath(ext)) #print("load_extension_path:", load_extension_path) @@ -728,7 +400,7 @@ def get_uc_options(uc, config_dict, webdriver_path): options.add_argument('--proxy-server=%s' % config_dict["advanced"]["proxy_server_port"]) if config_dict["browser"]=="brave": - brave_path = get_brave_bin_path() + brave_path = util.get_brave_bin_path() if os.path.exists(brave_path): options.binary_location = brave_path @@ -743,7 +415,7 @@ def load_chromdriver_uc(config_dict): if config_dict["advanced"]["verbose"]: show_debug_message = True - Root_Dir = get_app_root() + Root_Dir = util.get_app_root() webdriver_path = os.path.join(Root_Dir, "webdriver") chromedriver_path = get_chromedriver_path(webdriver_path) @@ -762,11 +434,10 @@ def load_chromdriver_uc(config_dict): else: print("ChromeDriver exist:", chromedriver_path) - driver = None if os.path.exists(chromedriver_path): # use chromedriver_autodownload instead of uc auto download. - is_cache_exist = clean_uc_exe_cache() + is_cache_exist = util.clean_uc_exe_cache() fail_1 = False try: @@ -881,7 +552,7 @@ def get_driver_by_config(config_dict): if homepage is None: homepage = "" - Root_Dir = get_app_root() + Root_Dir = util.get_app_root() webdriver_path = os.path.join(Root_Dir, "webdriver") #print("platform.system().lower():", platform.system().lower()) @@ -1104,692 +775,6 @@ def get_driver_by_config(config_dict): return driver -# common functions. -def find_between( s, first, last ): - ret = "" - try: - start = s.index( first ) + len( first ) - end = s.index( last, start ) - ret = s[start:end] - except ValueError: - pass - return ret - -# convert web string to reg pattern -def convert_string_to_pattern(my_str, dynamic_length=True): - my_hint_anwser_length = len(my_str) - my_formated = "" - if my_hint_anwser_length > 0: - my_anwser_symbols = "()[]<>{}-" - for idx in range(my_hint_anwser_length): - char = my_str[idx:idx+1] - - if char in my_anwser_symbols: - my_formated += ('\\' + char) - continue - - pattern = re.compile("[A-Z]") - match_result = pattern.match(char) - #print("match_result A:", match_result) - if not match_result is None: - my_formated += "[A-Z]" - - pattern = re.compile("[a-z]") - match_result = pattern.match(char) - #print("match_result a:", match_result) - if not match_result is None: - my_formated += "[a-z]" - - pattern = re.compile("[\d]") - match_result = pattern.match(char) - #print("match_result d:", match_result) - if not match_result is None: - my_formated += "[\d]" - - # for dynamic length - if dynamic_length: - for i in range(10): - my_formated = my_formated.replace("[A-Z][A-Z]","[A-Z]") - my_formated = my_formated.replace("[a-z][a-z]","[a-z]") - my_formated = my_formated.replace("[\d][\d]","[\d]") - - my_formated = my_formated.replace("[A-Z]","[A-Z]+") - my_formated = my_formated.replace("[a-z]","[a-z]+") - my_formated = my_formated.replace("[\d]","[\d]+") - return my_formated - -def guess_answer_list_from_multi_options(tmp_text): - show_debug_message = True # debug. - show_debug_message = False # online - - options_list = [] - matched_pattern = "" - if len(options_list) == 0: - if '【' in tmp_text and '】' in tmp_text: - pattern = '【.{1,4}】' - options_list = re.findall(pattern, tmp_text) - if len(options_list) <= 2: - options_list = [] - else: - matched_pattern = pattern - - if len(options_list) == 0: - if '(' in tmp_text and ')' in tmp_text: - pattern = '\(.{1,4}\)' - options_list = re.findall(pattern, tmp_text) - if len(options_list) <= 2: - options_list = [] - else: - matched_pattern = pattern - - if len(options_list) == 0: - if '[' in tmp_text and ']' in tmp_text: - pattern = '\[.{1,4}\]' - options_list = re.findall(pattern, tmp_text) - if len(options_list) <= 2: - options_list = [] - else: - matched_pattern = pattern - - if len(options_list) == 0: - if "\n" in tmp_text and ')' in tmp_text: - pattern = "\\n.{1,4}\)" - options_list = re.findall(pattern, tmp_text) - if len(options_list) <= 2: - options_list = [] - else: - matched_pattern = pattern - - if len(options_list) == 0: - if "\n" in tmp_text and ']' in tmp_text: - pattern = "\\n.{1,4}\]" - options_list = re.findall(pattern, tmp_text) - if len(options_list) <= 2: - options_list = [] - else: - matched_pattern = pattern - - if len(options_list) == 0: - if "\n" in tmp_text and '】' in tmp_text: - pattern = "\\n.{1,4}】" - options_list = re.findall(pattern, tmp_text) - if len(options_list) <= 2: - options_list = [] - else: - matched_pattern = pattern - - if len(options_list) == 0: - if "\n" in tmp_text and ':' in tmp_text: - pattern = "\\n.{1,4}:" - options_list = re.findall(pattern, tmp_text) - if len(options_list) <= 2: - options_list = [] - else: - matched_pattern = pattern - - if len(options_list) == 0: - if " " in tmp_text and '?' in tmp_text: - if ('.' in tmp_text or ':' in tmp_text or ')' in tmp_text or ']' in tmp_text or '>' in tmp_text): - pattern = "[ /\n\|;\.\?]{1}.{1}[\.:)\]>]{1}.{2,3}" - options_list = re.findall(pattern, tmp_text) - if len(options_list) <= 2: - options_list = [] - else: - formated_list = [] - for new_item in options_list: - new_item = new_item.strip() - if new_item[:1] == ".": - new_item = new_item[1:] - if new_item[:1] == "?": - new_item = new_item[1:] - if new_item[:1] == "|": - new_item = new_item[1:] - if new_item[:1] == ";": - new_item = new_item[1:] - if new_item[:1] == "/": - new_item = new_item[1:] - new_item = new_item.strip() - new_item = new_item[:1] - formated_list.append(new_item) - options_list = formated_list - - matched_pattern = pattern - - if show_debug_message: - print("matched pattern:", matched_pattern) - - # default remove quota - is_trim_quota = not check_answer_keep_symbol(tmp_text) - if show_debug_message: - print("is_trim_quota:", is_trim_quota) - - return_list = [] - if len(options_list) > 0: - options_list_length = len(options_list) - if show_debug_message: - print("options_list_length:", options_list_length) - print("options_list:", options_list) - if options_list_length > 2: - is_all_options_same_length = True - options_length_count = {} - for i in range(options_list_length-1): - current_option_length = len(options_list[i]) - next_option_length = len(options_list[i+1]) - if current_option_length != next_option_length: - is_all_options_same_length = False - if current_option_length in options_length_count: - options_length_count[current_option_length] += 1 - else: - options_length_count[current_option_length] = 1 - - if show_debug_message: - print("is_all_options_same_length:", is_all_options_same_length) - - if is_all_options_same_length: - return_list = [] - for each_option in options_list: - if len(each_option) > 2: - if is_trim_quota: - return_list.append(each_option[1:-1]) - else: - return_list.append(each_option) - else: - return_list.append(each_option) - else: - #print("options_length_count:", options_length_count) - if len(options_length_count) > 0: - target_option_length = 0 - most_length_count = 0 - for k in options_length_count.keys(): - if options_length_count[k] > most_length_count: - most_length_count = options_length_count[k] - target_option_length = k - #print("most_length_count:", most_length_count) - #print("target_option_length:", target_option_length) - if target_option_length > 0: - return_list = [] - for each_option in options_list: - current_option_length = len(each_option) - if current_option_length == target_option_length: - if is_trim_quota: - return_list.append(each_option[1:-1]) - else: - return_list.append(each_option) - - # something is wrong, give up when option equal 2 options. - if len(return_list) <= 2: - return_list = [] - - # remove chinese work options. - if len(options_list) > 0: - new_list = [] - for item in return_list: - if is_all_alpha_or_numeric(item): - new_list.append(item) - if len(new_list) >=3: - return_list = new_list - - return return_list - -#PS: this may get a wrong answer list. XD -def guess_answer_list_from_symbols(captcha_text_div_text): - return_list = [] - # need replace to space to get first options. - tmp_text = captcha_text_div_text - tmp_text = tmp_text.replace('?',' ') - tmp_text = tmp_text.replace('?',' ') - tmp_text = tmp_text.replace('。',' ') - - delimitor_symbols_left = [u"(","[","{", " ", " ", " ", " "] - delimitor_symbols_right = [u")","]","}", ":", ".", ")", "-"] - idx = -1 - for idx in range(len(delimitor_symbols_left)): - symbol_left = delimitor_symbols_left[idx] - symbol_right = delimitor_symbols_right[idx] - if symbol_left in tmp_text and symbol_right in tmp_text and '半形' in tmp_text: - hint_list = re.findall('\\'+ symbol_left + '[\\w]+\\'+ symbol_right , tmp_text) - #print("hint_list:", hint_list) - if not hint_list is None: - if len(hint_list) > 1: - return_list = [] - my_answer_delimitor = symbol_right - for options in hint_list: - if len(options) > 2: - my_anwser = options[1:-1] - #print("my_anwser:",my_anwser) - if len(my_anwser) > 0: - return_list.append(my_anwser) - - if len(return_list) > 0: - break - return return_list - -def get_offical_hint_string_from_symbol(symbol, tmp_text): - show_debug_message = True # debug. - show_debug_message = False # online - - offical_hint_string = "" - if symbol in tmp_text: - # start to guess offical hint - if offical_hint_string == "": - if '【' in tmp_text and '】' in tmp_text: - hint_list = re.findall('【.*?】', tmp_text) - if not hint_list is None: - if show_debug_message: - print("【.*?】hint_list:", hint_list) - for hint in hint_list: - if symbol in hint: - offical_hint_string = hint[1:-1] - break - if offical_hint_string == "": - if '(' in tmp_text and ')' in tmp_text: - hint_list = re.findall('\(.*?\)', tmp_text) - if not hint_list is None: - if show_debug_message: - print("\(.*?\)hint_list:", hint_list) - for hint in hint_list: - if symbol in hint: - offical_hint_string = hint[1:-1] - break - if offical_hint_string == "": - if '[' in tmp_text and ']' in tmp_text: - hint_list = re.findall('[.*?]', tmp_text) - if not hint_list is None: - if show_debug_message: - print("[.*?]hint_list:", hint_list) - for hint in hint_list: - if symbol in hint: - offical_hint_string = hint[1:-1] - break - if offical_hint_string == "": - offical_hint_string = tmp_text - return offical_hint_string - -def guess_answer_list_from_hint(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text): - show_debug_message = True # debug. - show_debug_message = False # online - - tmp_text = format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) - - my_question = "" - my_options = "" - offical_hint_string = "" - offical_hint_string_anwser = "" - my_anwser_formated = "" - my_answer_delimitor = "" - - if my_question == "": - if "?" in tmp_text: - question_index = tmp_text.find("?") - my_question = tmp_text[:question_index+1] - if my_question == "": - if "。" in tmp_text: - question_index = tmp_text.find("。") - my_question = tmp_text[:question_index+1] - if my_question == "": - my_question = tmp_text - #print("my_question:", my_question) - - # ps: hint_list is not options list - - if offical_hint_string == "": - # for: 若你覺得答案為 a,請輸入 a - if '答案' in tmp_text and CONST_INPUT_SYMBOL in tmp_text: - offical_hint_string = get_offical_hint_string_from_symbol(CONST_INPUT_SYMBOL, tmp_text) - if len(offical_hint_string) > 0: - right_part = offical_hint_string.split(CONST_INPUT_SYMBOL)[1] - #print("right_part:", right_part) - if len(offical_hint_string) == len(tmp_text): - offical_hint_string = right_part - - new_hint = find_continuous_text(right_part) - if len(new_hint) > 0: - # TODO: 答案為B需填入Bb) - #if '答案' in offical_hint_string and CONST_INPUT_SYMBOL in offical_hint_string: - offical_hint_string_anwser = new_hint - - - if offical_hint_string == "": - offical_hint_string = get_offical_hint_string_from_symbol(CONST_EXAMPLE_SYMBOL, tmp_text) - if len(offical_hint_string) > 0: - right_part = offical_hint_string.split(CONST_EXAMPLE_SYMBOL)[1] - if len(offical_hint_string) == len(tmp_text): - offical_hint_string = right_part - - # PS: find first text will only get B char in this case: 答案為B需填入Bb) - new_hint = find_continuous_text(right_part) - if len(new_hint) > 0: - offical_hint_string_anwser = new_hint - - # resize offical_hint_string_anwser for options contains in hint string. - #print("offical_hint_string_anwser:", offical_hint_string_anwser) - if len(offical_hint_string_anwser) > 0: - offical_hint_string = offical_hint_string.split(offical_hint_string_anwser)[0] - - if show_debug_message: - print("offical_hint_string:", offical_hint_string) - - # try rule4: - # get hint from rule 3: without '(' & '), but use "*" - if len(offical_hint_string) == 0: - target_symbol = "*" - if target_symbol in tmp_text : - star_index = tmp_text.find(target_symbol) - space_index = tmp_text.find(" ", star_index + len(target_symbol)) - offical_hint_string = tmp_text[star_index: space_index] - - # is need to merge next block - if len(offical_hint_string) > 0: - target_symbol = offical_hint_string + " " - if target_symbol in tmp_text : - star_index = tmp_text.find(target_symbol) - next_block_index = star_index + len(target_symbol) - space_index = tmp_text.find(" ", next_block_index) - next_block = tmp_text[next_block_index: space_index] - if CONST_EXAMPLE_SYMBOL in next_block: - offical_hint_string += ' ' + next_block - - # try rule5: - # get hint from rule 3: n個半形英文大寫 - if len(offical_hint_string) == 0: - target_symbol = "個半形英文大寫" - if target_symbol in tmp_text : - star_index = tmp_text.find(target_symbol) - space_index = tmp_text.find(" ", star_index) - answer_char_count = tmp_text[star_index-1:star_index] - if answer_char_count.isnumeric(): - answer_char_count = chinese_numeric_to_int(answer_char_count) - if answer_char_count is None: - answer_char_count = '0' - - star_index -= 1 - offical_hint_string_anwser = 'A' * int(answer_char_count) - offical_hint_string = tmp_text[star_index: space_index] - - target_symbol = "個英文大寫" - if target_symbol in tmp_text : - star_index = tmp_text.find(target_symbol) - space_index = tmp_text.find(" ", star_index) - answer_char_count = tmp_text[star_index-1:star_index] - if answer_char_count.isnumeric(): - answer_char_count = chinese_numeric_to_int(answer_char_count) - if answer_char_count is None: - answer_char_count = '0' - - star_index -= 1 - offical_hint_string_anwser = 'A' * int(answer_char_count) - offical_hint_string = tmp_text[star_index: space_index] - - target_symbol = "個半形英文小寫" - if target_symbol in tmp_text : - star_index = tmp_text.find(target_symbol) - space_index = tmp_text.find(" ", star_index) - answer_char_count = tmp_text[star_index-1:star_index] - if answer_char_count.isnumeric(): - answer_char_count = chinese_numeric_to_int(answer_char_count) - if answer_char_count is None: - answer_char_count = '0' - - star_index -= 1 - offical_hint_string_anwser = 'a' * int(answer_char_count) - offical_hint_string = tmp_text[star_index: space_index] - - target_symbol = "個英文小寫" - if target_symbol in tmp_text : - star_index = tmp_text.find(target_symbol) - space_index = tmp_text.find(" ", star_index) - answer_char_count = tmp_text[star_index-1:star_index] - if answer_char_count.isnumeric(): - answer_char_count = chinese_numeric_to_int(answer_char_count) - if answer_char_count is None: - answer_char_count = '0' - - star_index -= 1 - offical_hint_string_anwser = 'a' * int(answer_char_count) - offical_hint_string = tmp_text[star_index: space_index] - - target_symbol = "個英數半形字" - if target_symbol in tmp_text : - star_index = tmp_text.find(target_symbol) - space_index = tmp_text.find(" ", star_index) - answer_char_count = tmp_text[star_index-1:star_index] - if answer_char_count.isnumeric(): - answer_char_count = chinese_numeric_to_int(answer_char_count) - if answer_char_count is None: - answer_char_count = '0' - - star_index -= 1 - my_anwser_formated = '[A-Za-z\d]' * int(answer_char_count) - offical_hint_string = tmp_text[star_index: space_index] - - target_symbol = "個半形" - if target_symbol in tmp_text : - star_index = tmp_text.find(target_symbol) - space_index = tmp_text.find(" ", star_index) - answer_char_count = tmp_text[star_index-1:star_index] - if answer_char_count.isnumeric(): - answer_char_count = chinese_numeric_to_int(answer_char_count) - if answer_char_count is None: - answer_char_count = '0' - - star_index -= 1 - my_anwser_formated = '[A-Za-z\d]' * int(answer_char_count) - offical_hint_string = tmp_text[star_index: space_index] - - if len(offical_hint_string) > 0: - if show_debug_message: - print("offical_hint_string_anwser:", offical_hint_string_anwser) - my_anwser_formated = convert_string_to_pattern(offical_hint_string_anwser) - - my_options = tmp_text - if len(my_question) < len(tmp_text): - my_options = my_options.replace(my_question,"") - my_options = my_options.replace(offical_hint_string,"") - - # try rule7: - # check is chinese/english in question, if match, apply my_options rule. - if len(offical_hint_string) > 0: - tmp_text_org = captcha_text_div_text - if CONST_EXAMPLE_SYMBOL in tmp_text: - tmp_text_org = tmp_text_org.replace('Ex:','ex:') - target_symbol = "ex:" - if target_symbol in tmp_text_org : - star_index = tmp_text_org.find(target_symbol) - my_options = tmp_text_org[star_index-1:] - - if show_debug_message: - print("tmp_text:", tmp_text) - print("my_options:", my_options) - - if len(my_anwser_formated) > 0: - allow_delimitor_symbols = ")].: }" - pattern = re.compile(my_anwser_formated) - search_result = pattern.search(my_options) - if not search_result is None: - (span_start, span_end) = search_result.span() - maybe_delimitor="" - if len(my_options) > (span_end+1)+1: - maybe_delimitor = my_options[span_end+0:span_end+1] - if maybe_delimitor in allow_delimitor_symbols: - my_answer_delimitor = maybe_delimitor - - if show_debug_message: - print("my_answer_delimitor:", my_answer_delimitor) - - # default remove quota - is_trim_quota = not check_answer_keep_symbol(tmp_text) - if show_debug_message: - print("is_trim_quota:", is_trim_quota) - - return_list = [] - if len(my_anwser_formated) > 0: - new_pattern = my_anwser_formated - if len(my_answer_delimitor) > 0: - new_pattern = my_anwser_formated + '\\' + my_answer_delimitor - - return_list = re.findall(new_pattern, my_options) - if show_debug_message: - print("my_anwser_formated:", my_anwser_formated) - print("new_pattern:", new_pattern) - print("return_list:" , return_list) - - if not return_list is None: - if len(return_list) == 1: - # re-sample for this case. - return_list = re.findall(my_anwser_formated, my_options) - - if len(return_list) == 1: - # if use pattern to find matched only one, means it is for example text. - return_list = None - - if not return_list is None: - # clean delimitor - if is_trim_quota: - return_list_length = len(return_list) - if return_list_length >= 1: - if len(my_answer_delimitor) > 0: - for idx in range(return_list_length): - return_list[idx]=return_list[idx].replace(my_answer_delimitor,'') - if show_debug_message: - print("cleaned return_list:" , return_list) - - if return_list is None: - return_list = [] - - return return_list, offical_hint_string_anwser - -def format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text): - tmp_text = captcha_text_div_text - tmp_text = tmp_text.replace(' ',' ') - tmp_text = tmp_text.replace(':',':') - # for hint - tmp_text = tmp_text.replace('*','*') - - # stop word. - tmp_text = tmp_text.replace('輸入法','') - tmp_text = tmp_text.replace('請問','') - tmp_text = tmp_text.replace('請將','') - tmp_text = tmp_text.replace('請在','') - tmp_text = tmp_text.replace('請以','') - tmp_text = tmp_text.replace('請回答','') - tmp_text = tmp_text.replace('請','') - - # replace ex. - tmp_text = tmp_text.replace('例如', CONST_EXAMPLE_SYMBOL) - tmp_text = tmp_text.replace('如:', CONST_EXAMPLE_SYMBOL) - tmp_text = tmp_text.replace('如為', CONST_EXAMPLE_SYMBOL+'為') - - tmp_text = tmp_text.replace('舉例', CONST_EXAMPLE_SYMBOL) - if not CONST_EXAMPLE_SYMBOL in tmp_text: - tmp_text = tmp_text.replace('例', CONST_EXAMPLE_SYMBOL) - # important, maybe 例 & ex occurs at same time. - tmp_text = tmp_text.replace('ex:', CONST_EXAMPLE_SYMBOL) - tmp_text = tmp_text.replace('Ex:', CONST_EXAMPLE_SYMBOL) - - #若你覺得 - #PS:這個,可能會造成更多問題,呵呵。 - SYMBOL_IF_LIST = ['假設','如果','若'] - for symbol_if in SYMBOL_IF_LIST: - if symbol_if in tmp_text and '答案' in tmp_text: - tmp_text = tmp_text.replace('覺得', '') - tmp_text = tmp_text.replace('認為', '') - tmp_text = tmp_text.replace(symbol_if + '你答案', CONST_EXAMPLE_SYMBOL + '答案') - tmp_text = tmp_text.replace(symbol_if + '答案', CONST_EXAMPLE_SYMBOL + '答案') - - tmp_text = tmp_text.replace('填入', CONST_INPUT_SYMBOL) - - #tmp_text = tmp_text.replace('[','(') - #tmp_text = tmp_text.replace(']',')') - tmp_text = tmp_text.replace('?','?') - - tmp_text = tmp_text.replace('(','(') - tmp_text = tmp_text.replace(')',')') - - return tmp_text - -def permutations(iterable, r=None): - pool = tuple(iterable) - n = len(pool) - r = n if r is None else r - if r > n: - return - indices = list(range(n)) - cycles = list(range(n, n-r, -1)) - yield tuple(pool[i] for i in indices[:r]) - while n: - for i in reversed(range(r)): - cycles[i] -= 1 - if cycles[i] == 0: - indices[i:] = indices[i+1:] + indices[i:i+1] - cycles[i] = n - i - else: - j = cycles[i] - indices[i], indices[-j] = indices[-j], indices[i] - yield tuple(pool[i] for i in indices[:r]) - break - else: - return - -def get_answer_list_by_question(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text): - show_debug_message = True # debug. - show_debug_message = False # online - - return_list = [] - - tmp_text = format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) - - # guess answer list from multi-options: 【】() [] - if len(return_list)==0: - return_list = guess_answer_list_from_multi_options(tmp_text) - if show_debug_message: - print("captcha_text_div_text:", captcha_text_div_text) - if len(return_list) > 0: - print("found, guess_answer_list_from_multi_options:", return_list) - - offical_hint_string_anwser = "" - if len(return_list)==0: - return_list, offical_hint_string_anwser = guess_answer_list_from_hint(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) - else: - is_match_factorial = False - mutiple = 0 - - return_list_2, offical_hint_string_anwser = guess_answer_list_from_hint(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) - if return_list_2 is None: - if len(offical_hint_string_anwser) >=3: - if len(return_list) >=3: - mutiple = int(len(offical_hint_string_anwser) / len(return_list[0])) - if mutiple >=3 : - is_match_factorial = True - - if show_debug_message: - print("mutiple:", mutiple) - print("is_match_factorial:", is_match_factorial) - if is_match_factorial: - is_match_factorial = False - order_string_list = ['排列','排序','依序','順序','遞增','遞減','升冪','降冪','新到舊','舊到新','小到大','大到小','高到低','低到高'] - for order_string in order_string_list: - if order_string in tmp_text: - is_match_factorial = True - - if is_match_factorial: - new_array = permutations(return_list, mutiple) - #print("new_array:", new_array) - - return_list = [] - for item_tuple in new_array: - return_list.append(''.join(item_tuple)) - - if show_debug_message: - if len(return_list) > 0: - print("found, guess_answer_list_from_hint:", return_list) - - if len(return_list)==0: - return_list = guess_answer_list_from_symbols(captcha_text_div_text) - if show_debug_message: - if len(return_list) > 0: - print("found, guess_answer_list_from_symbols:", return_list) - - return return_list def force_press_button_iframe(driver, f, select_by, select_query, force_submit=True): if not f: @@ -1942,29 +927,6 @@ def tixcraft_redirect(driver, url): return ret -def get_target_item_from_matched_list(matched_blocks, auto_select_mode): - target_area = None - if not matched_blocks is None: - matched_blocks_count = len(matched_blocks) - if matched_blocks_count > 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 = matched_blocks_count - 1 - - if auto_select_mode == CONST_RANDOM: - if matched_blocks_count > 1: - target_row_index = random.randint(0,matched_blocks_count-1) - - if auto_select_mode == CONST_CENTER: - if matched_blocks_count > 2: - target_row_index = int(matched_blocks_count/2) - - target_area = matched_blocks[target_row_index] - return target_area def tixcraft_date_auto_select(driver, url, config_dict, domain_name): show_debug_message = True # debug. @@ -2018,15 +980,16 @@ def tixcraft_date_auto_select(driver, url, config_dict, domain_name): # only headless mode detected now. if config_dict["advanced"]["headless"]: html_body = driver.page_source - html_text = remove_html_tags(html_body) - if not html_text is None: - bot_detected_string_list = ['Your Session Has Been Suspended' - , 'Something about your browsing behavior or network made us think you were a bot' - , 'Your browser hit a snag and we need to make sure you' - ] - for each_string in bot_detected_string_list: - print(html_text) - break + if not html_body is None: + if len(html_body) > 0: + html_text = util.remove_html_tags(html_body) + bot_detected_string_list = ['Your Session Has Been Suspended' + , 'Something about your browsing behavior or network made us think you were a bot' + , 'Your browser hit a snag and we need to make sure you' + ] + for each_string in bot_detected_string_list: + print(html_text) + break except Exception as exc: print("find #gameList fail") @@ -2038,15 +1001,17 @@ def tixcraft_date_auto_select(driver, url, config_dict, domain_name): html_lang="en-US" try: html_body = driver.page_source - if ' 0: + if ' 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: @@ -2128,7 +1093,7 @@ def tixcraft_date_auto_select(driver, url, config_dict, domain_name): if show_debug_message: print("start to match formated keyword:", date_keyword) - matched_blocks = get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) + matched_blocks = util.get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) if show_debug_message: if not matched_blocks is None: @@ -2140,7 +1105,7 @@ def tixcraft_date_auto_select(driver, url, config_dict, domain_name): print("date date-time-position is None") pass - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) is_date_clicked = False if not target_area is None: @@ -2241,7 +1206,7 @@ def ticketmaster_date_auto_select(driver, url, config_dict, domain_name): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -2276,11 +1241,11 @@ def ticketmaster_date_auto_select(driver, url, config_dict, domain_name): matched_blocks = formated_area_list else: # match keyword. - date_keyword = format_keyword_string(date_keyword) + date_keyword = util.format_keyword_string(date_keyword) if show_debug_message: print("start to match formated keyword:", date_keyword) - matched_blocks = get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) + matched_blocks = util.get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) if show_debug_message: if not matched_blocks is None: @@ -2292,7 +1257,7 @@ def ticketmaster_date_auto_select(driver, url, config_dict, domain_name): print("date date-time-position is None") pass - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) is_date_clicked = False if not target_area is None: @@ -2323,109 +1288,6 @@ def ticketmaster_date_auto_select(driver, url, config_dict, domain_name): return is_date_clicked -def get_matched_blocks_by_keyword_item_set(config_dict, auto_select_mode, keyword_item_set, formated_area_list): - show_debug_message = True # debug. - show_debug_message = False # online - - if config_dict["advanced"]["verbose"]: - show_debug_message = True - - matched_blocks = [] - for row in formated_area_list: - row_text = "" - row_html = "" - try: - #row_text = row.text - row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) - except Exception as exc: - if show_debug_message: - print(exc) - # error, exit loop - break - - if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): - row_text = "" - - if len(row_text) > 0: - # start to compare, normalize all. - row_text = format_keyword_string(row_text) - if show_debug_message: - print("row_text:", row_text) - - is_match_all = False - if ' ' in keyword_item_set: - keyword_item_array = keyword_item_set.split(' ') - is_match_all = True - for keyword_item in keyword_item_array: - keyword_item = format_keyword_string(keyword_item) - if not keyword_item in row_text: - is_match_all = False - else: - exclude_item = format_keyword_string(keyword_item_set) - if exclude_item in row_text: - is_match_all = True - - if is_match_all: - matched_blocks.append(row) - - # only need first row. - if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM: - break - return matched_blocks - -def get_matched_blocks_by_keyword(config_dict, auto_select_mode, keyword_string, formated_area_list): - keyword_array = [] - try: - keyword_array = json.loads("["+ keyword_string +"]") - except Exception as exc: - keyword_array = [] - - matched_blocks = [] - for keyword_item_set in keyword_array: - matched_blocks = get_matched_blocks_by_keyword_item_set(config_dict, auto_select_mode, keyword_item_set, formated_area_list) - if len(matched_blocks) > 0: - break - return matched_blocks - -def is_row_match_keyword(keyword_string, row_text): - # clean stop word. - row_text = format_keyword_string(row_text) - - is_match_keyword = True - if len(keyword_string) > 0 and len(row_text) > 0: - is_match_keyword = False - keyword_array = [] - try: - keyword_array = json.loads("["+ keyword_string +"]") - except Exception as exc: - keyword_array = [] - for item_list in keyword_array: - if len(item_list) > 0: - if ' ' in item_list: - keyword_item_array = item_list.split(' ') - is_match_all_exclude = True - for each_item in keyword_item_array: - each_item = format_keyword_string(each_item) - if not each_item in row_text: - is_match_all_exclude = False - if is_match_all_exclude: - is_match_keyword = True - else: - item_list = format_keyword_string(item_list) - if item_list in row_text: - is_match_keyword = True - else: - # match all. - is_match_keyword = True - if is_match_keyword: - break - return is_match_keyword - -def reset_row_text_if_match_keyword_exclude(config_dict, row_text): - area_keyword_exclude = config_dict["keyword_exclude"] - return is_row_match_keyword(area_keyword_exclude, row_text) # PURPOSE: get target area list. # RETURN: @@ -2471,7 +1333,7 @@ def get_tixcraft_target_area(el, config_dict, area_keyword_item): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -2479,12 +1341,12 @@ def get_tixcraft_target_area(el, config_dict, area_keyword_item): break if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: # clean stop word. - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) is_append_this_row = False @@ -2493,7 +1355,7 @@ def get_tixcraft_target_area(el, config_dict, area_keyword_item): is_append_this_row = True area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_append_this_row = False break @@ -2590,12 +1452,12 @@ def get_ticketmaster_target_area(config_dict, area_keyword_item, zone_info): row_text = "" if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: # clean stop word. - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) if show_debug_message: #print("formated row_text:", row_text) pass @@ -2607,7 +1469,7 @@ def get_ticketmaster_target_area(config_dict, area_keyword_item, zone_info): is_append_this_row = True area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_append_this_row = False break @@ -2676,7 +1538,7 @@ def tixcraft_area_auto_select(driver, url, config_dict): # empty keyword, match all. is_need_refresh, matched_blocks = get_tixcraft_target_area(el, config_dict, "") - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: try: target_area.click() @@ -2732,7 +1594,7 @@ def ticketmaster_area_auto_select(driver, config_dict, zone_info): is_need_refresh, matched_blocks = get_ticketmaster_target_area(config_dict, "", zone_info) auto_select_mode = config_dict["area_auto_select"]["mode"] - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: try: #print("area text:", target_area.text) @@ -2756,28 +1618,6 @@ def ticketmaster_area_auto_select(driver, config_dict, zone_info): if config_dict["advanced"]["auto_reload_page_interval"] > 0: time.sleep(config_dict["advanced"]["auto_reload_page_interval"]) - -def tixcraft_ticket_agree(driver, config_dict): - show_debug_message = True # debug. - show_debug_message = False # online - - if config_dict["advanced"]["verbose"]: - show_debug_message = True - - agree_checkbox = None - try: - my_css_selector = '#TicketForm_agree' - agree_checkbox = driver.find_element(By.CSS_SELECTOR, my_css_selector) - except Exception as exc: - print("find TicketForm_agree fail") - if show_debug_message: - print(exc) - pass - - is_finish_checkbox_click = force_check_checkbox(driver, agree_checkbox) - - return is_finish_checkbox_click - def ticket_number_select_fill(driver, select_obj, ticket_number): is_ticket_number_assigned = False if not select_obj is None: @@ -2847,50 +1687,6 @@ def get_div_text_by_selector(driver, my_css_selector): return question_text -def guess_tixcraft_question(driver, question_text): - show_debug_message = True # debug. - show_debug_message = False # online - - answer_list = [] - - formated_html_text = "" - if len(question_text) > 0: - # format question text. - formated_html_text = question_text - formated_html_text = format_quota_string(formated_html_text) - - if '【' in formated_html_text and '】' in formated_html_text: - # PS: 這個太容易沖突,因為問題類型太多,不能直接使用。 - #inferred_answer_string = find_between(formated_html_text, "【", "】") - pass - - if show_debug_message: - print("formated_html_text:", formated_html_text) - - # start to guess answer - inferred_answer_string = None - - # 請輸入"YES",代表您已詳閱且瞭解並同意。 - if inferred_answer_string is None: - if '輸入"YES"' in formated_html_text: - if '已詳閱' in formated_html_text or '請詳閱' in formated_html_text: - if '同意' in formated_html_text: - inferred_answer_string = 'YES' - - # 購票前請詳閱注意事項,並於驗證碼欄位輸入【同意】繼續購票流程。 - if inferred_answer_string is None: - if '驗證碼' in formated_html_text or '驗證欄位' in formated_html_text: - if '已詳閱' in formated_html_text or '請詳閱' in formated_html_text: - if '輸入【同意】' in formated_html_text: - inferred_answer_string = '同意' - - if inferred_answer_string is None: - if len(question_text) > 0: - answer_list = get_answer_list_from_question_string(None, question_text) - else: - answer_list = [answer_list] - - return answer_list def fill_common_verify_form(driver, config_dict, inferred_answer_string, fail_list, input_text_css, next_step_button_css, submit_by_enter, check_input_interval): show_debug_message = True # debug. @@ -2923,7 +1719,7 @@ def fill_common_verify_form(driver, config_dict, inferred_answer_string, fail_li form_input_2 = form_input_list[1] is_multi_question_mode = False - answer_list = get_answer_list_from_user_guess_string(config_dict) + answer_list = util.get_answer_list_from_user_guess_string(config_dict, CONST_MAXBOT_ANSWER_ONLINE_FILE) if form_input_count == 1: is_do_press_next_button = True else: @@ -3035,31 +1831,6 @@ def fill_common_verify_form(driver, config_dict, inferred_answer_string, fail_li return is_answer_sent, fail_list -def get_answer_list_from_user_guess_string(config_dict): - local_array = [] - online_array = [] - - user_guess_string = config_dict["advanced"]["user_guess_string"] - if len(user_guess_string) > 0: - user_guess_string = format_config_keyword_for_json(user_guess_string) - try: - local_array = json.loads("["+ user_guess_string +"]") - except Exception as exc: - local_array = [] - - # load from internet. - user_guess_string = "" - if os.path.exists(CONST_MAXBOT_ANSWER_ONLINE_FILE): - with open(CONST_MAXBOT_ANSWER_ONLINE_FILE, "r") as text_file: - user_guess_string = text_file.readline() - if len(user_guess_string) > 0: - user_guess_string = format_config_keyword_for_json(user_guess_string) - try: - online_array = json.loads("["+ user_guess_string +"]") - except Exception as exc: - online_array = [] - - return local_array + online_array def ticketmaster_promo(driver, config_dict, fail_list): question_selector = '#promoBox' @@ -3082,10 +1853,10 @@ def tixcraft_input_check_code(driver, config_dict, fail_list, question_selector) if len(question_text) > 0: write_question_to_file(question_text) - answer_list = get_answer_list_from_user_guess_string(config_dict) + answer_list = util.get_answer_list_from_user_guess_string(config_dict, CONST_MAXBOT_ANSWER_ONLINE_FILE) if len(answer_list)==0: if config_dict["advanced"]["auto_guess_options"]: - answer_list = guess_tixcraft_question(driver, question_text) + answer_list = util.guess_tixcraft_question(driver, question_text) inferred_answer_string = "" for answer_item in answer_list: @@ -3336,7 +2107,7 @@ def tixcraft_auto_ocr(driver, ocr, away_from_keyboard_enable, previous_answer, C def tixcraft_ticket_main_agree(driver, config_dict): for i in range(3): - is_finish_checkbox_click = tixcraft_ticket_agree(driver, config_dict) + is_finish_checkbox_click = check_checkbox(driver, By.CSS_SELECTOR, '#TicketForm_agree') if is_finish_checkbox_click: break @@ -3379,7 +2150,7 @@ def get_tixcraft_ticket_select_by_keyword(driver, config_dict, area_keyword_item try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -3387,12 +2158,12 @@ def get_tixcraft_ticket_select_by_keyword(driver, config_dict, area_keyword_item break if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: # clean stop word. - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) is_append_this_row = False @@ -3401,7 +2172,7 @@ def get_tixcraft_ticket_select_by_keyword(driver, config_dict, area_keyword_item is_append_this_row = True area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_append_this_row = False break @@ -3447,7 +2218,7 @@ def get_tixcraft_ticket_select(driver, config_dict): is_need_refresh, matched_blocks = get_tixcraft_target_area(driver, config_dict, "") auto_select_mode = config_dict["area_auto_select"]["mode"] - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: try: form_select = target_area.find_element(By.TAG_NAME, 'select') @@ -3718,8 +2489,8 @@ def kktix_travel_price_list(driver, config_dict, kktix_area_auto_select_mode, kk kktix_area_keyword_1_and = kktix_area_keyword_array[1] # clean stop word. - kktix_area_keyword_1 = format_keyword_string(kktix_area_keyword_1) - kktix_area_keyword_1_and = format_keyword_string(kktix_area_keyword_1_and) + kktix_area_keyword_1 = util.format_keyword_string(kktix_area_keyword_1) + kktix_area_keyword_1_and = util.format_keyword_string(kktix_area_keyword_1_and) if show_debug_message: print('kktix_area_keyword_1:', kktix_area_keyword_1) @@ -3731,7 +2502,7 @@ def kktix_travel_price_list(driver, config_dict, kktix_area_auto_select_mode, kk try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: is_dom_ready = False if show_debug_message: @@ -3759,12 +2530,12 @@ def kktix_travel_price_list(driver, config_dict, kktix_area_auto_select_mode, kk row_text = "" if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: # clean stop word. - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) if len(row_text) > 0: if ticket_number > 1: @@ -3906,7 +2677,7 @@ def kktix_assign_ticket_number(driver, config_dict, kktix_area_keyword): is_need_refresh = False if is_dom_ready: if not is_ticket_number_assigned: - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not matched_blocks is None: if len(matched_blocks) == 0: @@ -4013,34 +2784,21 @@ def kktix_check_agree_checkbox(driver, config_dict): show_debug_message = True is_finish_checkbox_click = False - - agree_label = None - agree_checkbox = None + is_dom_ready = False try: - agree_label = driver.find_element(By.CSS_SELECTOR, 'label[for="person_agree_terms"]') - agree_checkbox = driver.find_element(By.CSS_SELECTOR, '#person_agree_terms') + html_body = driver.page_source + #print("html_body:",len(html_body)) + if len(html_body) > 0: + if not "{{'new.i_read_and_agree_to'" in html_body: + is_dom_ready = True except Exception as exc: - print("find person_agree_terms checkbox Exception") if show_debug_message: print(exc) pass - is_dom_ready = False - is_need_refresh = False - if not agree_checkbox is None and not agree_label is None: - checkbox_html = "" - try: - checkbox_html = agree_label.get_attribute('innerHTML').strip() - #print("agree_checkbox html:", checkbox_html) - if len(checkbox_html) > 0: - if not "{{'new.i_read_and_agree_to'" in checkbox_html: - is_dom_ready = True - except Exception as e: - #print(e) - pass - - is_finish_checkbox_click = force_check_checkbox(driver, agree_checkbox) - + if is_dom_ready: + is_finish_checkbox_click = check_checkbox(driver, By.CSS_SELECTOR, '#person_agree_terms') + #print("status:", is_dom_ready, is_finish_checkbox_click) return is_dom_ready, is_finish_checkbox_click @@ -4060,7 +2818,6 @@ def check_checkbox(driver, by, query): is_checkbox_checked = force_check_checkbox(driver, agree_checkbox) return is_checkbox_checked - def force_check_checkbox(driver, agree_checkbox): is_finish_checkbox_click = False if not agree_checkbox is None: @@ -4129,7 +2886,7 @@ def get_answer_string_from_web_date(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, re if show_debug_message: print("web_datetime:", web_datetime) - captcha_text_formatted = format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) + captcha_text_formatted = util.format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) if show_debug_message: print("captcha_text_formatted", captcha_text_formatted) @@ -4148,9 +2905,9 @@ def get_answer_string_from_web_date(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, re if CONST_INPUT_SYMBOL in right_part: right_part = right_part.split(CONST_INPUT_SYMBOL)[1] - number_text = find_continuous_number(right_part) + number_text = util.find_continuous_number(right_part) - my_anwser_formated = convert_string_to_pattern(number_text, dynamic_length=False) + my_anwser_formated = util.convert_string_to_pattern(number_text, dynamic_length=False) if my_anwser_formated == "[\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d]": my_datetime_foramted = "%Y%m%d" if my_anwser_formated == "[\\d][\\d][\\d][\\d]": @@ -4194,7 +2951,7 @@ def get_answer_string_from_web_date(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, re if my_hint_anwser[-1:]==check_char: my_hint_anwser = my_hint_anwser[:-1] - my_anwser_formated = convert_string_to_pattern(my_hint_anwser, dynamic_length=False) + my_anwser_formated = util.convert_string_to_pattern(my_hint_anwser, dynamic_length=False) if my_anwser_formated == "[\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d]": my_datetime_foramted = "%Y%m%d" if my_anwser_formated == "[\\d][\\d][\\d][\\d]/[\\d][\\d]/[\\d][\\d]": @@ -4255,7 +3012,7 @@ def get_answer_string_from_web_time(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, re if not registrationsNewApp_div is None: web_datetime = kktix_get_web_datetime(registrationsNewApp_div) if not web_datetime is None: - tmp_text = format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) + tmp_text = util.format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) my_datetime_foramted = None @@ -4281,7 +3038,7 @@ def get_answer_string_from_web_time(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, re if my_delimitor_symbol in my_hint_anwser: my_delimitor_index = my_hint_anwser.find(my_delimitor_symbol) my_hint_anwser = my_hint_anwser[:my_delimitor_index] - my_anwser_formated = convert_string_to_pattern(my_hint_anwser, dynamic_length=False) + my_anwser_formated = util.convert_string_to_pattern(my_hint_anwser, dynamic_length=False) #print("my_hint_anwser:", my_hint_anwser) #print("my_anwser_formated:", my_anwser_formated) if my_anwser_formated == "[\\d][\\d][\\d][\\d]": @@ -4312,47 +3069,6 @@ def get_answer_string_from_web_time(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, re return inferred_answer_string -def check_answer_keep_symbol(captcha_text_div_text): - is_need_keep_symbol = False - - # format text - keep_symbol_tmp = captcha_text_div_text - keep_symbol_tmp = keep_symbol_tmp.replace('也','須') - keep_symbol_tmp = keep_symbol_tmp.replace('必須','須') - - keep_symbol_tmp = keep_symbol_tmp.replace('全都','都') - keep_symbol_tmp = keep_symbol_tmp.replace('全部都','都') - - keep_symbol_tmp = keep_symbol_tmp.replace('一致','相同') - keep_symbol_tmp = keep_symbol_tmp.replace('一樣','相同') - keep_symbol_tmp = keep_symbol_tmp.replace('相等','相同') - - if '符號須都相同' in keep_symbol_tmp: - is_need_keep_symbol = True - - if '符號都相同' in keep_symbol_tmp: - is_need_keep_symbol = True - - if '符號須相同' in keep_symbol_tmp: - is_need_keep_symbol = True - - # for: 大小寫含括號需一模一樣 - keep_symbol_tmp = keep_symbol_tmp.replace('含', '') - keep_symbol_tmp = keep_symbol_tmp.replace('和', '') - keep_symbol_tmp = keep_symbol_tmp.replace('與', '') - keep_symbol_tmp = keep_symbol_tmp.replace('還有', '') - keep_symbol_tmp = keep_symbol_tmp.replace('及', '') - keep_symbol_tmp = keep_symbol_tmp.replace('以及', '') - keep_symbol_tmp = keep_symbol_tmp.replace('需', '') - keep_symbol_tmp = keep_symbol_tmp.replace('必須', '') - keep_symbol_tmp = keep_symbol_tmp.replace('而且', '') - keep_symbol_tmp = keep_symbol_tmp.replace('且', '') - keep_symbol_tmp = keep_symbol_tmp.replace('一模', '') - #print("keep_symbol_tmp:", keep_symbol_tmp) - if '大小寫括號相同' in keep_symbol_tmp: - is_need_keep_symbol = True - - return is_need_keep_symbol def get_answer_list_from_question_string(registrationsNewApp_div, captcha_text_div_text): show_debug_message = True # debug. @@ -4382,7 +3098,7 @@ def get_answer_list_from_question_string(registrationsNewApp_div, captcha_text_d is_use_quota_message = True #print("is_use_quota_message:" , is_use_quota_message) if is_use_quota_message: - temp_answer = find_between(captcha_text_div_text, "「", "」") + temp_answer = util.find_between(captcha_text_div_text, "「", "」") temp_answer = temp_answer.strip() if len(temp_answer) > 0: inferred_answer_string = temp_answer @@ -4391,7 +3107,7 @@ def get_answer_list_from_question_string(registrationsNewApp_div, captcha_text_d # 請在下方空白處輸入括號內數字 if inferred_answer_string is None: formated_html_text = captcha_text_div_text.strip() - formated_html_text = format_quota_string(formated_html_text) + formated_html_text = util.format_quota_string(formated_html_text) formated_html_text = formated_html_text.replace('請輸入','輸入') formated_html_text = formated_html_text.replace('的','') @@ -4420,14 +3136,14 @@ def get_answer_list_from_question_string(registrationsNewApp_div, captcha_text_d break if is_match_input_quota_text: - temp_answer = find_between(formated_html_text, "【", "】") + temp_answer = util.find_between(formated_html_text, "【", "】") temp_answer = temp_answer.strip() if len(temp_answer) > 0: temp_answer = temp_answer.replace(' ','') # check raw question. if '數字' in captcha_text_div_text: - temp_answer = normalize_chinese_numeric(temp_answer) + temp_answer = util.normalize_chinese_numeric(temp_answer) inferred_answer_string = temp_answer @@ -4440,7 +3156,7 @@ def get_answer_list_from_question_string(registrationsNewApp_div, captcha_text_d is_use_quota_message = True #print("is_use_quota_message:" , is_use_quota_message) if is_use_quota_message: - inferred_answer_string = find_between(captcha_text_div_text, "【", "】") + inferred_answer_string = util.find_between(captcha_text_div_text, "【", "】") inferred_answer_string = inferred_answer_string.strip() #print("find captcha text:" , inferred_answer_string) @@ -4491,7 +3207,7 @@ def get_answer_list_from_question_string(registrationsNewApp_div, captcha_text_d # still no answer. if inferred_answer_string is None: if not is_combine_two_question: - answer_list = get_answer_list_by_question(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) + answer_list = util.get_answer_list_by_question(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) if show_debug_message: print("guess answer list:", answer_list) else: @@ -4526,6 +3242,7 @@ def kktix_reg_captcha_question_text(captcha_inner_div): return question_text +# PS: no double check, NOW. def kktix_double_check_all_text_value(driver, ticket_number): is_do_press_next_button = False @@ -4567,14 +3284,14 @@ def get_kktix_control_label_text(driver): try: captcha_inner_div = driver.find_element(By.CSS_SELECTOR, 'div > div.code-input > div.control-group > label.control-label') if not captcha_inner_div is None: - question_text = remove_html_tags(captcha_inner_div.get_attribute('innerHTML')) + question_text = util.remove_html_tags(captcha_inner_div.get_attribute('innerHTML')) except Exception as exc: pass return question_text def set_kktix_control_label_text(driver, config_dict): fail_list = [] - answer_list = get_answer_list_from_user_guess_string(config_dict) + answer_list = util.get_answer_list_from_user_guess_string(config_dict, CONST_MAXBOT_ANSWER_ONLINE_FILE) inferred_answer_string = "" for answer_item in answer_list: if not answer_item in fail_list: @@ -4614,7 +3331,7 @@ def kktix_reg_captcha(driver, config_dict, fail_list, is_finish_checkbox_click, is_question_popup = True write_question_to_file(question_text) - answer_list = get_answer_list_from_user_guess_string(config_dict) + answer_list = util.get_answer_list_from_user_guess_string(config_dict, CONST_MAXBOT_ANSWER_ONLINE_FILE) if len(answer_list)==0: if config_dict["advanced"]["auto_guess_options"]: answer_list = get_answer_list_from_question_string(registrationsNewApp_div, question_text) @@ -4751,57 +3468,9 @@ def kktix_reg_new_main(driver, config_dict, fail_list, played_sound_ticket, is_f return fail_list, played_sound_ticket -def kktix_get_registerStatus(event_code): - html_result = None - - url = "https://kktix.com/g/events/%s/register_info" % (event_code) - #print('event_code:',event_code) - #print("url:", url) - - headers = {"Accept-Language": "zh-TW,zh;q=0.5", 'User-Agent': USER_AGENT} - try: - html_result = requests.get(url , headers=headers, timeout=0.7, allow_redirects=False) - except Exception as exc: - html_result = None - print("send reg_info request fail:") - print(exc) - - registerStatus = None - if not html_result is None: - status_code = html_result.status_code - #print("status_code:",status_code) - if status_code == 200: - html_text = html_result.text - #print("html_text:", html_text) - try: - jsLoads = json.loads(html_text) - if 'inventory' in jsLoads: - if 'registerStatus' in jsLoads['inventory']: - registerStatus = jsLoads['inventory']['registerStatus'] - except Exception as exc: - print("load reg_info json fail:") - print(exc) - pass - - #print("registerStatus:", registerStatus) - return registerStatus - -def kktix_get_event_code(url): - event_code = "" - if '/registrations/new' in url: - prefix_list = ['.com/events/','.cc/events/'] - postfix = '/registrations/new' - - for prefix in prefix_list: - event_code = find_between(url,prefix,postfix) - if len(event_code) > 0: - break - - #print('event_code:',event_code) - return event_code def kktix_check_register_status(driver, url): - event_code = kktix_get_event_code(url) + event_code = util.kktix_get_event_code(url) if len(event_code) > 0: js = ''' function load_kktix_register_code(){ @@ -4843,7 +3512,7 @@ if (typeof $.kkUser.checked_status_register_code === 'undefined') { # use javascritp version only. is_match_event_code = False if is_match_event_code: - registerStatus = kktix_get_registerStatus(event_code) + registerStatus = util.kktix_get_registerStatus(event_code) return registerStatus def kktix_reg_auto_reload(driver, url, config_dict): @@ -4873,7 +3542,7 @@ def get_fami_target_area(driver, config_dict, area_keyword_item): show_debug_message = True date_keyword = config_dict["date_auto_select"]["date_keyword"].strip() - date_keyword = format_keyword_string(date_keyword) + date_keyword = util.format_keyword_string(date_keyword) auto_select_mode = config_dict["area_auto_select"]["mode"] @@ -4935,17 +3604,17 @@ def get_fami_target_area(driver, config_dict, area_keyword_item): td_date = row.find_element(By.CSS_SELECTOR, my_css_selector) if not td_date is None: #print("date:", td_date.text) - date_html_text = format_keyword_string(td_date.text) + date_html_text = util.format_keyword_string(td_date.text) my_css_selector = "td:nth-child(2)" td_area = row.find_element(By.CSS_SELECTOR, my_css_selector) if not td_area is None: #print("area:", td_area.text) - area_html_text = format_keyword_string(td_area.text) + area_html_text = util.format_keyword_string(td_area.text) #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -4953,7 +3622,7 @@ def get_fami_target_area(driver, config_dict, area_keyword_item): break if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: @@ -4974,7 +3643,7 @@ def get_fami_target_area(driver, config_dict, area_keyword_item): is_match_area = True area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_match_area = False break @@ -5014,10 +3683,10 @@ def fami_verify(driver, config_dict, fail_list): if True: #write_question_to_file(question_text) - answer_list = get_answer_list_from_user_guess_string(config_dict) + answer_list = util.get_answer_list_from_user_guess_string(config_dict, CONST_MAXBOT_ANSWER_ONLINE_FILE) if len(answer_list)==0: if config_dict["advanced"]["auto_guess_options"]: - answer_list = guess_tixcraft_question(driver, question_text) + answer_list = util.guess_tixcraft_question(driver, question_text) inferred_answer_string = "" for answer_item in answer_list: @@ -5124,7 +3793,7 @@ def fami_date_auto_select(driver, config_dict, last_activity_url): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -5153,7 +3822,7 @@ def fami_date_auto_select(driver, config_dict, last_activity_url): if show_debug_message: print("start to match keyword:", date_keyword) - matched_blocks = get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) + matched_blocks = util.get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) if show_debug_message: if not matched_blocks is None: @@ -5165,7 +3834,7 @@ def fami_date_auto_select(driver, config_dict, last_activity_url): print("date date-time-position is None") pass - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) is_date_assign_by_bot = False if not target_area is None: is_button_clicked = False @@ -5252,7 +3921,7 @@ def fami_area_auto_select(driver, config_dict, area_keyword_item): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -5266,7 +3935,7 @@ def fami_area_auto_select(driver, config_dict, area_keyword_item): row_text = "" if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: @@ -5299,7 +3968,7 @@ def fami_area_auto_select(driver, config_dict, area_keyword_item): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -5307,7 +3976,7 @@ def fami_area_auto_select(driver, config_dict, area_keyword_item): break if len(row_text) > 0: - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) if show_debug_message: print("row_text:", row_text) @@ -5318,7 +3987,7 @@ def fami_area_auto_select(driver, config_dict, area_keyword_item): is_match_area = True area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_match_area = False break @@ -5336,7 +4005,7 @@ def fami_area_auto_select(driver, config_dict, area_keyword_item): if show_debug_message: print("after match keyword, found count:", len(matched_blocks)) - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not matched_blocks is None: if len(matched_blocks) == 0: is_need_refresh = True @@ -5541,7 +4210,7 @@ def fami_home_auto_select(driver, config_dict, last_activity_url): matched_blocks = get_fami_target_area(driver, config_dict, "") auto_select_mode = config_dict["area_auto_select"]["mode"] - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: el_btn = None is_visible = False @@ -5631,7 +4300,7 @@ def urbtix_date_auto_select(driver, auto_select_mode, date_keyword, auto_reload_ try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -5641,7 +4310,7 @@ def urbtix_date_auto_select(driver, auto_select_mode, date_keyword, auto_reload_ if len(row_text) > 0: if show_debug_message: print("row_text:", row_text) - is_match_area = is_row_match_keyword(date_keyword, row_text) + is_match_area = util.is_row_match_keyword(date_keyword, row_text) if is_match_area: matched_blocks.append(row) @@ -5660,7 +4329,7 @@ def urbtix_date_auto_select(driver, auto_select_mode, date_keyword, auto_reload_ print("date date-time-position is None") pass - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: el_btn = None try: @@ -5760,7 +4429,7 @@ def urbtix_area_auto_select(driver, config_dict, area_keyword_item): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -5768,7 +4437,7 @@ def urbtix_area_auto_select(driver, config_dict, area_keyword_item): break if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: @@ -5817,7 +4486,7 @@ def urbtix_area_auto_select(driver, config_dict, area_keyword_item): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -5825,7 +4494,7 @@ def urbtix_area_auto_select(driver, config_dict, area_keyword_item): break if len(row_text) > 0: - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) if show_debug_message: print("row_text:", row_text) @@ -5836,7 +4505,7 @@ def urbtix_area_auto_select(driver, config_dict, area_keyword_item): is_match_area = True area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_match_area = False break @@ -5858,7 +4527,7 @@ def urbtix_area_auto_select(driver, config_dict, area_keyword_item): matched_blocks = None is_need_refresh = True - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: try: if target_area.is_enabled(): @@ -6100,7 +4769,6 @@ def urbtix_performance(driver, config_dict): if show_debug_message: print("is_ticket_number_assigned:", is_ticket_number_assigned) - return ret @@ -6159,7 +4827,7 @@ def cityline_date_auto_select(driver, auto_select_mode, date_keyword, auto_reloa try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -6169,7 +4837,7 @@ def cityline_date_auto_select(driver, auto_select_mode, date_keyword, auto_reloa if len(row_text) > 0: if show_debug_message: print("row_text:", row_text) - is_match_area = is_row_match_keyword(date_keyword, row_text) + is_match_area = util.is_row_match_keyword(date_keyword, row_text) if is_match_area: matched_blocks.append(row) @@ -6186,7 +4854,7 @@ def cityline_date_auto_select(driver, auto_select_mode, date_keyword, auto_reloa print("date date-time-position is None") pass - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: try: if target_area.is_enabled(): @@ -6293,7 +4961,7 @@ def cityline_area_auto_select(driver, config_dict, area_keyword_item): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -6301,11 +4969,11 @@ def cityline_area_auto_select(driver, config_dict, area_keyword_item): break if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) if show_debug_message: print("row_text:", row_text) @@ -6316,7 +4984,7 @@ def cityline_area_auto_select(driver, config_dict, area_keyword_item): is_match_area = True area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_match_area = False break @@ -6337,7 +5005,7 @@ def cityline_area_auto_select(driver, config_dict, area_keyword_item): matched_blocks = None is_need_refresh = True - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: el_btn = None try: @@ -6649,7 +5317,7 @@ def ibon_date_auto_select(driver, config_dict): if show_debug_message: print("start to match keyword:", date_keyword) - matched_blocks = get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) + matched_blocks = util.get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) if show_debug_message: if not matched_blocks is None: @@ -6661,7 +5329,7 @@ def ibon_date_auto_select(driver, config_dict): print("date date-time-position is None") pass - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) is_date_assign_by_bot = False if not target_area is None: is_button_clicked = False @@ -6752,7 +5420,7 @@ def ibon_area_auto_select(driver, config_dict, area_keyword_item): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -6779,7 +5447,7 @@ def ibon_area_auto_select(driver, config_dict, area_keyword_item): row_text="" if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.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. @@ -6843,7 +5511,7 @@ def ibon_area_auto_select(driver, config_dict, area_keyword_item): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -6851,7 +5519,7 @@ def ibon_area_auto_select(driver, config_dict, area_keyword_item): break if len(row_text) > 0: - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) if show_debug_message: print("row_text:", row_text) @@ -6862,7 +5530,7 @@ def ibon_area_auto_select(driver, config_dict, area_keyword_item): is_match_area = True area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_match_area = False break @@ -6880,7 +5548,7 @@ def ibon_area_auto_select(driver, config_dict, area_keyword_item): if show_debug_message: print("after match keyword, found count:", len(matched_blocks)) - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not matched_blocks is None: if len(matched_blocks) == 0: @@ -7428,27 +6096,9 @@ def hkticketing_login(driver, account, password): return ret def play_sound_while_ordering(config_dict): - app_root = get_app_root() + app_root = util.get_app_root() captcha_sound_filename = os.path.join(app_root, config_dict["advanced"]["play_sound"]["filename"].strip()) - play_mp3_async(captcha_sound_filename) - -def play_mp3_async(sound_filename): - import threading - threading.Thread(target=play_mp3, args=(sound_filename,), daemon=True).start() - -def play_mp3(sound_filename): - try: - from playsound import playsound - playsound(sound_filename) - except Exception as exc: - msg=str(exc) - #print("play sound exeption:", msg) - if platform.system() == 'Windows': - import winsound - try: - winsound.PlaySound(sound_filename, winsound.SND_FILENAME) - except Exception as exc2: - pass + util.play_mp3_async(captcha_sound_filename) # purpose: check alert poped. # PS: current version not enable... @@ -7702,7 +6352,7 @@ def ticketmaster_captcha(driver, config_dict, ocr, Captcha_Browser, domain_name) ocr_captcha_image_source = config_dict["ocr_captcha"]["image_source"] for i in range(2): - is_finish_checkbox_click = tixcraft_ticket_agree(driver, config_dict) + is_finish_checkbox_click = check_checkbox(driver, By.CSS_SELECTOR, '#TicketForm_agree') if is_finish_checkbox_click: break @@ -7853,7 +6503,7 @@ def kktix_paused_main(driver, url, config_dict, kktix_dict): kktix_account = config_dict["advanced"]["kktix_account"] kktix_password = config_dict["advanced"]["kktix_password_plaintext"].strip() if kktix_password == "": - kktix_password = decryptMe(config_dict["advanced"]["kktix_password"]) + kktix_password = util.decryptMe(config_dict["advanced"]["kktix_password"]) if len(kktix_account) > 4: kktix_login(driver, kktix_account, kktix_password) is_url_contain_sign_in = True @@ -7887,7 +6537,7 @@ def kktix_main(driver, url, config_dict, kktix_dict): kktix_account = config_dict["advanced"]["kktix_account"] kktix_password = config_dict["advanced"]["kktix_password_plaintext"].strip() if kktix_password == "": - kktix_password = decryptMe(config_dict["advanced"]["kktix_password"]) + kktix_password = util.decryptMe(config_dict["advanced"]["kktix_password"]) if len(kktix_account) > 0: kktix_login(driver, kktix_account, kktix_password) is_url_contain_sign_in = True @@ -7961,7 +6611,7 @@ def kktix_main(driver, url, config_dict, kktix_dict): kktix_account = config_dict["advanced"]["kktix_account"] kktix_password = config_dict["advanced"]["kktix_password_plaintext"].strip() if kktix_password == "": - kktix_password = decryptMe(config_dict["advanced"]["kktix_password"]) + kktix_password = util.decryptMe(config_dict["advanced"]["kktix_password"]) print("基本資料(或實名制)網址:", url) if len(kktix_account) > 0: @@ -8002,7 +6652,7 @@ def famiticket_main(driver, url, config_dict, fami_dict): fami_account = config_dict["advanced"]["fami_account"] fami_password = config_dict["advanced"]["fami_password_plaintext"].strip() if fami_password == "": - fami_password = decryptMe(config_dict["advanced"]["fami_password"]) + fami_password = util.decryptMe(config_dict["advanced"]["fami_password"]) if len(fami_account) > 4: fami_login(driver, fami_account, fami_password) @@ -8060,12 +6710,13 @@ def urbtix_performance_confirm_dialog_popup(driver): return ret +# PS: NOW not able to use, due to open question not able to fill by stupid program. def get_urbtix_survey_answer_by_question(question_text): show_debug_message = True # debug. show_debug_message = False # online question_text = question_text.replace(' ',' ') - question_text = full2half(question_text) + question_text = util.full2half(question_text) seq = 0 if '第' in question_text and '個' in question_text: @@ -8075,7 +6726,7 @@ def get_urbtix_survey_answer_by_question(question_text): if seq_string.isdigit(): seq = int(seq_string) else: - tmp_seq = chinese_numeric_to_int(seq_string) + tmp_seq = util.chinese_numeric_to_int(seq_string) if not tmp_seq is None: seq = tmp_seq @@ -8122,8 +6773,7 @@ def get_urbtix_survey_answer_by_question(question_text): question_text_formated = question_text_formated.replace(',','') question_answer_char = "" - option_text_string = find_continuous_text(question_text_formated) - + option_text_string = util.find_continuous_text(question_text_formated) if show_debug_message: print("option_text_string:", option_text_string) @@ -8149,7 +6799,7 @@ def get_urbtix_survey_answer_by_question(question_text): if count_target_string.isdigit(): count_target = int(count_target_string) else: - count_target = chinese_numeric_to_int(count_target_string) + count_target = util.chinese_numeric_to_int(count_target_string) if not count_target is None: for char in option_text_string: @@ -8211,10 +6861,10 @@ def urbtix_auto_survey(driver, config_dict): if option_content_div is None: option_content_div="" option_content_div_text = option_content_div_text.strip() - option_content_div_text = full2half(option_content_div_text) + option_content_div_text = util.full2half(option_content_div_text) if question_direction in ['left','right']: - for answer_item in synonym_dict(question_answer_char): + for answer_item in util.synonym_dict(question_answer_char): if answer_item in option_content_div_text: is_radio_clicked = force_press_button(each_option_div, By.CSS_SELECTOR, 'div.radio-wrapper') if is_radio_clicked: @@ -8224,7 +6874,7 @@ def urbtix_auto_survey(driver, config_dict): break if question_direction == "count": - for answer_item in synonym_dict(question_answer_char): + for answer_item in util.synonym_dict(question_answer_char): if answer_item in option_content_div_text: is_radio_clicked = force_press_button(each_option_div, By.CSS_SELECTOR, 'div.radio-wrapper') if is_radio_clicked: @@ -8250,7 +6900,7 @@ def urbtix_auto_survey(driver, config_dict): int_answer_char = int(question_answer_char) if int_answer_char > 1: for i in range(int_answer_char-1): - for answer_item in synonym_dict(str(i+1)): + for answer_item in util.synonym_dict(str(i+1)): is_match_more_then = False if answer_item + '個或以上' in option_content_div_text: is_match_more_then = True @@ -8362,7 +7012,7 @@ def urbtix_main(driver, url, config_dict): urbtix_account = config_dict["advanced"]["urbtix_account"] urbtix_password = config_dict["advanced"]["urbtix_password_plaintext"].strip() if urbtix_password == "": - urbtix_password = decryptMe(config_dict["advanced"]["urbtix_password"]) + urbtix_password = util.decryptMe(config_dict["advanced"]["urbtix_password"]) if len(urbtix_account) > 4: urbtix_login(driver, urbtix_account, urbtix_password) @@ -8505,7 +7155,7 @@ def cityline_input_code(driver, config_dict, fail_list): answer_list = [] - answer_list = get_answer_list_from_user_guess_string(config_dict) + answer_list = util.get_answer_list_from_user_guess_string(config_dict, CONST_MAXBOT_ANSWER_ONLINE_FILE) inferred_answer_string = "" for answer_item in answer_list: @@ -8563,7 +7213,7 @@ def cityline_main(driver, url, config_dict): cityline_account = config_dict["advanced"]["cityline_account"] cityline_password = config_dict["advanced"]["cityline_password_plaintext"].strip() if cityline_password == "": - cityline_password = decryptMe(config_dict["advanced"]["cityline_password"]) + cityline_password = util.decryptMe(config_dict["advanced"]["cityline_password"]) if len(cityline_account) > 4: cityline_login(driver, cityline_account, cityline_password) return @@ -8636,7 +7286,7 @@ def ibon_verification_question(driver, fail_list, config_dict): if len(question_text) > 0: write_question_to_file(question_text) - answer_list = get_answer_list_from_user_guess_string(config_dict) + answer_list = util.get_answer_list_from_user_guess_string(config_dict, CONST_MAXBOT_ANSWER_ONLINE_FILE) if len(answer_list)==0: if config_dict["advanced"]["auto_guess_options"]: answer_list = get_answer_list_from_question_string(None, question_text) @@ -9183,7 +7833,7 @@ def hkticketing_date_assign(driver, config_dict): matched_blocks = None # clean stop word. - date_keyword = format_keyword_string(date_keyword) + date_keyword = util.format_keyword_string(date_keyword) date_keyword_and = "" form_select = None @@ -9251,7 +7901,7 @@ def hkticketing_date_assign(driver, config_dict): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -9290,7 +7940,7 @@ def hkticketing_date_assign(driver, config_dict): if show_debug_message: print("start to match keyword:", date_keyword) - matched_blocks = get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) + matched_blocks = util.get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) if show_debug_message: if not matched_blocks is None: @@ -9302,7 +7952,7 @@ def hkticketing_date_assign(driver, config_dict): print("date date-time-position is None") pass - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: try: if target_area.is_enabled(): @@ -9344,7 +7994,7 @@ def hkticketing_date_password_input(driver, config_dict, fail_list): local_array = [] user_guess_string = config_dict["advanced"]["user_guess_string"] if len(user_guess_string) > 0: - user_guess_string = format_config_keyword_for_json(user_guess_string) + user_guess_string = util.format_config_keyword_for_json(user_guess_string) try: local_array = json.loads("["+ user_guess_string +"]") except Exception as exc: @@ -9533,7 +8183,7 @@ def hkticketing_area_auto_select(driver, config_dict, area_keyword_item): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -9541,11 +8191,11 @@ def hkticketing_area_auto_select(driver, config_dict, area_keyword_item): break if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) if show_debug_message: print("row_text:", row_text) @@ -9555,7 +8205,7 @@ def hkticketing_area_auto_select(driver, config_dict, area_keyword_item): is_match_area = True area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_match_area = False break @@ -9576,7 +8226,7 @@ def hkticketing_area_auto_select(driver, config_dict, area_keyword_item): matched_blocks = None is_need_refresh = True - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: try: if target_area.is_enabled(): @@ -10037,7 +8687,7 @@ def softix_powerweb_main(driver, url, config_dict, hkticketing_dict): hkticketing_account = config_dict["advanced"]["hkticketing_account"].strip() hkticketing_password = config_dict["advanced"]["hkticketing_password_plaintext"].strip() if hkticketing_password == "": - hkticketing_password = decryptMe(config_dict["advanced"]["hkticketing_password"]) + hkticketing_password = util.decryptMe(config_dict["advanced"]["hkticketing_password"]) if len(hkticketing_account) > 4: hkticketing_login(driver, hkticketing_account, hkticketing_password) @@ -10152,7 +8802,7 @@ def hkam_date_auto_select(driver, domain_name, config_dict): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -10160,7 +8810,7 @@ def hkam_date_auto_select(driver, domain_name, config_dict): break if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: @@ -10227,7 +8877,7 @@ def hkam_date_auto_select(driver, domain_name, config_dict): if show_debug_message: print("start to match keyword:", date_keyword) - matched_blocks = get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) + matched_blocks = util.get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) if show_debug_message: if not matched_blocks is None: @@ -10239,7 +8889,7 @@ def hkam_date_auto_select(driver, domain_name, config_dict): print("date date-time-position is None") pass - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) is_date_assign_by_bot = False if not target_area is None: is_button_clicked = False @@ -10377,7 +9027,7 @@ def kham_area_auto_select(driver, domain_name, config_dict, area_keyword_item): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -10396,7 +9046,7 @@ def kham_area_auto_select(driver, domain_name, config_dict, area_keyword_item): pass if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" # check ticket_number and available count. @@ -10410,7 +9060,7 @@ def kham_area_auto_select(driver, domain_name, config_dict, area_keyword_item): td_array = row_html.split(" 0: td_target = " 0: - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) if show_debug_message: print("row_text:", row_text) @@ -10433,7 +9083,7 @@ def kham_area_auto_select(driver, domain_name, config_dict, area_keyword_item): # match keyword. area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_match_area = False break @@ -10453,7 +9103,7 @@ def kham_area_auto_select(driver, domain_name, config_dict, area_keyword_item): matched_blocks = None is_need_refresh = True - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: try: if not("udnfunlife" in domain_name): @@ -11000,7 +9650,7 @@ def kham_main(driver, url, config_dict, ocr, Captcha_Browser): udn_account = config_dict["advanced"]["udn_account"] udn_password = config_dict["advanced"]["udn_password_plaintext"].strip() if udn_password == "": - udn_password = decryptMe(config_dict["advanced"]["udn_password"]) + udn_password = util.decryptMe(config_dict["advanced"]["udn_password"]) if len(udn_account) > 4: udn_login(driver, udn_account, udn_password) @@ -11169,7 +9819,7 @@ def kham_main(driver, url, config_dict, ocr, Captcha_Browser): kham_account = config_dict["advanced"]["kham_account"] kham_password = config_dict["advanced"]["kham_password_plaintext"].strip() if kham_password == "": - kham_password = decryptMe(config_dict["advanced"]["kham_password"]) + kham_password = util.decryptMe(config_dict["advanced"]["kham_password"]) if len(kham_account) > 4: kham_login(driver, kham_account, kham_password) @@ -11177,7 +9827,7 @@ def kham_main(driver, url, config_dict, ocr, Captcha_Browser): ticket_account = config_dict["advanced"]["ticket_account"] ticket_password = config_dict["advanced"]["ticket_password_plaintext"].strip() if ticket_password == "": - ticket_password = decryptMe(config_dict["advanced"]["ticket_password"]) + ticket_password = util.decryptMe(config_dict["advanced"]["ticket_password"]) if len(ticket_account) > 4: ticket_login(driver, ticket_account, ticket_password) @@ -11239,7 +9889,7 @@ def ticketplus_date_auto_select(driver, config_dict): try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -11247,7 +9897,7 @@ def ticketplus_date_auto_select(driver, config_dict): break if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: @@ -11283,11 +9933,11 @@ def ticketplus_date_auto_select(driver, config_dict): matched_blocks = formated_area_list else: # match keyword. - date_keyword = format_keyword_string(date_keyword) + date_keyword = util.format_keyword_string(date_keyword) if show_debug_message: print("start to match formated keyword:", date_keyword) - matched_blocks = get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) + matched_blocks = util.get_matched_blocks_by_keyword(config_dict, auto_select_mode, date_keyword, formated_area_list) if show_debug_message: if not matched_blocks is None: @@ -11301,7 +9951,7 @@ def ticketplus_date_auto_select(driver, config_dict): is_date_clicked = False if is_vue_ready: - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not target_area is None: target_button = None try: @@ -11488,7 +10138,7 @@ def ticketplus_order_expansion_auto_select(driver, config_dict, area_keyword_ite try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -11523,7 +10173,7 @@ def ticketplus_order_expansion_auto_select(driver, config_dict, area_keyword_ite row_text = "" if len(row_text) > 0: - if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + if util.reset_row_text_if_match_keyword_exclude(config_dict, row_text): row_text = "" if len(row_text) > 0: @@ -11562,7 +10212,7 @@ def ticketplus_order_expansion_auto_select(driver, config_dict, area_keyword_ite try: #row_text = row.text row_html = row.get_attribute('innerHTML') - row_text = remove_html_tags(row_html) + row_text = util.remove_html_tags(row_html) except Exception as exc: if show_debug_message: print(exc) @@ -11570,7 +10220,7 @@ def ticketplus_order_expansion_auto_select(driver, config_dict, area_keyword_ite break if len(row_text) > 0: - row_text = format_keyword_string(row_text) + row_text = util.format_keyword_string(row_text) if show_debug_message: print("row_text:", row_text) @@ -11581,7 +10231,7 @@ def ticketplus_order_expansion_auto_select(driver, config_dict, area_keyword_ite is_match_area = True area_keyword_array = area_keyword_item.split(' ') for area_keyword in area_keyword_array: - area_keyword = format_keyword_string(area_keyword) + area_keyword = util.format_keyword_string(area_keyword) if not area_keyword in row_text: is_match_area = False break @@ -11604,7 +10254,7 @@ def ticketplus_order_expansion_auto_select(driver, config_dict, area_keyword_ite matched_blocks = None is_need_refresh = True - target_area = get_target_item_from_matched_list(matched_blocks, auto_select_mode) + target_area = util.get_target_item_from_matched_list(matched_blocks, auto_select_mode) if not matched_blocks is None: if len(matched_blocks) == 0: is_need_refresh = True @@ -11739,10 +10389,10 @@ def ticketplus_order_exclusive_code(driver, config_dict, fail_list): is_question_popup = True write_question_to_file(question_text) - answer_list = get_answer_list_from_user_guess_string(config_dict) + answer_list = util.get_answer_list_from_user_guess_string(config_dict, CONST_MAXBOT_ANSWER_ONLINE_FILE) if len(answer_list)==0: if config_dict["advanced"]["auto_guess_options"]: - answer_list = guess_tixcraft_question(driver, question_text) + answer_list = util.guess_tixcraft_question(driver, question_text) inferred_answer_string = "" for answer_item in answer_list: @@ -12320,7 +10970,7 @@ def ticketplus_account_sign_in(driver, config_dict): if not inputed_text is None: ticketplus_password = config_dict["advanced"]["ticketplus_password_plaintext"].strip() if ticketplus_password == "": - ticketplus_password = decryptMe(config_dict["advanced"]["ticketplus_password"]) + ticketplus_password = util.decryptMe(config_dict["advanced"]["ticketplus_password"]) if len(inputed_text) == 0: el_pass.click() @@ -12803,7 +11453,7 @@ def main(args): facebook_account = config_dict["advanced"]["facebook_account"].strip() facebook_password = config_dict["advanced"]["facebook_password_plaintext"].strip() if facebook_password == "": - facebook_password = decryptMe(config_dict["advanced"]["facebook_password"]) + facebook_password = util.decryptMe(config_dict["advanced"]["facebook_password"]) if len(facebook_account) > 4: facebook_login(driver, facebook_account, facebook_password) diff --git a/config_launcher.py b/config_launcher.py index 6cb716c..f99e2b1 100644 --- a/config_launcher.py +++ b/config_launcher.py @@ -23,7 +23,9 @@ import sys import threading import webbrowser -CONST_APP_VERSION = "MaxBot (2024.03.19)" +import util + +CONST_APP_VERSION = "MaxBot (2024.03.20)" CONST_MAXBOT_LAUNCHER_FILE = "config_launcher.json" CONST_MAXBOT_CONFIG_FILE = "settings.json" @@ -134,16 +136,6 @@ def load_translate(): translate['ja_jp']=ja_jp return translate -def get_app_root(): - app_root = "" - if hasattr(sys, 'frozen'): - basis = sys.executable - app_root = os.path.dirname(basis) - else: - app_root = os.getcwd() - return app_root - - def get_default_config(): config_dict={} @@ -154,9 +146,8 @@ def get_default_config(): return config_dict - def load_json(): - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_LAUNCHER_FILE) config_dict = None @@ -168,7 +159,7 @@ def load_json(): return config_filepath, config_dict def btn_restore_defaults_clicked(language_code): - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_LAUNCHER_FILE) if os.path.exists(str(config_filepath)): try: @@ -187,7 +178,7 @@ def btn_save_clicked(): btn_save_act() def btn_save_act(slience_mode=True): - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_LAUNCHER_FILE) config_dict = get_default_config() @@ -213,18 +204,13 @@ def btn_save_act(slience_mode=True): # save config. if is_all_data_correct: # slience - save_json(config_dict, config_filepath) + util.save_json(config_dict, config_filepath) if not slience_mode: messagebox.showinfo(translate[language_code]["save"], translate[language_code]["done"]) return is_all_data_correct -def save_json(config_dict, target_path): - json_str = json.dumps(config_dict, indent=4) - with open(target_path, 'w') as outfile: - outfile.write(json_str) - def open_url(url): webbrowser.open_new(url) diff --git a/kktix_signout.py b/kktix_signout.py index 978f132..42ef894 100644 --- a/kktix_signout.py +++ b/kktix_signout.py @@ -1,49 +1,25 @@ #!/usr/bin/env python #encoding=utf-8 import argparse +import asyncio import base64 import json import os import sys import time + +import nodriver as uc import requests -import asyncio -import nodriver as uc +import util -CONST_APP_VERSION = "MaxBot (2024.03.19)" +CONST_APP_VERSION = "MaxBot (2024.03.20)" CONST_MAXBOT_CONFIG_FILE = "settings.json" USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" - -def sx(s1): - key=18 - return ''.join(chr(ord(a) ^ key) for a in s1) - -def decryptMe(b): - s="" - if(len(b)>0): - s=sx(base64.b64decode(b).decode("UTF-8")) - return s - -def encryptMe(s): - data="" - if(len(s)>0): - data=base64.b64encode(sx(s).encode('UTF-8')).decode("UTF-8") - return data - -def get_app_root(): - app_root = "" - if hasattr(sys, 'frozen'): - basis = sys.executable - app_root = os.path.dirname(basis) - else: - app_root = os.getcwd() - return app_root - def load_json(): - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_CONFIG_FILE) config_dict = None @@ -161,7 +137,7 @@ async def kktix_account_loop(config_dict): kktix_account = config_dict["advanced"]["kktix_account"] kktix_password = config_dict["advanced"]["kktix_password_plaintext"].strip() if kktix_password == "": - kktix_password = decryptMe(config_dict["advanced"]["kktix_password"]) + kktix_password = util.decryptMe(config_dict["advanced"]["kktix_password"]) print("kktix_account:", kktix_account) #print("kktix_password:", kktix_password) diff --git a/kktix_status.py b/kktix_status.py index acb6bfe..0d31e4b 100644 --- a/kktix_status.py +++ b/kktix_status.py @@ -27,9 +27,9 @@ import time import webbrowser from datetime import datetime -import requests +import util -CONST_APP_VERSION = "MaxBot (2024.03.19)" +CONST_APP_VERSION = "MaxBot (2024.03.20)" CONST_MAXBOT_CONFIG_FILE = "settings.json" CONST_MAXBOT_KKTIX_CONFIG_FILE = "kktix.json" @@ -46,8 +46,6 @@ URL_CHROME_DRIVER = 'https://chromedriver.chromium.org/' URL_FIREFOX_DRIVER = 'https://github.com/mozilla/geckodriver/releases' URL_EDGE_DRIVER = 'https://developer.microsoft.com/zh-tw/microsoft-edge/tools/webdriver/' -USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" - def load_translate(): translate = {} en_us={} @@ -96,37 +94,9 @@ def load_translate(): translate['ja_jp']=ja_jp return translate -# common functions. -def find_between( s, first, last ): - ret = "" - try: - start = s.index( first ) + len( first ) - end = s.index( last, start ) - ret = s[start:end] - except ValueError: - pass - return ret - -def t_or_f(arg): - ret = False - ua = str(arg).upper() - if 'TRUE'.startswith(ua): - ret = True - elif 'YES'.startswith(ua): - ret = True - return ret - -def get_app_root(): - app_root = "" - if hasattr(sys, 'frozen'): - basis = sys.executable - app_root = os.path.dirname(basis) - else: - app_root = os.getcwd() - return app_root def load_json(): - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_KKTIX_CONFIG_FILE) config_dict = None @@ -138,7 +108,7 @@ def load_json(): return config_filepath, config_dict def btn_restore_defaults_clicked(language_code): - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_KKTIX_CONFIG_FILE) if os.path.exists(str(config_filepath)): try: @@ -157,32 +127,15 @@ def btn_preview_sound_clicked(): global txt_play_sound_filename new_sound_filename = txt_play_sound_filename.get().strip() #print("new_sound_filename:", new_sound_filename) - app_root = get_app_root() + app_root = util.get_app_root() new_sound_filename = os.path.join(app_root, new_sound_filename) - play_mp3_async(new_sound_filename) - -def play_mp3_async(sound_filename): - threading.Thread(target=play_mp3, args=(sound_filename,)).start() - -def play_mp3(sound_filename): - from playsound import playsound - try: - playsound(sound_filename) - except Exception as exc: - msg=str(exc) - print("play sound exeption:", msg) - if platform.system() == 'Windows': - import winsound - try: - winsound.PlaySound(sound_filename, winsound.SND_FILENAME) - except Exception as exc2: - pass + util.play_mp3_async(new_sound_filename) def btn_save_clicked(): btn_save_act() def get_config_dict_from_ui(): - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_KKTIX_CONFIG_FILE) config_dict = get_default_config() @@ -236,18 +189,13 @@ def btn_save_act(slience_mode=True): is_all_data_correct, config_dict = get_config_dict_from_ui() # slience - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_KKTIX_CONFIG_FILE) - save_json(config_dict, config_filepath) + util.save_json(config_dict, config_filepath) if not slience_mode: messagebox.showinfo(translate[language_code]["save"], translate[language_code]["done"]) -def save_json(config_dict, target_path): - json_str = json.dumps(config_dict, indent=4) - with open(target_path, 'w') as outfile: - outfile.write(json_str) - def open_url(url): webbrowser.open_new(url) @@ -758,7 +706,7 @@ def get_default_config(): config_dict={} config_dict["list"] = [CONST_MAXBOT_CONFIG_FILE] - config_dict["check_interval"]=3 + config_dict["check_interval"]=1 config_dict["url"]="" config_dict["advanced"] = {} @@ -832,55 +780,6 @@ def main_gui(): root.mainloop() -def kktix_get_registerStatus(event_code): - html_result = None - - url = "https://kktix.com/g/events/%s/register_info" % (event_code) - #print('event_code:',event_code) - #print("url:", url) - - headers = {"Accept-Language": "zh-TW,zh;q=0.5", 'User-Agent': USER_AGENT} - try: - html_result = requests.get(url , headers=headers, timeout=0.7, allow_redirects=False) - except Exception as exc: - html_result = None - print("send reg_info request fail:") - print(exc) - - registerStatus = "" - if not html_result is None: - status_code = html_result.status_code - #print("status_code:",status_code) - if status_code == 200: - html_text = html_result.text - #print("html_text:", html_text) - try: - jsLoads = json.loads(html_text) - if 'inventory' in jsLoads: - if 'registerStatus' in jsLoads['inventory']: - registerStatus = jsLoads['inventory']['registerStatus'] - except Exception as exc: - print("load reg_info json fail:") - print(exc) - pass - - #print("registerStatus:", registerStatus) - return registerStatus - -def kktix_get_event_code(url): - event_code = "" - if '/registrations/new' in url: - prefix_list = ['.com/events/','.cc/events/'] - postfix = '/registrations/new' - - for prefix in prefix_list: - event_code = find_between(url,prefix,postfix) - if len(event_code) > 0: - break - - #print('event_code:',event_code) - return event_code - def kktix_in_stock_play_sound(): global chk_state_play_ticket_sound if 'chk_state_play_ticket_sound' in globals(): @@ -890,16 +789,6 @@ def kktix_in_stock_play_sound(): except Exception as e: pass -def get_kktix_status_by_url(url): - registerStatus = "" - if len(url) > 0: - event_code = kktix_get_event_code(url) - #print(event_code) - if len(event_code) > 0: - registerStatus = kktix_get_registerStatus(event_code) - #print(registerStatus) - return registerStatus - def update_kktix_status(registerStatus): global status_variable if 'status_variable' in globals(): @@ -917,7 +806,7 @@ def append_kktix_status_log(output_log): pass def append_kktix_status_log_file(output_log): - app_root = get_app_root() + app_root = util.get_app_root() log_filepath = os.path.join(app_root, CONST_MAXBOT_KKTIX_LOG_FILE) file1 = open(log_filepath, "a") # append mode file1.write(output_log) @@ -928,7 +817,7 @@ def kktix_status_query(config_dict, last_status, log_file=False): datetime_string = datetime.now().strftime("%Y-%m-%d_%H:%M:%S") registerStatus = "" if len(url) > 0: - registerStatus = get_kktix_status_by_url(url) + registerStatus = util.get_kktix_status_by_url(url) update_kktix_status(registerStatus) if len(registerStatus) > 0: @@ -1037,7 +926,7 @@ def resetful_api_timer(log_file=False): if is_ui_ready: json_str_new = json.dumps(config_dict) if json_str_new != json_str_old: - save_json(config_dict, config_filepath) + util.save_json(config_dict, config_filepath) json_str_old = json_str_new time.sleep(0.5) @@ -1045,7 +934,7 @@ def resetful_api_timer(log_file=False): def main(args): silent_flag = False if not args.silent is None: - silent_flag = t_or_f(args.silent) + silent_flag = util.t_or_f(args.silent) #print("silent_flag:",silent_flag) if not silent_flag: diff --git a/settings.json b/settings.json index 241bcb7..e703795 100644 --- a/settings.json +++ b/settings.json @@ -77,7 +77,7 @@ "user_guess_string": "", "remote_url": "\"http://127.0.0.1:16888/\"", "auto_reload_page_interval": 0.05, - "reset_browser_interval": 0.0, + "reset_browser_interval": 0, "max_dwell_time": 60, "proxy_server_port": "", "window_size": "512,1024", diff --git a/settings.py b/settings.py index fa11b14..4cebc50 100644 --- a/settings.py +++ b/settings.py @@ -14,21 +14,12 @@ except ImportError: from tkinter.filedialog import asksaveasfilename except Exception as e: pass - ''' - try: - import customtkinter - customtkinter.set_appearance_mode("dark") # Modes: system (default), light, dark - customtkinter.set_default_color_theme("dark-blue") # Themes: blue (default), dark-blue, green - except Exception as exc: - pass - ''' import asyncio import base64 import json import os import platform -import socket import ssl import subprocess import sys @@ -37,20 +28,20 @@ import time import warnings import webbrowser from datetime import datetime -from typing import Optional import pyperclip -import requests import tornado from tornado.web import Application from urllib3.exceptions import InsecureRequestWarning +import util + try: import ddddocr except Exception as exc: pass -CONST_APP_VERSION = "MaxBot (2024.03.19)" +CONST_APP_VERSION = "MaxBot (2024.03.20)" CONST_MAXBOT_ANSWER_ONLINE_FILE = "MAXBOT_ONLINE_ANSWER.txt" CONST_MAXBOT_CONFIG_FILE = "settings.json" @@ -600,80 +591,6 @@ def load_translate(): translate['ja_jp']=ja_jp return translate -def get_ip_address(): - gethostname = None - try: - gethostname = socket.gethostname() - except Exception as exc: - print(exc) - gethostname = None - - default_ip = "127.0.0.1" - ip = default_ip - if not gethostname is None: - try: - ip = [l for l in ([ip for ip in socket.gethostbyname_ex(gethostname)[2] - if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), - s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, - socket.SOCK_DGRAM)]][0][1]]) if l][0][0] - except Exception as exc: - print(exc) - ip = gethostname - - #print("get_ip_address:", ip) - return ip - -def format_config_keyword_for_json(user_input): - if len(user_input) > 0: - if not ('\"' in user_input): - user_input = '"' + user_input + '"' - - if user_input[:1]=="{" and user_input[-1:]=="}": - tmp_json = {} - try: - tmp_json = json.loads(user_input) - key=list(tmp_json.keys())[0] - first_item=tmp_json[key] - user_input=json.dumps(first_item) - except Exception as exc: - pass - - if user_input[:1]=="[" and user_input[-1:]=="]": - user_input=user_input[1:] - user_input=user_input[:-1] - return user_input - -def sx(s1): - key=18 - return ''.join(chr(ord(a) ^ key) for a in s1) - -def decryptMe(b): - s="" - if(len(b)>0): - s=sx(base64.b64decode(b).decode("UTF-8")) - return s - -def encryptMe(s): - data="" - if(len(s)>0): - data=base64.b64encode(sx(s).encode('UTF-8')).decode("UTF-8") - return data - -def is_arm(): - ret = False - if "-arm" in platform.platform(): - ret = True - return ret - -def get_app_root(): - app_root = "" - if hasattr(sys, 'frozen'): - basis = sys.executable - app_root = os.path.dirname(basis) - else: - app_root = os.getcwd() - return app_root - def get_default_config(): config_dict={} @@ -688,7 +605,7 @@ def get_default_config(): config_dict["ocr_captcha"]["image_source"] = CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS config_dict["webdriver_type"] = CONST_WEBDRIVER_TYPE_UC - if is_arm(): + if util.is_arm(): config_dict["ocr_captcha"]["enable"] = False config_dict["ocr_captcha"]["force_submit"] = False @@ -785,7 +702,7 @@ def read_last_url_from_file(): return ret def load_json(): - app_root = get_app_root() + app_root = util.get_app_root() # overwrite config path. config_filepath = os.path.join(app_root, CONST_MAXBOT_CONFIG_FILE) @@ -799,7 +716,7 @@ def load_json(): return config_filepath, config_dict def btn_restore_defaults_clicked(language_code): - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_CONFIG_FILE) if os.path.exists(str(config_filepath)): try: @@ -815,7 +732,7 @@ def btn_restore_defaults_clicked(language_code): load_GUI(root, config_dict) def do_maxbot_idle(): - app_root = get_app_root() + app_root = util.get_app_root() idle_filepath = os.path.join(app_root, CONST_MAXBOT_INT28_FILE) with open(CONST_MAXBOT_INT28_FILE, "w") as text_file: text_file.write("") @@ -825,10 +742,10 @@ def btn_idle_clicked(language_code): update_maxbot_runtime_status() def do_maxbot_resume(): - app_root = get_app_root() + app_root = util.get_app_root() idle_filepath = os.path.join(app_root, CONST_MAXBOT_INT28_FILE) for i in range(3): - force_remove_file(idle_filepath) + util.force_remove_file(idle_filepath) def btn_resume_clicked(language_code): do_maxbot_resume() @@ -844,7 +761,7 @@ def btn_save_clicked(): btn_save_act() def btn_save_act(slience_mode=False): - app_root = get_app_root() + app_root = util.get_app_root() config_filepath = os.path.join(app_root, CONST_MAXBOT_CONFIG_FILE) config_dict = get_default_config() @@ -967,35 +884,35 @@ def btn_save_act(slience_mode=False): config_dict["date_auto_select"]["mode"] = combo_date_auto_select_mode.get().strip() date_keyword = txt_date_keyword.get("1.0",END).strip() - date_keyword = format_config_keyword_for_json(date_keyword) + date_keyword = util.format_config_keyword_for_json(date_keyword) config_dict["date_auto_select"]["date_keyword"] = date_keyword config_dict["tixcraft"]["pass_date_is_sold_out"] = bool(chk_state_pass_date_is_sold_out.get()) config_dict["tixcraft"]["auto_reload_coming_soon_page"] = bool(chk_state_auto_reload_coming_soon_page.get()) area_keyword = txt_area_keyword.get("1.0",END).strip() - area_keyword = format_config_keyword_for_json(area_keyword) + area_keyword = util.format_config_keyword_for_json(area_keyword) keyword_exclude = txt_keyword_exclude.get("1.0",END).strip() - keyword_exclude = format_config_keyword_for_json(keyword_exclude) + keyword_exclude = util.format_config_keyword_for_json(keyword_exclude) user_guess_string = txt_user_guess_string.get("1.0",END).strip() - user_guess_string = format_config_keyword_for_json(user_guess_string) + user_guess_string = util.format_config_keyword_for_json(user_guess_string) remote_url = txt_remote_url.get("1.0",END).strip() - remote_url = format_config_keyword_for_json(remote_url) + remote_url = util.format_config_keyword_for_json(remote_url) idle_keyword = txt_idle_keyword.get("1.0",END).strip() - idle_keyword = format_config_keyword_for_json(idle_keyword) + idle_keyword = util.format_config_keyword_for_json(idle_keyword) resume_keyword = txt_resume_keyword.get("1.0",END).strip() - resume_keyword = format_config_keyword_for_json(resume_keyword) + resume_keyword = util.format_config_keyword_for_json(resume_keyword) idle_keyword_second = txt_idle_keyword_second.get("1.0",END).strip() - idle_keyword_second = format_config_keyword_for_json(idle_keyword_second) + idle_keyword_second = util.format_config_keyword_for_json(idle_keyword_second) resume_keyword_second = txt_resume_keyword_second.get("1.0",END).strip() - resume_keyword_second = format_config_keyword_for_json(resume_keyword_second) + resume_keyword_second = util.format_config_keyword_for_json(resume_keyword_second) # test keyword format. if is_all_data_correct: @@ -1127,16 +1044,16 @@ def btn_save_act(slience_mode=False): config_dict["advanced"]["tixcraft_sid"] = config_dict["advanced"]["tixcraft_sid"] config_dict["advanced"]["ibonqware"] = config_dict["advanced"]["ibonqware"] - config_dict["advanced"]["facebook_password"] = encryptMe(config_dict["advanced"]["facebook_password"]) - config_dict["advanced"]["kktix_password"] = encryptMe(config_dict["advanced"]["kktix_password"]) - config_dict["advanced"]["fami_password"] = encryptMe(config_dict["advanced"]["fami_password"]) - config_dict["advanced"]["cityline_password"] = encryptMe(config_dict["advanced"]["cityline_password"]) - config_dict["advanced"]["urbtix_password"] = encryptMe(config_dict["advanced"]["urbtix_password"]) - config_dict["advanced"]["hkticketing_password"] = encryptMe(config_dict["advanced"]["hkticketing_password"]) - config_dict["advanced"]["kham_password"] = encryptMe(config_dict["advanced"]["kham_password"]) - config_dict["advanced"]["ticket_password"] = encryptMe(config_dict["advanced"]["ticket_password"]) - config_dict["advanced"]["udn_password"] = encryptMe(config_dict["advanced"]["udn_password"]) - config_dict["advanced"]["ticketplus_password"] = encryptMe(config_dict["advanced"]["ticketplus_password"]) + config_dict["advanced"]["facebook_password"] = util.encryptMe(config_dict["advanced"]["facebook_password"]) + config_dict["advanced"]["kktix_password"] = util.encryptMe(config_dict["advanced"]["kktix_password"]) + config_dict["advanced"]["fami_password"] = util.encryptMe(config_dict["advanced"]["fami_password"]) + config_dict["advanced"]["cityline_password"] = util.encryptMe(config_dict["advanced"]["cityline_password"]) + config_dict["advanced"]["urbtix_password"] = util.encryptMe(config_dict["advanced"]["urbtix_password"]) + config_dict["advanced"]["hkticketing_password"] = util.encryptMe(config_dict["advanced"]["hkticketing_password"]) + config_dict["advanced"]["kham_password"] = util.encryptMe(config_dict["advanced"]["kham_password"]) + config_dict["advanced"]["ticket_password"] = util.encryptMe(config_dict["advanced"]["ticket_password"]) + config_dict["advanced"]["udn_password"] = util.encryptMe(config_dict["advanced"]["udn_password"]) + config_dict["advanced"]["ticketplus_password"] = util.encryptMe(config_dict["advanced"]["ticketplus_password"]) config_dict["advanced"]["chrome_extension"] = bool(chk_state_chrome_extension.get()) config_dict["advanced"]["disable_adjacent_seat"] = bool(chk_state_adjacent_seat.get()) @@ -1149,7 +1066,7 @@ def btn_save_act(slience_mode=False): config_dict["ocr_captcha"]["force_submit"] = bool(chk_state_ocr_captcha_force_submit.get()) config_dict["ocr_captcha"]["image_source"] = combo_ocr_captcha_image_source.get().strip() - if is_arm(): + if util.is_arm(): config_dict["ocr_captcha"]["enable"] = False config_dict["ocr_captcha"]["force_submit"] = False @@ -1161,7 +1078,7 @@ def btn_save_act(slience_mode=False): config_dict["advanced"]["auto_reload_page_interval"] = float(txt_auto_reload_page_interval.get().strip()) config_dict["advanced"]["max_dwell_time"] = int(txt_max_dwell_time.get().strip()) - config_dict["advanced"]["reset_browser_interval"] = float(txt_reset_browser_interval.get().strip()) + config_dict["advanced"]["reset_browser_interval"] = int(txt_reset_browser_interval.get().strip()) config_dict["advanced"]["proxy_server_port"] = txt_proxy_server_port.get().strip() config_dict["advanced"]["window_size"] = txt_window_size.get().strip() @@ -1183,17 +1100,13 @@ def btn_save_act(slience_mode=False): if not file_to_save is None: if len(file_to_save) > 0: print("save as to:", file_to_save) - save_json(config_dict, file_to_save) + util.save_json(config_dict, file_to_save) else: # slience - save_json(config_dict, config_filepath) + util.save_json(config_dict, config_filepath) return is_all_data_correct -def save_json(config_dict, target_path): - json_str = json.dumps(config_dict, indent=4) - with open(target_path, 'w') as outfile: - outfile.write(json_str) def btn_run_clicked(language_code): print('run button pressed.') @@ -1212,7 +1125,7 @@ def show_preview_text(): with open(CONST_MAXBOT_ANSWER_ONLINE_FILE, "r") as text_file: answer_text = text_file.readline() - answer_text = format_config_keyword_for_json(answer_text) + answer_text = util.format_config_keyword_for_json(answer_text) date_array = [] try: @@ -1227,45 +1140,6 @@ def show_preview_text(): except Exception as exc: pass -def write_string_to_file(filename, data): - outfile = None - if platform.system() == 'Windows': - outfile = open(filename, 'w', encoding='UTF-8') - else: - outfile = open(filename, 'w') - - if not outfile is None: - outfile.write("%s" % data) - -def save_url_to_file(new_remote_url, force_write = False): - html_text = "" - if len(new_remote_url) > 0: - html_result = None - try: - html_result = requests.get(new_remote_url , timeout=0.5, allow_redirects=False) - except Exception as exc: - html_result = None - #print(exc) - if not html_result is None: - status_code = html_result.status_code - #print("status_code:", status_code) - if status_code == 200: - html_text = html_result.text - #print("html_text:", html_text) - - is_write_to_file = False - if force_write: - is_write_to_file = True - if len(html_text) > 0: - is_write_to_file = True - - if is_write_to_file: - html_text = format_config_keyword_for_json(html_text) - working_dir = os.path.dirname(os.path.realpath(__file__)) - target_path = os.path.join(working_dir, CONST_MAXBOT_ANSWER_ONLINE_FILE) - write_string_to_file(target_path, html_text) - return is_write_to_file - def btn_preview_text_clicked(): global txt_remote_url remote_url = "" @@ -1274,7 +1148,7 @@ def btn_preview_text_clicked(): remote_url = txt_remote_url.get("1.0",END).strip() except Exception as exc: pass - remote_url = format_config_keyword_for_json(remote_url) + remote_url = util.format_config_keyword_for_json(remote_url) if len(remote_url) > 0: url_array = [] @@ -1288,7 +1162,7 @@ def btn_preview_text_clicked(): force_write = True for each_url in url_array: #print("new_remote_url:", new_remote_url) - is_write_to_file = save_url_to_file(each_url, force_write=force_write) + is_write_to_file = util.save_url_to_file(each_url, CONST_MAXBOT_ANSWER_ONLINE_FILE, force_write=force_write) if is_write_to_file: break show_preview_text() @@ -1339,26 +1213,9 @@ def btn_preview_sound_clicked(): global txt_play_sound_filename new_sound_filename = txt_play_sound_filename.get().strip() #print("new_sound_filename:", new_sound_filename) - app_root = get_app_root() + app_root = util.get_app_root() new_sound_filename = os.path.join(app_root, new_sound_filename) - play_mp3_async(new_sound_filename) - -def play_mp3_async(sound_filename): - threading.Thread(target=play_mp3, args=(sound_filename,)).start() - -def play_mp3(sound_filename): - from playsound import playsound - try: - playsound(sound_filename) - except Exception as exc: - msg=str(exc) - #print("play sound exeption:", msg) - if platform.system() == 'Windows': - import winsound - try: - winsound.PlaySound(sound_filename, winsound.SND_FILENAME) - except Exception as exc2: - pass + util.play_mp3_async(new_sound_filename) def open_url(url): webbrowser.open_new(url) @@ -2332,7 +2189,7 @@ def AdvancedTab(root, config_dict, language_code, UI_PADDING_X): global lbl_ocr_captcha_not_support_arm lbl_ocr_captcha_not_support_arm = Label(frame_group_ddddocr_enable, fg="red", text=translate[language_code]['ocr_captcha_not_support_arm']) - if is_arm(): + if util.is_arm(): lbl_ocr_captcha_not_support_arm.grid(column=1, row=0, sticky = E) frame_group_ddddocr_enable.grid(column=1, row=group_row_count, sticky = W) @@ -2450,7 +2307,7 @@ def ServerTab(root, config_dict, language_code, UI_PADDING_X): lbl_server_url = Label(frame_group_header, text=translate[language_code]['server_url']) lbl_server_url.grid(column=0, row=group_row_count, sticky = E) - local_ip = get_ip_address() + local_ip = util.get_ip_address() ip_address = "http://%s:%d/" % (local_ip, CONST_SERVER_PORT) global lbl_ip_address lbl_ip_address = Label(frame_group_header, text=ip_address) @@ -2548,7 +2405,7 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): txt_facebook_account.grid(column=1, row=group_row_count, sticky = W) global txt_facebook_password - txt_facebook_password_value = StringVar(frame_group_header, value=decryptMe(config_dict["advanced"]["facebook_password"].strip())) + txt_facebook_password_value = StringVar(frame_group_header, value=util.decryptMe(config_dict["advanced"]["facebook_password"].strip())) txt_facebook_password = Entry(frame_group_header, width=15, textvariable = txt_facebook_password_value, show="*") txt_facebook_password.grid(column=2, row=group_row_count, sticky = W) @@ -2564,7 +2421,7 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): txt_kktix_account.grid(column=1, row=group_row_count, sticky = W) global txt_kktix_password - txt_kktix_password_value = StringVar(frame_group_header, value=decryptMe(config_dict["advanced"]["kktix_password"].strip())) + txt_kktix_password_value = StringVar(frame_group_header, value=util.decryptMe(config_dict["advanced"]["kktix_password"].strip())) txt_kktix_password = Entry(frame_group_header, width=15, textvariable = txt_kktix_password_value, show="*") txt_kktix_password.grid(column=2, row=group_row_count, sticky = W) @@ -2580,7 +2437,7 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): txt_fami_account.grid(column=1, row=group_row_count, sticky = W) global txt_fami_password - txt_fami_password_value = StringVar(frame_group_header, value=decryptMe(config_dict["advanced"]["fami_password"].strip())) + txt_fami_password_value = StringVar(frame_group_header, value=util.decryptMe(config_dict["advanced"]["fami_password"].strip())) txt_fami_password = Entry(frame_group_header, width=15, textvariable = txt_fami_password_value, show="*") txt_fami_password.grid(column=2, row=group_row_count, sticky = W) @@ -2596,7 +2453,7 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): txt_cityline_account.grid(column=1, row=group_row_count, sticky = W) global txt_cityline_password - txt_cityline_password_value = StringVar(frame_group_header, value=decryptMe(config_dict["advanced"]["cityline_password"].strip())) + txt_cityline_password_value = StringVar(frame_group_header, value=util.decryptMe(config_dict["advanced"]["cityline_password"].strip())) txt_cityline_password = Entry(frame_group_header, width=15, textvariable = txt_cityline_password_value, show="*") txt_cityline_password.grid(column=2, row=group_row_count, sticky = W) @@ -2612,7 +2469,7 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): txt_urbtix_account.grid(column=1, row=group_row_count, sticky = W) global txt_urbtix_password - txt_urbtix_password_value = StringVar(frame_group_header, value=decryptMe(config_dict["advanced"]["urbtix_password"].strip())) + txt_urbtix_password_value = StringVar(frame_group_header, value=util.decryptMe(config_dict["advanced"]["urbtix_password"].strip())) txt_urbtix_password = Entry(frame_group_header, width=15, textvariable = txt_urbtix_password_value, show="*") txt_urbtix_password.grid(column=2, row=group_row_count, sticky = W) @@ -2628,7 +2485,7 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): txt_hkticketing_account.grid(column=1, row=group_row_count, sticky = W) global txt_hkticketing_password - txt_hkticketing_password_value = StringVar(frame_group_header, value=decryptMe(config_dict["advanced"]["hkticketing_password"].strip())) + txt_hkticketing_password_value = StringVar(frame_group_header, value=util.decryptMe(config_dict["advanced"]["hkticketing_password"].strip())) txt_hkticketing_password = Entry(frame_group_header, width=15, textvariable = txt_hkticketing_password_value, show="*") txt_hkticketing_password.grid(column=2, row=group_row_count, sticky = W) @@ -2644,7 +2501,7 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): txt_kham_account.grid(column=1, row=group_row_count, sticky = W) global txt_kham_password - txt_kham_password_value = StringVar(frame_group_header, value=decryptMe(config_dict["advanced"]["kham_password"].strip())) + txt_kham_password_value = StringVar(frame_group_header, value=util.decryptMe(config_dict["advanced"]["kham_password"].strip())) txt_kham_password = Entry(frame_group_header, width=15, textvariable = txt_kham_password_value, show="*") txt_kham_password.grid(column=2, row=group_row_count, sticky = W) @@ -2660,7 +2517,7 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): txt_ticket_account.grid(column=1, row=group_row_count, sticky = W) global txt_ticket_password - txt_ticket_password_value = StringVar(frame_group_header, value=decryptMe(config_dict["advanced"]["ticket_password"].strip())) + txt_ticket_password_value = StringVar(frame_group_header, value=util.decryptMe(config_dict["advanced"]["ticket_password"].strip())) txt_ticket_password = Entry(frame_group_header, width=15, textvariable = txt_ticket_password_value, show="*") txt_ticket_password.grid(column=2, row=group_row_count, sticky = W) @@ -2676,7 +2533,7 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): txt_udn_account.grid(column=1, row=group_row_count, sticky = W) global txt_udn_password - txt_udn_password_value = StringVar(frame_group_header, value=decryptMe(config_dict["advanced"]["udn_password"].strip())) + txt_udn_password_value = StringVar(frame_group_header, value=util.decryptMe(config_dict["advanced"]["udn_password"].strip())) txt_udn_password = Entry(frame_group_header, width=15, textvariable = txt_udn_password_value, show="*") txt_udn_password.grid(column=2, row=group_row_count, sticky = W) @@ -2692,7 +2549,7 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): txt_ticketplus_account.grid(column=1, row=group_row_count, sticky = W) global txt_ticketplus_password - txt_ticketplus_password_value = StringVar(frame_group_header, value=decryptMe(config_dict["advanced"]["ticketplus_password"].strip())) + txt_ticketplus_password_value = StringVar(frame_group_header, value=util.decryptMe(config_dict["advanced"]["ticketplus_password"].strip())) txt_ticketplus_password = Entry(frame_group_header, width=15, textvariable = txt_ticketplus_password_value, show="*") txt_ticketplus_password.grid(column=2, row=group_row_count, sticky = W) @@ -2704,33 +2561,6 @@ def AutofillTab(root, config_dict, language_code, UI_PADDING_X): frame_group_header.grid(column=0, row=row_count, padx=UI_PADDING_X) -def is_text_match_keyword(keyword_string, text): - is_match_keyword = True - if len(keyword_string) > 0 and len(text) > 0: - is_match_keyword = False - keyword_array = [] - try: - keyword_array = json.loads("["+ keyword_string +"]") - except Exception as exc: - keyword_array = [] - for item_list in keyword_array: - if len(item_list) > 0: - if ' ' in item_list: - keyword_item_array = item_list.split(' ') - is_match_all = True - for each_item in keyword_item_array: - if not each_item in text: - is_match_all = False - if is_match_all: - is_match_keyword = True - else: - if item_list in text: - is_match_keyword = True - else: - is_match_keyword = True - if is_match_keyword: - break - return is_match_keyword def change_maxbot_status_by_keyword(): config_filepath, config_dict = load_json() @@ -2739,24 +2569,24 @@ def change_maxbot_status_by_keyword(): current_time = system_clock_data.strftime('%H:%M:%S') #print('Current Time is:', current_time) if len(config_dict["advanced"]["idle_keyword"]) > 0: - is_matched = is_text_match_keyword(config_dict["advanced"]["idle_keyword"], current_time) + is_matched = util.is_text_match_keyword(config_dict["advanced"]["idle_keyword"], current_time) if is_matched: #print("match to idle:", current_time) do_maxbot_idle() if len(config_dict["advanced"]["resume_keyword"]) > 0: - is_matched = is_text_match_keyword(config_dict["advanced"]["resume_keyword"], current_time) + is_matched = util.is_text_match_keyword(config_dict["advanced"]["resume_keyword"], current_time) if is_matched: #print("match to resume:", current_time) do_maxbot_resume() current_time = system_clock_data.strftime('%S') if len(config_dict["advanced"]["idle_keyword_second"]) > 0: - is_matched = is_text_match_keyword(config_dict["advanced"]["idle_keyword_second"], current_time) + is_matched = util.is_text_match_keyword(config_dict["advanced"]["idle_keyword_second"], current_time) if is_matched: #print("match to idle:", current_time) do_maxbot_idle() if len(config_dict["advanced"]["resume_keyword_second"]) > 0: - is_matched = is_text_match_keyword(config_dict["advanced"]["resume_keyword_second"], current_time) + is_matched = util.is_text_match_keyword(config_dict["advanced"]["resume_keyword_second"], current_time) if is_matched: #print("match to resume:", current_time) do_maxbot_resume() @@ -2781,37 +2611,37 @@ def check_maxbot_config_unsaved(config_dict): date_keyword = "" if 'txt_date_keyword' in globals(): date_keyword = txt_date_keyword.get("1.0",END).strip() - date_keyword = format_config_keyword_for_json(date_keyword) + date_keyword = util.format_config_keyword_for_json(date_keyword) area_keyword = "" if 'txt_area_keyword' in globals(): area_keyword = txt_area_keyword.get("1.0",END).strip() - area_keyword = format_config_keyword_for_json(area_keyword) + area_keyword = util.format_config_keyword_for_json(area_keyword) keyword_exclude = "" if 'txt_keyword_exclude' in globals(): keyword_exclude = txt_keyword_exclude.get("1.0",END).strip() - keyword_exclude = format_config_keyword_for_json(keyword_exclude) + keyword_exclude = util.format_config_keyword_for_json(keyword_exclude) idle_keyword = "" if 'txt_idle_keyword' in globals(): idle_keyword = txt_idle_keyword.get("1.0",END).strip() - idle_keyword = format_config_keyword_for_json(idle_keyword) + idle_keyword = util.format_config_keyword_for_json(idle_keyword) resume_keyword = "" if 'txt_resume_keyword' in globals(): resume_keyword = txt_resume_keyword.get("1.0",END).strip() - resume_keyword = format_config_keyword_for_json(resume_keyword) + resume_keyword = util.format_config_keyword_for_json(resume_keyword) idle_keyword_second = "" if 'txt_idle_keyword_second' in globals(): idle_keyword_second = txt_idle_keyword_second.get("1.0",END).strip() - idle_keyword_second = format_config_keyword_for_json(idle_keyword_second) + idle_keyword_second = util.format_config_keyword_for_json(idle_keyword_second) resume_keyword_second = "" if 'txt_resume_keyword_second' in globals(): resume_keyword_second = txt_resume_keyword_second.get("1.0",END).strip() - resume_keyword_second = format_config_keyword_for_json(resume_keyword_second) + resume_keyword_second = util.format_config_keyword_for_json(resume_keyword_second) highlightthickness = 0 if 'combo_homepage' in globals(): @@ -2879,7 +2709,7 @@ def settgins_gui_timer(): break def clean_extension_status(): - Root_Dir = get_app_root() + Root_Dir = util.get_app_root() webdriver_path = os.path.join(Root_Dir, "webdriver") target_path = os.path.join(webdriver_path, CONST_MAXBOT_EXTENSION_NAME) target_path = os.path.join(target_path, "data") @@ -2892,7 +2722,7 @@ def clean_extension_status(): pass def sync_status_to_extension(status): - Root_Dir = get_app_root() + Root_Dir = util.get_app_root() webdriver_path = os.path.join(Root_Dir, "webdriver") target_path = os.path.join(webdriver_path, CONST_MAXBOT_EXTENSION_NAME) target_path = os.path.join(target_path, "data") @@ -3286,17 +3116,10 @@ def main_gui(): os.remove(icon_filepath) root.mainloop() - print("exit settings") + #print("exit settings") GLOBAL_SERVER_SHUTDOWN=True clean_extension_status() -def force_remove_file(filepath): - if os.path.exists(filepath): - try: - os.remove(filepath) - except Exception as exc: - pass - def clean_tmp_file(): remove_file_list = [CONST_MAXBOT_LAST_URL_FILE ,CONST_MAXBOT_INT28_FILE @@ -3304,10 +3127,10 @@ def clean_tmp_file(): ,CONST_MAXBOT_QUESTION_FILE ] for filepath in remove_file_list: - force_remove_file(filepath) + util.force_remove_file(filepath) def btn_copy_ip_clicked(): - local_ip = get_ip_address() + local_ip = util.get_ip_address() ip_address = "http://%s:%d/" % (local_ip,CONST_SERVER_PORT) pyperclip.copy(ip_address) @@ -3424,26 +3247,9 @@ async def main_server(): print("server running on port:", CONST_SERVER_PORT) await asyncio.Event().wait() -def is_connectable(port: int, host: Optional[str] = "localhost") -> bool: - """Tries to connect to the server at port to see if it is running. - - :Args: - - port - The port to connect. - """ - socket_ = None - _is_connectable_exceptions = (socket.error, ConnectionResetError) - try: - socket_ = socket.create_connection((host, port), 1) - result = True - except _is_connectable_exceptions: - result = False - finally: - if socket_: - socket_.close() - return result def web_server(): - is_port_binded = is_connectable(CONST_SERVER_PORT) + is_port_binded = util.is_connectable(CONST_SERVER_PORT) #print("is_port_binded:", is_port_binded) if not is_port_binded: asyncio.run(main_server()) diff --git a/util.py b/util.py new file mode 100644 index 0000000..caeeab1 --- /dev/null +++ b/util.py @@ -0,0 +1,1487 @@ +import base64 +import json +import os +import pathlib +import platform +import random +import re +import socket +import sys +import threading +from typing import Optional + +import requests + +CONST_FROM_TOP_TO_BOTTOM = "from top to bottom" +CONST_FROM_BOTTOM_TO_TOP = "from bottom to top" +CONST_CENTER = "center" +CONST_RANDOM = "random" + +USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" + +def get_ip_address(): + gethostname = None + try: + gethostname = socket.gethostname() + except Exception as exc: + print(exc) + gethostname = None + + default_ip = "127.0.0.1" + ip = default_ip + if not gethostname is None: + try: + ip = [l for l in ([ip for ip in socket.gethostbyname_ex(gethostname)[2] + if not ip.startswith("127.")][:1], [[(s.connect(('8.8.8.8', 53)), + s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, + socket.SOCK_DGRAM)]][0][1]]) if l][0][0] + except Exception as exc: + print(exc) + ip = gethostname + + #print("get_ip_address:", ip) + return ip + +def is_connectable(port: int, host: Optional[str] = "localhost") -> bool: + """Tries to connect to the server at port to see if it is running. + + :Args: + - port - The port to connect. + """ + socket_ = None + _is_connectable_exceptions = (socket.error, ConnectionResetError) + try: + socket_ = socket.create_connection((host, port), 1) + result = True + except _is_connectable_exceptions: + result = False + finally: + if socket_: + socket_.close() + return result + +def remove_html_tags(text): + ret = "" + if not text is None: + clean = re.compile('<.*?>') + ret = re.sub(clean, '', text) + ret = ret.strip() + return ret + +# common functions. +def find_between( s, first, last ): + ret = "" + try: + start = s.index( first ) + len( first ) + end = s.index( last, start ) + ret = s[start:end] + except ValueError: + pass + return ret + +def sx(s1): + key=18 + return ''.join(chr(ord(a) ^ key) for a in s1) + +def decryptMe(b): + s="" + if(len(b)>0): + s=sx(base64.b64decode(b).decode("UTF-8")) + return s + +def encryptMe(s): + data="" + if(len(s)>0): + data=base64.b64encode(sx(s).encode('UTF-8')).decode("UTF-8") + return data + +def is_arm(): + ret = False + if "-arm" in platform.platform(): + ret = True + return ret + +def get_app_root(): + app_root = "" + if hasattr(sys, 'frozen'): + basis = sys.executable + app_root = os.path.dirname(basis) + else: + app_root = os.getcwd() + return app_root + + +def format_config_keyword_for_json(user_input): + if len(user_input) > 0: + if not ('\"' in user_input): + user_input = '"' + user_input + '"' + + if user_input[:1]=="{" and user_input[-1:]=="}": + tmp_json = {} + try: + tmp_json = json.loads(user_input) + key=list(tmp_json.keys())[0] + first_item=tmp_json[key] + user_input=json.dumps(first_item) + except Exception as exc: + pass + + if user_input[:1]=="[" and user_input[-1:]=="]": + user_input=user_input[1:] + user_input=user_input[:-1] + return user_input + +def is_text_match_keyword(keyword_string, text): + is_match_keyword = True + if len(keyword_string) > 0 and len(text) > 0: + is_match_keyword = False + keyword_array = [] + try: + keyword_array = json.loads("["+ keyword_string +"]") + except Exception as exc: + keyword_array = [] + for item_list in keyword_array: + if len(item_list) > 0: + if ' ' in item_list: + keyword_item_array = item_list.split(' ') + is_match_all = True + for each_item in keyword_item_array: + if not each_item in text: + is_match_all = False + if is_match_all: + is_match_keyword = True + else: + if item_list in text: + is_match_keyword = True + else: + is_match_keyword = True + if is_match_keyword: + break + return is_match_keyword + +def save_json(config_dict, target_path): + json_str = json.dumps(config_dict, indent=4) + with open(target_path, 'w') as outfile: + outfile.write(json_str) + +def write_string_to_file(filename, data): + outfile = None + if platform.system() == 'Windows': + outfile = open(filename, 'w', encoding='UTF-8') + else: + outfile = open(filename, 'w') + + if not outfile is None: + outfile.write("%s" % data) + +def save_url_to_file(remote_url, CONST_MAXBOT_ANSWER_ONLINE_FILE, force_write = False, timeout=0.5): + html_text = "" + if len(remote_url) > 0: + html_result = None + try: + html_result = requests.get(remote_url , timeout=timeout, allow_redirects=False) + except Exception as exc: + html_result = None + #print(exc) + if not html_result is None: + status_code = html_result.status_code + #print("status_code:", status_code) + if status_code == 200: + html_text = html_result.text + #print("html_text:", html_text) + + is_write_to_file = False + if force_write: + is_write_to_file = True + if len(html_text) > 0: + is_write_to_file = True + + if is_write_to_file: + html_text = format_config_keyword_for_json(html_text) + working_dir = os.path.dirname(os.path.realpath(__file__)) + target_path = os.path.join(working_dir, CONST_MAXBOT_ANSWER_ONLINE_FILE) + write_string_to_file(target_path, html_text) + return is_write_to_file + + +def play_mp3_async(sound_filename): + threading.Thread(target=play_mp3, args=(sound_filename,)).start() + +def play_mp3(sound_filename): + from playsound import playsound + try: + playsound(sound_filename) + except Exception as exc: + msg=str(exc) + #print("play sound exeption:", msg) + if platform.system() == 'Windows': + import winsound + try: + winsound.PlaySound(sound_filename, winsound.SND_FILENAME) + except Exception as exc2: + pass + + +def force_remove_file(filepath): + if os.path.exists(filepath): + try: + os.remove(filepath) + except Exception as exc: + pass + + +def clean_uc_exe_cache(): + exe_name = "chromedriver%s" + + platform = sys.platform + if platform.endswith("win32"): + exe_name %= ".exe" + if platform.endswith(("linux", "linux2")): + exe_name %= "" + if platform.endswith("darwin"): + exe_name %= "" + + d = "" + if platform.endswith("win32"): + d = "~/appdata/roaming/undetected_chromedriver" + elif "LAMBDA_TASK_ROOT" in os.environ: + d = "/tmp/undetected_chromedriver" + elif platform.startswith(("linux", "linux2")): + d = "~/.local/share/undetected_chromedriver" + elif platform.endswith("darwin"): + d = "~/Library/Application Support/undetected_chromedriver" + else: + d = "~/.undetected_chromedriver" + data_path = os.path.abspath(os.path.expanduser(d)) + + is_cache_exist = False + p = pathlib.Path(data_path) + files = list(p.rglob("*chromedriver*?")) + for file in files: + if os.path.exists(str(file)): + is_cache_exist = True + try: + os.unlink(str(file)) + except Exception as exc2: + print(exc2) + pass + + return is_cache_exist + +def t_or_f(arg): + ret = False + ua = str(arg).upper() + if 'TRUE'.startswith(ua): + ret = True + elif 'YES'.startswith(ua): + ret = True + return ret + +def format_keyword_string(keyword): + if not keyword is None: + if len(keyword) > 0: + keyword = keyword.replace('/','/') + keyword = keyword.replace(' ','') + keyword = keyword.replace(',','') + keyword = keyword.replace(',','') + keyword = keyword.replace('$','') + keyword = keyword.replace(' ','').lower() + return keyword + +def format_quota_string(formated_html_text): + formated_html_text = formated_html_text.replace('「','【') + formated_html_text = formated_html_text.replace('『','【') + formated_html_text = formated_html_text.replace('〔','【') + formated_html_text = formated_html_text.replace('﹝','【') + formated_html_text = formated_html_text.replace('〈','【') + formated_html_text = formated_html_text.replace('《','【') + formated_html_text = formated_html_text.replace('[','【') + formated_html_text = formated_html_text.replace('〖','【') + formated_html_text = formated_html_text.replace('[','【') + formated_html_text = formated_html_text.replace('(','【') + formated_html_text = formated_html_text.replace('(','【') + + formated_html_text = formated_html_text.replace('」','】') + formated_html_text = formated_html_text.replace('』','】') + formated_html_text = formated_html_text.replace('〕','】') + formated_html_text = formated_html_text.replace('﹞','】') + formated_html_text = formated_html_text.replace('〉','】') + formated_html_text = formated_html_text.replace('》','】') + formated_html_text = formated_html_text.replace(']','】') + formated_html_text = formated_html_text.replace('〗','】') + formated_html_text = formated_html_text.replace(']','】') + formated_html_text = formated_html_text.replace(')','】') + formated_html_text = formated_html_text.replace(')','】') + return formated_html_text + +def full2half(keyword): + n = "" + if not keyword is None: + if len(keyword) > 0: + for char in keyword: + num = ord(char) + if num == 0x3000: + num = 32 + elif 0xFF01 <= num <= 0xFF5E: + num -= 0xfee0 + n += chr(num) + return n + +def get_chinese_numeric(): + my_dict = {} + my_dict['0']=['0','0','zero','零'] + my_dict['1']=['1','1','one','一','壹','①','❶','⑴'] + my_dict['2']=['2','2','two','二','貳','②','❷','⑵'] + my_dict['3']=['3','3','three','三','叁','③','❸','⑶'] + my_dict['4']=['4','4','four','四','肆','④','❹','⑷'] + my_dict['5']=['5','5','five','五','伍','⑤','❺','⑸'] + my_dict['6']=['6','6','six','六','陸','⑥','❻','⑹'] + my_dict['7']=['7','7','seven','七','柒','⑦','❼','⑺'] + my_dict['8']=['8','8','eight','八','捌','⑧','❽','⑻'] + my_dict['9']=['9','9','nine','九','玖','⑨','❾','⑼'] + return my_dict + +# 同義字 +def synonym_dict(char): + ret = [] + my_dict = get_chinese_numeric() + if char in my_dict: + ret = my_dict[char] + else: + ret.append(char) + return ret + +def chinese_numeric_to_int(char): + ret = None + my_dict = get_chinese_numeric() + for i in my_dict: + for item in my_dict[i]: + if char.lower() == item: + ret = int(i) + break + if not ret is None: + break + return ret + +def normalize_chinese_numeric(keyword): + ret = "" + for char in keyword: + converted_int = chinese_numeric_to_int(char) + if not converted_int is None: + ret += str(converted_int) + return ret + +def find_continuous_number(text): + chars = "0123456789" + return find_continuous_pattern(chars, text) + +def find_continuous_text(text): + chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + return find_continuous_pattern(chars, text) + +def find_continuous_pattern(allowed_char, text): + ret = "" + is_allowed_char_start = False + for char in text: + #print("char:", char) + if char in allowed_char: + if len(ret)==0 and not is_allowed_char_start: + is_allowed_char_start = True + if is_allowed_char_start: + ret += char + else: + # make not continuous + is_allowed_char_start = False + return ret + +def is_all_alpha_or_numeric(text): + ret = False + alpha_count = 0 + numeric_count = 0 + for char in text: + try: + if char.encode('UTF-8').isalpha(): + alpha_count += 1 + except Exception as exc: + pass + + #if char.isnumeric(): + if char.isdigit(): + numeric_count += 1 + + if (alpha_count + numeric_count) == len(text): + ret = True + + #print("text/is_all_alpha_or_numeric:",text,ret) + return ret + +def get_brave_bin_path(): + brave_path = "" + if platform.system() == 'Windows': + brave_path = "C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe" + if not os.path.exists(brave_path): + brave_path = os.path.expanduser('~') + "\\AppData\\Local\\BraveSoftware\\Brave-Browser\\Application\\brave.exe" + if not os.path.exists(brave_path): + brave_path = "C:\\Program Files (x86)\\BraveSoftware\\Brave-Browser\\Application\\brave.exe" + if not os.path.exists(brave_path): + brave_path = "D:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe" + + if platform.system() == 'Linux': + brave_path = "/usr/bin/brave-browser" + + if platform.system() == 'Darwin': + brave_path = '/Applications/Brave Browser.app/Contents/MacOS/Brave Browser' + + return brave_path + + +def dump_settings_to_maxbot_plus_extension(ext, config_dict, CONST_MAXBOT_CONFIG_FILE): + # sync config. + target_path = ext + target_path = os.path.join(target_path, "data") + target_path = os.path.join(target_path, CONST_MAXBOT_CONFIG_FILE) + #print("save as to:", target_path) + if os.path.isfile(target_path): + try: + #print("remove file:", target_path) + os.unlink(target_path) + except Exception as exc: + pass + with open(target_path, 'w') as outfile: + json.dump(config_dict, outfile) + + # add host_permissions + target_path = ext + target_path = os.path.join(target_path, "manifest.json") + + manifest_dict = None + if os.path.isfile(target_path): + with open(target_path) as json_data: + manifest_dict = json.load(json_data) + + local_remote_url_array = [] + local_remote_url = config_dict["advanced"]["remote_url"] + if len(local_remote_url) > 0: + try: + temp_remote_url_array = json.loads("["+ local_remote_url +"]") + for remote_url in temp_remote_url_array: + remote_url_final = remote_url + "*" + local_remote_url_array.append(remote_url_final) + except Exception as exc: + pass + + if len(local_remote_url_array) > 0: + is_manifest_changed = False + for remote_url_final in local_remote_url_array: + if not remote_url_final in manifest_dict["host_permissions"]: + #print("local remote_url not in manifest:", remote_url_final) + manifest_dict["host_permissions"].append(remote_url_final) + is_manifest_changed = True + + if is_manifest_changed: + json_str = json.dumps(manifest_dict, indent=4) + with open(target_path, 'w') as outfile: + outfile.write(json_str) + + +def dump_settings_to_maxblock_plus_extension(ext, config_dict, CONST_MAXBOT_CONFIG_FILE, CONST_MAXBLOCK_EXTENSION_FILTER): + # sync config. + target_path = ext + target_path = os.path.join(target_path, "data") + # special case, due to data folder is empty, sometime will be removed. + if not os.path.exists(target_path): + os.mkdir(target_path) + target_path = os.path.join(target_path, CONST_MAXBOT_CONFIG_FILE) + #print("save as to:", target_path) + if os.path.isfile(target_path): + try: + #print("remove file:", target_path) + os.unlink(target_path) + except Exception as exc: + pass + with open(target_path, 'w') as outfile: + config_dict["domain_filter"]=CONST_MAXBLOCK_EXTENSION_FILTER + json.dump(config_dict, outfile) + +# convert web string to reg pattern +def convert_string_to_pattern(my_str, dynamic_length=True): + my_hint_anwser_length = len(my_str) + my_formated = "" + if my_hint_anwser_length > 0: + my_anwser_symbols = "()[]<>{}-" + for idx in range(my_hint_anwser_length): + char = my_str[idx:idx+1] + + if char in my_anwser_symbols: + my_formated += ('\\' + char) + continue + + pattern = re.compile("[A-Z]") + match_result = pattern.match(char) + #print("match_result A:", match_result) + if not match_result is None: + my_formated += "[A-Z]" + + pattern = re.compile("[a-z]") + match_result = pattern.match(char) + #print("match_result a:", match_result) + if not match_result is None: + my_formated += "[a-z]" + + pattern = re.compile("[\d]") + match_result = pattern.match(char) + #print("match_result d:", match_result) + if not match_result is None: + my_formated += "[\d]" + + # for dynamic length + if dynamic_length: + for i in range(10): + my_formated = my_formated.replace("[A-Z][A-Z]","[A-Z]") + my_formated = my_formated.replace("[a-z][a-z]","[a-z]") + my_formated = my_formated.replace("[\d][\d]","[\d]") + + my_formated = my_formated.replace("[A-Z]","[A-Z]+") + my_formated = my_formated.replace("[a-z]","[a-z]+") + my_formated = my_formated.replace("[\d]","[\d]+") + return my_formated + +def guess_answer_list_from_multi_options(tmp_text): + show_debug_message = True # debug. + show_debug_message = False # online + + options_list = [] + matched_pattern = "" + if len(options_list) == 0: + if '【' in tmp_text and '】' in tmp_text: + pattern = '【.{1,4}】' + options_list = re.findall(pattern, tmp_text) + if len(options_list) <= 2: + options_list = [] + else: + matched_pattern = pattern + + if len(options_list) == 0: + if '(' in tmp_text and ')' in tmp_text: + pattern = '\(.{1,4}\)' + options_list = re.findall(pattern, tmp_text) + if len(options_list) <= 2: + options_list = [] + else: + matched_pattern = pattern + + if len(options_list) == 0: + if '[' in tmp_text and ']' in tmp_text: + pattern = '\[.{1,4}\]' + options_list = re.findall(pattern, tmp_text) + if len(options_list) <= 2: + options_list = [] + else: + matched_pattern = pattern + + if len(options_list) == 0: + if "\n" in tmp_text and ')' in tmp_text: + pattern = "\\n.{1,4}\)" + options_list = re.findall(pattern, tmp_text) + if len(options_list) <= 2: + options_list = [] + else: + matched_pattern = pattern + + if len(options_list) == 0: + if "\n" in tmp_text and ']' in tmp_text: + pattern = "\\n.{1,4}\]" + options_list = re.findall(pattern, tmp_text) + if len(options_list) <= 2: + options_list = [] + else: + matched_pattern = pattern + + if len(options_list) == 0: + if "\n" in tmp_text and '】' in tmp_text: + pattern = "\\n.{1,4}】" + options_list = re.findall(pattern, tmp_text) + if len(options_list) <= 2: + options_list = [] + else: + matched_pattern = pattern + + if len(options_list) == 0: + if "\n" in tmp_text and ':' in tmp_text: + pattern = "\\n.{1,4}:" + options_list = re.findall(pattern, tmp_text) + if len(options_list) <= 2: + options_list = [] + else: + matched_pattern = pattern + + if len(options_list) == 0: + if " " in tmp_text and '?' in tmp_text: + if ('.' in tmp_text or ':' in tmp_text or ')' in tmp_text or ']' in tmp_text or '>' in tmp_text): + pattern = "[ /\n\|;\.\?]{1}.{1}[\.:)\]>]{1}.{2,3}" + options_list = re.findall(pattern, tmp_text) + if len(options_list) <= 2: + options_list = [] + else: + formated_list = [] + for new_item in options_list: + new_item = new_item.strip() + if new_item[:1] == ".": + new_item = new_item[1:] + if new_item[:1] == "?": + new_item = new_item[1:] + if new_item[:1] == "|": + new_item = new_item[1:] + if new_item[:1] == ";": + new_item = new_item[1:] + if new_item[:1] == "/": + new_item = new_item[1:] + new_item = new_item.strip() + new_item = new_item[:1] + formated_list.append(new_item) + options_list = formated_list + + matched_pattern = pattern + + if show_debug_message: + print("matched pattern:", matched_pattern) + + # default remove quota + is_trim_quota = not check_answer_keep_symbol(tmp_text) + if show_debug_message: + print("is_trim_quota:", is_trim_quota) + + return_list = [] + if len(options_list) > 0: + options_list_length = len(options_list) + if show_debug_message: + print("options_list_length:", options_list_length) + print("options_list:", options_list) + if options_list_length > 2: + is_all_options_same_length = True + options_length_count = {} + for i in range(options_list_length-1): + current_option_length = len(options_list[i]) + next_option_length = len(options_list[i+1]) + if current_option_length != next_option_length: + is_all_options_same_length = False + if current_option_length in options_length_count: + options_length_count[current_option_length] += 1 + else: + options_length_count[current_option_length] = 1 + + if show_debug_message: + print("is_all_options_same_length:", is_all_options_same_length) + + if is_all_options_same_length: + return_list = [] + for each_option in options_list: + if len(each_option) > 2: + if is_trim_quota: + return_list.append(each_option[1:-1]) + else: + return_list.append(each_option) + else: + return_list.append(each_option) + else: + #print("options_length_count:", options_length_count) + if len(options_length_count) > 0: + target_option_length = 0 + most_length_count = 0 + for k in options_length_count.keys(): + if options_length_count[k] > most_length_count: + most_length_count = options_length_count[k] + target_option_length = k + #print("most_length_count:", most_length_count) + #print("target_option_length:", target_option_length) + if target_option_length > 0: + return_list = [] + for each_option in options_list: + current_option_length = len(each_option) + if current_option_length == target_option_length: + if is_trim_quota: + return_list.append(each_option[1:-1]) + else: + return_list.append(each_option) + + # something is wrong, give up when option equal 2 options. + if len(return_list) <= 2: + return_list = [] + + # remove chinese work options. + if len(options_list) > 0: + new_list = [] + for item in return_list: + if is_all_alpha_or_numeric(item): + new_list.append(item) + if len(new_list) >=3: + return_list = new_list + + return return_list + + +#PS: this may get a wrong answer list. XD +def guess_answer_list_from_symbols(captcha_text_div_text): + return_list = [] + # need replace to space to get first options. + tmp_text = captcha_text_div_text + tmp_text = tmp_text.replace('?',' ') + tmp_text = tmp_text.replace('?',' ') + tmp_text = tmp_text.replace('。',' ') + + delimitor_symbols_left = [u"(","[","{", " ", " ", " ", " "] + delimitor_symbols_right = [u")","]","}", ":", ".", ")", "-"] + idx = -1 + for idx in range(len(delimitor_symbols_left)): + symbol_left = delimitor_symbols_left[idx] + symbol_right = delimitor_symbols_right[idx] + if symbol_left in tmp_text and symbol_right in tmp_text and '半形' in tmp_text: + hint_list = re.findall('\\'+ symbol_left + '[\\w]+\\'+ symbol_right , tmp_text) + #print("hint_list:", hint_list) + if not hint_list is None: + if len(hint_list) > 1: + return_list = [] + my_answer_delimitor = symbol_right + for options in hint_list: + if len(options) > 2: + my_anwser = options[1:-1] + #print("my_anwser:",my_anwser) + if len(my_anwser) > 0: + return_list.append(my_anwser) + + if len(return_list) > 0: + break + return return_list + +def get_offical_hint_string_from_symbol(symbol, tmp_text): + show_debug_message = True # debug. + show_debug_message = False # online + + offical_hint_string = "" + if symbol in tmp_text: + # start to guess offical hint + if offical_hint_string == "": + if '【' in tmp_text and '】' in tmp_text: + hint_list = re.findall('【.*?】', tmp_text) + if not hint_list is None: + if show_debug_message: + print("【.*?】hint_list:", hint_list) + for hint in hint_list: + if symbol in hint: + offical_hint_string = hint[1:-1] + break + if offical_hint_string == "": + if '(' in tmp_text and ')' in tmp_text: + hint_list = re.findall('\(.*?\)', tmp_text) + if not hint_list is None: + if show_debug_message: + print("\(.*?\)hint_list:", hint_list) + for hint in hint_list: + if symbol in hint: + offical_hint_string = hint[1:-1] + break + if offical_hint_string == "": + if '[' in tmp_text and ']' in tmp_text: + hint_list = re.findall('[.*?]', tmp_text) + if not hint_list is None: + if show_debug_message: + print("[.*?]hint_list:", hint_list) + for hint in hint_list: + if symbol in hint: + offical_hint_string = hint[1:-1] + break + if offical_hint_string == "": + offical_hint_string = tmp_text + return offical_hint_string + + +def guess_answer_list_from_hint(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text): + show_debug_message = True # debug. + show_debug_message = False # online + + tmp_text = format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) + + my_question = "" + my_options = "" + offical_hint_string = "" + offical_hint_string_anwser = "" + my_anwser_formated = "" + my_answer_delimitor = "" + + if my_question == "": + if "?" in tmp_text: + question_index = tmp_text.find("?") + my_question = tmp_text[:question_index+1] + if my_question == "": + if "。" in tmp_text: + question_index = tmp_text.find("。") + my_question = tmp_text[:question_index+1] + if my_question == "": + my_question = tmp_text + #print("my_question:", my_question) + + # ps: hint_list is not options list + + if offical_hint_string == "": + # for: 若你覺得答案為 a,請輸入 a + if '答案' in tmp_text and CONST_INPUT_SYMBOL in tmp_text: + offical_hint_string = get_offical_hint_string_from_symbol(CONST_INPUT_SYMBOL, tmp_text) + if len(offical_hint_string) > 0: + right_part = offical_hint_string.split(CONST_INPUT_SYMBOL)[1] + #print("right_part:", right_part) + if len(offical_hint_string) == len(tmp_text): + offical_hint_string = right_part + + new_hint = find_continuous_text(right_part) + if len(new_hint) > 0: + # TODO: 答案為B需填入Bb) + #if '答案' in offical_hint_string and CONST_INPUT_SYMBOL in offical_hint_string: + offical_hint_string_anwser = new_hint + + + if offical_hint_string == "": + offical_hint_string = get_offical_hint_string_from_symbol(CONST_EXAMPLE_SYMBOL, tmp_text) + if len(offical_hint_string) > 0: + right_part = offical_hint_string.split(CONST_EXAMPLE_SYMBOL)[1] + if len(offical_hint_string) == len(tmp_text): + offical_hint_string = right_part + + # PS: find first text will only get B char in this case: 答案為B需填入Bb) + new_hint = find_continuous_text(right_part) + if len(new_hint) > 0: + offical_hint_string_anwser = new_hint + + # resize offical_hint_string_anwser for options contains in hint string. + #print("offical_hint_string_anwser:", offical_hint_string_anwser) + if len(offical_hint_string_anwser) > 0: + offical_hint_string = offical_hint_string.split(offical_hint_string_anwser)[0] + + if show_debug_message: + print("offical_hint_string:", offical_hint_string) + + # try rule4: + # get hint from rule 3: without '(' & '), but use "*" + if len(offical_hint_string) == 0: + target_symbol = "*" + if target_symbol in tmp_text : + star_index = tmp_text.find(target_symbol) + space_index = tmp_text.find(" ", star_index + len(target_symbol)) + offical_hint_string = tmp_text[star_index: space_index] + + # is need to merge next block + if len(offical_hint_string) > 0: + target_symbol = offical_hint_string + " " + if target_symbol in tmp_text : + star_index = tmp_text.find(target_symbol) + next_block_index = star_index + len(target_symbol) + space_index = tmp_text.find(" ", next_block_index) + next_block = tmp_text[next_block_index: space_index] + if CONST_EXAMPLE_SYMBOL in next_block: + offical_hint_string += ' ' + next_block + + # try rule5: + # get hint from rule 3: n個半形英文大寫 + if len(offical_hint_string) == 0: + target_symbol = "個半形英文大寫" + if target_symbol in tmp_text : + star_index = tmp_text.find(target_symbol) + space_index = tmp_text.find(" ", star_index) + answer_char_count = tmp_text[star_index-1:star_index] + if answer_char_count.isnumeric(): + answer_char_count = chinese_numeric_to_int(answer_char_count) + if answer_char_count is None: + answer_char_count = '0' + + star_index -= 1 + offical_hint_string_anwser = 'A' * int(answer_char_count) + offical_hint_string = tmp_text[star_index: space_index] + + target_symbol = "個英文大寫" + if target_symbol in tmp_text : + star_index = tmp_text.find(target_symbol) + space_index = tmp_text.find(" ", star_index) + answer_char_count = tmp_text[star_index-1:star_index] + if answer_char_count.isnumeric(): + answer_char_count = chinese_numeric_to_int(answer_char_count) + if answer_char_count is None: + answer_char_count = '0' + + star_index -= 1 + offical_hint_string_anwser = 'A' * int(answer_char_count) + offical_hint_string = tmp_text[star_index: space_index] + + target_symbol = "個半形英文小寫" + if target_symbol in tmp_text : + star_index = tmp_text.find(target_symbol) + space_index = tmp_text.find(" ", star_index) + answer_char_count = tmp_text[star_index-1:star_index] + if answer_char_count.isnumeric(): + answer_char_count = chinese_numeric_to_int(answer_char_count) + if answer_char_count is None: + answer_char_count = '0' + + star_index -= 1 + offical_hint_string_anwser = 'a' * int(answer_char_count) + offical_hint_string = tmp_text[star_index: space_index] + + target_symbol = "個英文小寫" + if target_symbol in tmp_text : + star_index = tmp_text.find(target_symbol) + space_index = tmp_text.find(" ", star_index) + answer_char_count = tmp_text[star_index-1:star_index] + if answer_char_count.isnumeric(): + answer_char_count = chinese_numeric_to_int(answer_char_count) + if answer_char_count is None: + answer_char_count = '0' + + star_index -= 1 + offical_hint_string_anwser = 'a' * int(answer_char_count) + offical_hint_string = tmp_text[star_index: space_index] + + target_symbol = "個英數半形字" + if target_symbol in tmp_text : + star_index = tmp_text.find(target_symbol) + space_index = tmp_text.find(" ", star_index) + answer_char_count = tmp_text[star_index-1:star_index] + if answer_char_count.isnumeric(): + answer_char_count = chinese_numeric_to_int(answer_char_count) + if answer_char_count is None: + answer_char_count = '0' + + star_index -= 1 + my_anwser_formated = '[A-Za-z\d]' * int(answer_char_count) + offical_hint_string = tmp_text[star_index: space_index] + + target_symbol = "個半形" + if target_symbol in tmp_text : + star_index = tmp_text.find(target_symbol) + space_index = tmp_text.find(" ", star_index) + answer_char_count = tmp_text[star_index-1:star_index] + if answer_char_count.isnumeric(): + answer_char_count = chinese_numeric_to_int(answer_char_count) + if answer_char_count is None: + answer_char_count = '0' + + star_index -= 1 + my_anwser_formated = '[A-Za-z\d]' * int(answer_char_count) + offical_hint_string = tmp_text[star_index: space_index] + + if len(offical_hint_string) > 0: + if show_debug_message: + print("offical_hint_string_anwser:", offical_hint_string_anwser) + my_anwser_formated = convert_string_to_pattern(offical_hint_string_anwser) + + my_options = tmp_text + if len(my_question) < len(tmp_text): + my_options = my_options.replace(my_question,"") + my_options = my_options.replace(offical_hint_string,"") + + # try rule7: + # check is chinese/english in question, if match, apply my_options rule. + if len(offical_hint_string) > 0: + tmp_text_org = captcha_text_div_text + if CONST_EXAMPLE_SYMBOL in tmp_text: + tmp_text_org = tmp_text_org.replace('Ex:','ex:') + target_symbol = "ex:" + if target_symbol in tmp_text_org : + star_index = tmp_text_org.find(target_symbol) + my_options = tmp_text_org[star_index-1:] + + if show_debug_message: + print("tmp_text:", tmp_text) + print("my_options:", my_options) + + if len(my_anwser_formated) > 0: + allow_delimitor_symbols = ")].: }" + pattern = re.compile(my_anwser_formated) + search_result = pattern.search(my_options) + if not search_result is None: + (span_start, span_end) = search_result.span() + maybe_delimitor="" + if len(my_options) > (span_end+1)+1: + maybe_delimitor = my_options[span_end+0:span_end+1] + if maybe_delimitor in allow_delimitor_symbols: + my_answer_delimitor = maybe_delimitor + + if show_debug_message: + print("my_answer_delimitor:", my_answer_delimitor) + + # default remove quota + is_trim_quota = not check_answer_keep_symbol(tmp_text) + if show_debug_message: + print("is_trim_quota:", is_trim_quota) + + return_list = [] + if len(my_anwser_formated) > 0: + new_pattern = my_anwser_formated + if len(my_answer_delimitor) > 0: + new_pattern = my_anwser_formated + '\\' + my_answer_delimitor + + return_list = re.findall(new_pattern, my_options) + if show_debug_message: + print("my_anwser_formated:", my_anwser_formated) + print("new_pattern:", new_pattern) + print("return_list:" , return_list) + + if not return_list is None: + if len(return_list) == 1: + # re-sample for this case. + return_list = re.findall(my_anwser_formated, my_options) + + if len(return_list) == 1: + # if use pattern to find matched only one, means it is for example text. + return_list = None + + if not return_list is None: + # clean delimitor + if is_trim_quota: + return_list_length = len(return_list) + if return_list_length >= 1: + if len(my_answer_delimitor) > 0: + for idx in range(return_list_length): + return_list[idx]=return_list[idx].replace(my_answer_delimitor,'') + if show_debug_message: + print("cleaned return_list:" , return_list) + + if return_list is None: + return_list = [] + + return return_list, offical_hint_string_anwser + +def format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text): + tmp_text = captcha_text_div_text + tmp_text = tmp_text.replace(' ',' ') + tmp_text = tmp_text.replace(':',':') + # for hint + tmp_text = tmp_text.replace('*','*') + + # stop word. + tmp_text = tmp_text.replace('輸入法','') + tmp_text = tmp_text.replace('請問','') + tmp_text = tmp_text.replace('請將','') + tmp_text = tmp_text.replace('請在','') + tmp_text = tmp_text.replace('請以','') + tmp_text = tmp_text.replace('請回答','') + tmp_text = tmp_text.replace('請','') + + # replace ex. + tmp_text = tmp_text.replace('例如', CONST_EXAMPLE_SYMBOL) + tmp_text = tmp_text.replace('如:', CONST_EXAMPLE_SYMBOL) + tmp_text = tmp_text.replace('如為', CONST_EXAMPLE_SYMBOL+'為') + + tmp_text = tmp_text.replace('舉例', CONST_EXAMPLE_SYMBOL) + if not CONST_EXAMPLE_SYMBOL in tmp_text: + tmp_text = tmp_text.replace('例', CONST_EXAMPLE_SYMBOL) + # important, maybe 例 & ex occurs at same time. + tmp_text = tmp_text.replace('ex:', CONST_EXAMPLE_SYMBOL) + tmp_text = tmp_text.replace('Ex:', CONST_EXAMPLE_SYMBOL) + + #若你覺得 + #PS:這個,可能會造成更多問題,呵呵。 + SYMBOL_IF_LIST = ['假設','如果','若'] + for symbol_if in SYMBOL_IF_LIST: + if symbol_if in tmp_text and '答案' in tmp_text: + tmp_text = tmp_text.replace('覺得', '') + tmp_text = tmp_text.replace('認為', '') + tmp_text = tmp_text.replace(symbol_if + '你答案', CONST_EXAMPLE_SYMBOL + '答案') + tmp_text = tmp_text.replace(symbol_if + '答案', CONST_EXAMPLE_SYMBOL + '答案') + + tmp_text = tmp_text.replace('填入', CONST_INPUT_SYMBOL) + + #tmp_text = tmp_text.replace('[','(') + #tmp_text = tmp_text.replace(']',')') + tmp_text = tmp_text.replace('?','?') + + tmp_text = tmp_text.replace('(','(') + tmp_text = tmp_text.replace(')',')') + + return tmp_text + +def permutations(iterable, r=None): + pool = tuple(iterable) + n = len(pool) + r = n if r is None else r + if r > n: + return + indices = list(range(n)) + cycles = list(range(n, n-r, -1)) + yield tuple(pool[i] for i in indices[:r]) + while n: + for i in reversed(range(r)): + cycles[i] -= 1 + if cycles[i] == 0: + indices[i:] = indices[i+1:] + indices[i:i+1] + cycles[i] = n - i + else: + j = cycles[i] + indices[i], indices[-j] = indices[-j], indices[i] + yield tuple(pool[i] for i in indices[:r]) + break + else: + return + +def get_answer_list_by_question(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text): + show_debug_message = True # debug. + show_debug_message = False # online + + return_list = [] + + tmp_text = format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) + + # guess answer list from multi-options: 【】() [] + if len(return_list)==0: + return_list = guess_answer_list_from_multi_options(tmp_text) + if show_debug_message: + print("captcha_text_div_text:", captcha_text_div_text) + if len(return_list) > 0: + print("found, guess_answer_list_from_multi_options:", return_list) + + offical_hint_string_anwser = "" + if len(return_list)==0: + return_list, offical_hint_string_anwser = guess_answer_list_from_hint(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) + else: + is_match_factorial = False + mutiple = 0 + + return_list_2, offical_hint_string_anwser = guess_answer_list_from_hint(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text) + if return_list_2 is None: + if len(offical_hint_string_anwser) >=3: + if len(return_list) >=3: + mutiple = int(len(offical_hint_string_anwser) / len(return_list[0])) + if mutiple >=3 : + is_match_factorial = True + + if show_debug_message: + print("mutiple:", mutiple) + print("is_match_factorial:", is_match_factorial) + if is_match_factorial: + is_match_factorial = False + order_string_list = ['排列','排序','依序','順序','遞增','遞減','升冪','降冪','新到舊','舊到新','小到大','大到小','高到低','低到高'] + for order_string in order_string_list: + if order_string in tmp_text: + is_match_factorial = True + + if is_match_factorial: + new_array = permutations(return_list, mutiple) + #print("new_array:", new_array) + + return_list = [] + for item_tuple in new_array: + return_list.append(''.join(item_tuple)) + + if show_debug_message: + if len(return_list) > 0: + print("found, guess_answer_list_from_hint:", return_list) + + if len(return_list)==0: + return_list = guess_answer_list_from_symbols(captcha_text_div_text) + if show_debug_message: + if len(return_list) > 0: + print("found, guess_answer_list_from_symbols:", return_list) + + return return_list + + +def get_matched_blocks_by_keyword_item_set(config_dict, auto_select_mode, keyword_item_set, formated_area_list): + show_debug_message = True # debug. + show_debug_message = False # online + + if config_dict["advanced"]["verbose"]: + show_debug_message = True + + matched_blocks = [] + for row in formated_area_list: + row_text = "" + row_html = "" + try: + #row_text = row.text + row_html = row.get_attribute('innerHTML') + row_text = remove_html_tags(row_html) + except Exception as exc: + if show_debug_message: + print(exc) + # error, exit loop + break + + if len(row_text) > 0: + if reset_row_text_if_match_keyword_exclude(config_dict, row_text): + row_text = "" + + if len(row_text) > 0: + # start to compare, normalize all. + row_text = format_keyword_string(row_text) + if show_debug_message: + print("row_text:", row_text) + + is_match_all = False + if ' ' in keyword_item_set: + keyword_item_array = keyword_item_set.split(' ') + is_match_all = True + for keyword_item in keyword_item_array: + keyword_item = format_keyword_string(keyword_item) + if not keyword_item in row_text: + is_match_all = False + else: + exclude_item = format_keyword_string(keyword_item_set) + if exclude_item in row_text: + is_match_all = True + + if is_match_all: + matched_blocks.append(row) + + # only need first row. + if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM: + break + return matched_blocks + +def get_target_item_from_matched_list(matched_blocks, auto_select_mode): + target_area = None + if not matched_blocks is None: + matched_blocks_count = len(matched_blocks) + if matched_blocks_count > 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 = matched_blocks_count - 1 + + if auto_select_mode == CONST_RANDOM: + if matched_blocks_count > 1: + target_row_index = random.randint(0,matched_blocks_count-1) + + if auto_select_mode == CONST_CENTER: + if matched_blocks_count > 2: + target_row_index = int(matched_blocks_count/2) + + target_area = matched_blocks[target_row_index] + return target_area + + +def get_matched_blocks_by_keyword(config_dict, auto_select_mode, keyword_string, formated_area_list): + keyword_array = [] + try: + keyword_array = json.loads("["+ keyword_string +"]") + except Exception as exc: + keyword_array = [] + + matched_blocks = [] + for keyword_item_set in keyword_array: + matched_blocks = get_matched_blocks_by_keyword_item_set(config_dict, auto_select_mode, keyword_item_set, formated_area_list) + if len(matched_blocks) > 0: + break + return matched_blocks + + +def is_row_match_keyword(keyword_string, row_text): + # clean stop word. + row_text = format_keyword_string(row_text) + + is_match_keyword = True + if len(keyword_string) > 0 and len(row_text) > 0: + is_match_keyword = False + keyword_array = [] + try: + keyword_array = json.loads("["+ keyword_string +"]") + except Exception as exc: + keyword_array = [] + for item_list in keyword_array: + if len(item_list) > 0: + if ' ' in item_list: + keyword_item_array = item_list.split(' ') + is_match_all_exclude = True + for each_item in keyword_item_array: + each_item = format_keyword_string(each_item) + if not each_item in row_text: + is_match_all_exclude = False + if is_match_all_exclude: + is_match_keyword = True + else: + item_list = format_keyword_string(item_list) + if item_list in row_text: + is_match_keyword = True + else: + # match all. + is_match_keyword = True + if is_match_keyword: + break + return is_match_keyword + +def reset_row_text_if_match_keyword_exclude(config_dict, row_text): + area_keyword_exclude = config_dict["keyword_exclude"] + return is_row_match_keyword(area_keyword_exclude, row_text) + + +def guess_tixcraft_question(driver, question_text): + show_debug_message = True # debug. + show_debug_message = False # online + + answer_list = [] + + formated_html_text = "" + if len(question_text) > 0: + # format question text. + formated_html_text = question_text + formated_html_text = format_quota_string(formated_html_text) + + if '【' in formated_html_text and '】' in formated_html_text: + # PS: 這個太容易沖突,因為問題類型太多,不能直接使用。 + #inferred_answer_string = find_between(formated_html_text, "【", "】") + pass + + if show_debug_message: + print("formated_html_text:", formated_html_text) + + # start to guess answer + inferred_answer_string = None + + # 請輸入"YES",代表您已詳閱且瞭解並同意。 + if inferred_answer_string is None: + if '輸入"YES"' in formated_html_text: + if '已詳閱' in formated_html_text or '請詳閱' in formated_html_text: + if '同意' in formated_html_text: + inferred_answer_string = 'YES' + + # 購票前請詳閱注意事項,並於驗證碼欄位輸入【同意】繼續購票流程。 + if inferred_answer_string is None: + if '驗證碼' in formated_html_text or '驗證欄位' in formated_html_text: + if '已詳閱' in formated_html_text or '請詳閱' in formated_html_text: + if '輸入【同意】' in formated_html_text: + inferred_answer_string = '同意' + + if inferred_answer_string is None: + if len(question_text) > 0: + answer_list = get_answer_list_from_question_string(None, question_text) + else: + answer_list = [answer_list] + + return answer_list + +def get_answer_list_from_user_guess_string(config_dict, CONST_MAXBOT_ANSWER_ONLINE_FILE): + local_array = [] + online_array = [] + + user_guess_string = config_dict["advanced"]["user_guess_string"] + if len(user_guess_string) > 0: + user_guess_string = format_config_keyword_for_json(user_guess_string) + try: + local_array = json.loads("["+ user_guess_string +"]") + except Exception as exc: + local_array = [] + + # load from internet. + user_guess_string = "" + if os.path.exists(CONST_MAXBOT_ANSWER_ONLINE_FILE): + with open(CONST_MAXBOT_ANSWER_ONLINE_FILE, "r") as text_file: + user_guess_string = text_file.readline() + if len(user_guess_string) > 0: + user_guess_string = format_config_keyword_for_json(user_guess_string) + try: + online_array = json.loads("["+ user_guess_string +"]") + except Exception as exc: + online_array = [] + + return local_array + online_array + +def check_answer_keep_symbol(captcha_text_div_text): + is_need_keep_symbol = False + + # format text + keep_symbol_tmp = captcha_text_div_text + keep_symbol_tmp = keep_symbol_tmp.replace('也','須') + keep_symbol_tmp = keep_symbol_tmp.replace('必須','須') + + keep_symbol_tmp = keep_symbol_tmp.replace('全都','都') + keep_symbol_tmp = keep_symbol_tmp.replace('全部都','都') + + keep_symbol_tmp = keep_symbol_tmp.replace('一致','相同') + keep_symbol_tmp = keep_symbol_tmp.replace('一樣','相同') + keep_symbol_tmp = keep_symbol_tmp.replace('相等','相同') + + if '符號須都相同' in keep_symbol_tmp: + is_need_keep_symbol = True + + if '符號都相同' in keep_symbol_tmp: + is_need_keep_symbol = True + + if '符號須相同' in keep_symbol_tmp: + is_need_keep_symbol = True + + # for: 大小寫含括號需一模一樣 + keep_symbol_tmp = keep_symbol_tmp.replace('含', '') + keep_symbol_tmp = keep_symbol_tmp.replace('和', '') + keep_symbol_tmp = keep_symbol_tmp.replace('與', '') + keep_symbol_tmp = keep_symbol_tmp.replace('還有', '') + keep_symbol_tmp = keep_symbol_tmp.replace('及', '') + keep_symbol_tmp = keep_symbol_tmp.replace('以及', '') + keep_symbol_tmp = keep_symbol_tmp.replace('需', '') + keep_symbol_tmp = keep_symbol_tmp.replace('必須', '') + keep_symbol_tmp = keep_symbol_tmp.replace('而且', '') + keep_symbol_tmp = keep_symbol_tmp.replace('且', '') + keep_symbol_tmp = keep_symbol_tmp.replace('一模', '') + #print("keep_symbol_tmp:", keep_symbol_tmp) + if '大小寫括號相同' in keep_symbol_tmp: + is_need_keep_symbol = True + + return is_need_keep_symbol + +def kktix_get_registerStatus(event_code): + html_result = None + + url = "https://kktix.com/g/events/%s/register_info" % (event_code) + #print('event_code:',event_code) + #print("url:", url) + + headers = {"Accept-Language": "zh-TW,zh;q=0.5", 'User-Agent': USER_AGENT} + try: + html_result = requests.get(url , headers=headers, timeout=0.7, allow_redirects=False) + except Exception as exc: + html_result = None + print("send reg_info request fail:") + print(exc) + + registerStatus = None + if not html_result is None: + status_code = html_result.status_code + #print("status_code:",status_code) + if status_code == 200: + html_text = html_result.text + #print("html_text:", html_text) + try: + jsLoads = json.loads(html_text) + if 'inventory' in jsLoads: + if 'registerStatus' in jsLoads['inventory']: + registerStatus = jsLoads['inventory']['registerStatus'] + except Exception as exc: + print("load reg_info json fail:") + print(exc) + pass + + #print("registerStatus:", registerStatus) + return registerStatus + +def kktix_get_event_code(url): + event_code = "" + if '/registrations/new' in url: + prefix_list = ['.com/events/','.cc/events/'] + postfix = '/registrations/new' + + for prefix in prefix_list: + event_code = find_between(url,prefix,postfix) + if len(event_code) > 0: + break + + #print('event_code:',event_code) + return event_code + +def get_kktix_status_by_url(url): + registerStatus = "" + if len(url) > 0: + event_code = kktix_get_event_code(url) + #print(event_code) + if len(event_code) > 0: + registerStatus = kktix_get_registerStatus(event_code) + #print(registerStatus) + return registerStatus + diff --git a/webdriver/Maxblockplus_1.0.0/data/settings.json b/webdriver/Maxblockplus_1.0.0/data/settings.json index 3bdeadd..33aac94 100644 --- a/webdriver/Maxblockplus_1.0.0/data/settings.json +++ b/webdriver/Maxblockplus_1.0.0/data/settings.json @@ -1 +1 @@ -{"homepage": "https://tixcraft.com", "browser": "chrome", "language": "\u7e41\u9ad4\u4e2d\u6587", "ticket_number": 2, "ocr_captcha": {"enable": true, "beta": true, "force_submit": true, "image_source": "canvas"}, "webdriver_type": "undetected_chromedriver", "date_auto_select": {"enable": true, "date_keyword": "", "mode": "random"}, "area_auto_select": {"enable": true, "mode": "random", "area_keyword": ""}, "keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\",\"\u71c8\u67f1\u906e\u853d\",\"\u8996\u7dda\u4e0d\u5b8c\u6574\"", "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true}, "tixcraft": {"pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true}, "advanced": {"play_sound": {"ticket": true, "order": true, "filename": "ding-dong.wav"}, "tixcraft_sid": "", "ibonqware": "", "facebook_account": "", "kktix_account": "", "fami_account": "", "cityline_account": "", "urbtix_account": "", "hkticketing_account": "", "kham_account": "", "ticket_account": "", "udn_account": "", "ticketplus_account": "", "facebook_password": "", "kktix_password": "", "fami_password": "", "urbtix_password": "", "cityline_password": "", "hkticketing_password": "", "kham_password": "", "ticket_password": "", "udn_password": "", "ticketplus_password": "", "facebook_password_plaintext": "", "kktix_password_plaintext": "", "fami_password_plaintext": "", "urbtix_password_plaintext": "", "cityline_password_plaintext": "", "hkticketing_password_plaintext": "", "kham_password_plaintext": "", "ticket_password_plaintext": "", "udn_password_plaintext": "", "ticketplus_password_plaintext": "", "chrome_extension": true, "disable_adjacent_seat": false, "hide_some_image": true, "block_facebook_network": false, "headless": false, "verbose": false, "auto_guess_options": true, "user_guess_string": "", "remote_url": "\"http://127.0.0.1:16888/\"", "auto_reload_page_interval": 0.05, "reset_browser_interval": 0.0, "max_dwell_time": 60, "proxy_server_port": "", "window_size": "512,1024", "idle_keyword": "", "resume_keyword": "", "idle_keyword_second": "", "resume_keyword_second": ""}, "domain_filter": ["*google-analytics.com/*", "*googletagmanager.com/*", "*googletagservices.com/*", "*lndata.com/*", "*a.amnet.tw/*", "*adx.c.appier.net/*", "*clarity.ms/*", "*cloudfront.com/*", "*cms.analytics.yahoo.com/*", "*doubleclick.net/*", "*e2elog.fetnet.net/*", "*fundingchoicesmessages.google.com/*", "*ghtinc.com/*", "*match.adsrvr.org/*", "*onead.onevision.com.tw/*", "*popin.cc/*", "*rollbar.com/*", "*sb.scorecardresearch.com/*", "*tagtoo.co/*", "*.ssp.hinet.net/*", "*ticketmaster.sg/js/adblock*", "*.googlesyndication.com/*", "*treasuredata.com/*", "*play.google.com/log?*", "*www.youtube.com/youtubei/v1/player/heartbeat*", "*tixcraft.com/js/analytics.js*", "*ticketmaster.sg/js/adblock.js*", "*img.uniicreative.com/*", "*cdn.cookielaw.org/*", "*tixcraft.com/js/custom.js*", "*tixcraft.com/js/common.js*", "*cdnjs.cloudflare.com/ajax/libs/clipboard.js/*"]} \ No newline at end of file +{"homepage": "https://tixcraft.com", "browser": "chrome", "language": "\u7e41\u9ad4\u4e2d\u6587", "ticket_number": 2, "ocr_captcha": {"enable": true, "beta": true, "force_submit": true, "image_source": "canvas"}, "webdriver_type": "undetected_chromedriver", "date_auto_select": {"enable": true, "date_keyword": "", "mode": "random"}, "area_auto_select": {"enable": true, "mode": "random", "area_keyword": ""}, "keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\",\"\u71c8\u67f1\u906e\u853d\",\"\u8996\u7dda\u4e0d\u5b8c\u6574\"", "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true}, "tixcraft": {"pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true}, "advanced": {"play_sound": {"ticket": true, "order": true, "filename": "ding-dong.wav"}, "tixcraft_sid": "", "ibonqware": "", "facebook_account": "", "kktix_account": "", "fami_account": "", "cityline_account": "", "urbtix_account": "", "hkticketing_account": "", "kham_account": "", "ticket_account": "", "udn_account": "", "ticketplus_account": "", "facebook_password": "", "kktix_password": "", "fami_password": "", "urbtix_password": "", "cityline_password": "", "hkticketing_password": "", "kham_password": "", "ticket_password": "", "udn_password": "", "ticketplus_password": "", "facebook_password_plaintext": "", "kktix_password_plaintext": "", "fami_password_plaintext": "", "urbtix_password_plaintext": "", "cityline_password_plaintext": "", "hkticketing_password_plaintext": "", "kham_password_plaintext": "", "ticket_password_plaintext": "", "udn_password_plaintext": "", "ticketplus_password_plaintext": "", "chrome_extension": true, "disable_adjacent_seat": false, "hide_some_image": true, "block_facebook_network": false, "headless": false, "verbose": false, "auto_guess_options": true, "user_guess_string": "", "remote_url": "\"http://127.0.0.1:16888/\"", "auto_reload_page_interval": 0.05, "reset_browser_interval": 0, "max_dwell_time": 60, "proxy_server_port": "", "window_size": "512,1024", "idle_keyword": "", "resume_keyword": "", "idle_keyword_second": "", "resume_keyword_second": ""}, "domain_filter": ["*google-analytics.com/*", "*googletagmanager.com/*", "*googletagservices.com/*", "*lndata.com/*", "*a.amnet.tw/*", "*adx.c.appier.net/*", "*clarity.ms/*", "*cloudfront.com/*", "*cms.analytics.yahoo.com/*", "*doubleclick.net/*", "*e2elog.fetnet.net/*", "*fundingchoicesmessages.google.com/*", "*ghtinc.com/*", "*match.adsrvr.org/*", "*onead.onevision.com.tw/*", "*popin.cc/*", "*rollbar.com/*", "*sb.scorecardresearch.com/*", "*tagtoo.co/*", "*.ssp.hinet.net/*", "*ticketmaster.sg/js/adblock*", "*.googlesyndication.com/*", "*treasuredata.com/*", "*play.google.com/log?*", "*www.youtube.com/youtubei/v1/player/heartbeat*", "*tixcraft.com/js/analytics.js*", "*ticketmaster.sg/js/adblock.js*", "*img.uniicreative.com/*", "*cdn.cookielaw.org/*", "*tixcraft.com/js/custom.js*", "*tixcraft.com/js/common.js*", "*cdnjs.cloudflare.com/ajax/libs/clipboard.js/*"]} \ No newline at end of file diff --git a/webdriver/Maxbotplus_1.0.0/data/settings.json b/webdriver/Maxbotplus_1.0.0/data/settings.json index 05479f2..1483cbe 100644 --- a/webdriver/Maxbotplus_1.0.0/data/settings.json +++ b/webdriver/Maxbotplus_1.0.0/data/settings.json @@ -1 +1 @@ -{"homepage": "https://tixcraft.com", "browser": "chrome", "language": "\u7e41\u9ad4\u4e2d\u6587", "ticket_number": 2, "ocr_captcha": {"enable": true, "beta": true, "force_submit": true, "image_source": "canvas"}, "webdriver_type": "undetected_chromedriver", "date_auto_select": {"enable": true, "date_keyword": "", "mode": "random"}, "area_auto_select": {"enable": true, "mode": "random", "area_keyword": ""}, "keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\",\"\u71c8\u67f1\u906e\u853d\",\"\u8996\u7dda\u4e0d\u5b8c\u6574\"", "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true}, "tixcraft": {"pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true}, "advanced": {"play_sound": {"ticket": true, "order": true, "filename": "ding-dong.wav"}, "tixcraft_sid": "", "ibonqware": "", "facebook_account": "", "kktix_account": "", "fami_account": "", "cityline_account": "", "urbtix_account": "", "hkticketing_account": "", "kham_account": "", "ticket_account": "", "udn_account": "", "ticketplus_account": "", "facebook_password": "", "kktix_password": "", "fami_password": "", "urbtix_password": "", "cityline_password": "", "hkticketing_password": "", "kham_password": "", "ticket_password": "", "udn_password": "", "ticketplus_password": "", "facebook_password_plaintext": "", "kktix_password_plaintext": "", "fami_password_plaintext": "", "urbtix_password_plaintext": "", "cityline_password_plaintext": "", "hkticketing_password_plaintext": "", "kham_password_plaintext": "", "ticket_password_plaintext": "", "udn_password_plaintext": "", "ticketplus_password_plaintext": "", "chrome_extension": true, "disable_adjacent_seat": false, "hide_some_image": true, "block_facebook_network": false, "headless": false, "verbose": false, "auto_guess_options": true, "user_guess_string": "", "remote_url": "\"http://127.0.0.1:16888/\"", "auto_reload_page_interval": 0.05, "reset_browser_interval": 0.0, "max_dwell_time": 60, "proxy_server_port": "", "window_size": "512,1024", "idle_keyword": "", "resume_keyword": "", "idle_keyword_second": "", "resume_keyword_second": ""}} \ No newline at end of file +{"homepage": "https://tixcraft.com", "browser": "chrome", "language": "\u7e41\u9ad4\u4e2d\u6587", "ticket_number": 2, "ocr_captcha": {"enable": true, "beta": true, "force_submit": true, "image_source": "canvas"}, "webdriver_type": "undetected_chromedriver", "date_auto_select": {"enable": true, "date_keyword": "", "mode": "random"}, "area_auto_select": {"enable": true, "mode": "random", "area_keyword": ""}, "keyword_exclude": "\"\u8f2a\u6905\",\"\u8eab\u969c\",\"\u8eab\u5fc3 \u969c\u7919\",\"Restricted View\",\"\u71c8\u67f1\u906e\u853d\",\"\u8996\u7dda\u4e0d\u5b8c\u6574\"", "kktix": {"auto_press_next_step_button": true, "auto_fill_ticket_number": true}, "tixcraft": {"pass_date_is_sold_out": true, "auto_reload_coming_soon_page": true}, "advanced": {"play_sound": {"ticket": true, "order": true, "filename": "ding-dong.wav"}, "tixcraft_sid": "", "ibonqware": "", "facebook_account": "", "kktix_account": "", "fami_account": "", "cityline_account": "", "urbtix_account": "", "hkticketing_account": "", "kham_account": "", "ticket_account": "", "udn_account": "", "ticketplus_account": "", "facebook_password": "", "kktix_password": "", "fami_password": "", "urbtix_password": "", "cityline_password": "", "hkticketing_password": "", "kham_password": "", "ticket_password": "", "udn_password": "", "ticketplus_password": "", "facebook_password_plaintext": "", "kktix_password_plaintext": "", "fami_password_plaintext": "", "urbtix_password_plaintext": "", "cityline_password_plaintext": "", "hkticketing_password_plaintext": "", "kham_password_plaintext": "", "ticket_password_plaintext": "", "udn_password_plaintext": "", "ticketplus_password_plaintext": "", "chrome_extension": true, "disable_adjacent_seat": false, "hide_some_image": true, "block_facebook_network": false, "headless": false, "verbose": false, "auto_guess_options": true, "user_guess_string": "", "remote_url": "\"http://127.0.0.1:16888/\"", "auto_reload_page_interval": 0.05, "reset_browser_interval": 0, "max_dwell_time": 60, "proxy_server_port": "", "window_size": "512,1024", "idle_keyword": "", "resume_keyword": "", "idle_keyword_second": "", "resume_keyword_second": ""}} \ No newline at end of file