2024-04-03 04:05:10 +00:00
|
|
|
|
import base64
|
|
|
|
|
import json
|
|
|
|
|
import os
|
|
|
|
|
import pathlib
|
|
|
|
|
import platform
|
|
|
|
|
import random
|
|
|
|
|
import re
|
|
|
|
|
import socket
|
2024-04-07 13:24:21 +00:00
|
|
|
|
import subprocess
|
2024-04-03 04:05:10 +00:00
|
|
|
|
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"
|
|
|
|
|
|
2024-05-11 04:23:43 +00:00
|
|
|
|
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
|
2024-04-03 04:05:10 +00:00
|
|
|
|
|
|
|
|
|
def get_ip_address():
|
|
|
|
|
gethostname = None
|
|
|
|
|
try:
|
|
|
|
|
gethostname = socket.gethostname()
|
|
|
|
|
except Exception as exc:
|
2024-04-23 13:37:46 +00:00
|
|
|
|
print("gethostname", exc)
|
2024-04-03 04:05:10 +00:00
|
|
|
|
gethostname = None
|
|
|
|
|
|
|
|
|
|
default_ip = "127.0.0.1"
|
|
|
|
|
ip = default_ip
|
2024-04-23 13:37:46 +00:00
|
|
|
|
|
|
|
|
|
check_public_ip = True
|
|
|
|
|
if "macos" in platform.platform().lower():
|
|
|
|
|
if "arm64" in platform.platform().lower():
|
|
|
|
|
check_public_ip = False
|
|
|
|
|
|
|
|
|
|
if check_public_ip and not gethostname is None:
|
2024-04-03 04:05:10 +00:00
|
|
|
|
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:
|
2024-04-23 13:37:46 +00:00
|
|
|
|
print("gethostbyname_ex", exc)
|
2024-04-03 04:05:10 +00:00
|
|
|
|
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:
|
2024-05-01 14:26:41 +00:00
|
|
|
|
|
|
|
|
|
# directly input text into arrray field.
|
|
|
|
|
if len(keyword_string) > 0:
|
|
|
|
|
if not '"' in keyword_string:
|
|
|
|
|
keyword_string = '"' + keyword_string + '"'
|
|
|
|
|
|
2024-04-03 04:05:10 +00:00
|
|
|
|
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)
|
2024-04-23 13:37:46 +00:00
|
|
|
|
try:
|
|
|
|
|
with open(target_path, 'w') as outfile:
|
|
|
|
|
outfile.write(json_str)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
pass
|
2024-04-03 04:05:10 +00:00
|
|
|
|
|
|
|
|
|
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
|
2024-04-23 13:37:46 +00:00
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
with open(target_path, 'w') as outfile:
|
|
|
|
|
json.dump(config_dict, outfile)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
pass
|
2024-04-03 04:05:10 +00:00
|
|
|
|
|
|
|
|
|
# add host_permissions
|
|
|
|
|
target_path = ext
|
|
|
|
|
target_path = os.path.join(target_path, "manifest.json")
|
|
|
|
|
|
|
|
|
|
manifest_dict = None
|
|
|
|
|
if os.path.isfile(target_path):
|
2024-04-23 13:37:46 +00:00
|
|
|
|
try:
|
|
|
|
|
with open(target_path) as json_data:
|
|
|
|
|
manifest_dict = json.load(json_data)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
pass
|
2024-04-03 04:05:10 +00:00
|
|
|
|
|
|
|
|
|
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
|
2024-04-11 02:56:01 +00:00
|
|
|
|
if 'host_permissions' in manifest_dict:
|
|
|
|
|
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
|
2024-04-03 04:05:10 +00:00
|
|
|
|
|
|
|
|
|
if is_manifest_changed:
|
|
|
|
|
json_str = json.dumps(manifest_dict, indent=4)
|
2024-04-23 13:37:46 +00:00
|
|
|
|
try:
|
|
|
|
|
with open(target_path, 'w') as outfile:
|
|
|
|
|
outfile.write(json_str)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
pass
|
2024-04-03 04:05:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
2024-04-23 13:37:46 +00:00
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
with open(target_path, 'w') as outfile:
|
|
|
|
|
config_dict["domain_filter"]=CONST_MAXBLOCK_EXTENSION_FILTER
|
|
|
|
|
json.dump(config_dict, outfile)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
pass
|
2024-04-03 04:05:10 +00:00
|
|
|
|
|
|
|
|
|
# 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):
|
2024-04-23 13:37:46 +00:00
|
|
|
|
try:
|
|
|
|
|
with open(CONST_MAXBOT_ANSWER_ONLINE_FILE, "r") as text_file:
|
|
|
|
|
user_guess_string = text_file.readline()
|
|
|
|
|
except Exception as e:
|
|
|
|
|
pass
|
|
|
|
|
|
2024-04-03 04:05:10 +00:00
|
|
|
|
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
|
|
|
|
|
|
2024-04-03 11:51:36 +00:00
|
|
|
|
#PS: this is for selenium webdriver.
|
|
|
|
|
def kktix_get_web_datetime(registrationsNewApp_div):
|
|
|
|
|
show_debug_message = True # debug.
|
|
|
|
|
show_debug_message = False # online
|
|
|
|
|
|
|
|
|
|
web_datetime = None
|
|
|
|
|
|
|
|
|
|
is_found_web_datetime = False
|
|
|
|
|
|
|
|
|
|
el_web_datetime_list = None
|
|
|
|
|
if not registrationsNewApp_div is None:
|
|
|
|
|
try:
|
|
|
|
|
el_web_datetime_list = registrationsNewApp_div.find_elements(By.TAG_NAME, 'td')
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("find td.ng-binding Exception")
|
|
|
|
|
print(exc)
|
|
|
|
|
pass
|
|
|
|
|
#print("is_found_web_datetime", is_found_web_datetime)
|
|
|
|
|
|
|
|
|
|
if not el_web_datetime_list is None:
|
|
|
|
|
el_web_datetime_list_count = len(el_web_datetime_list)
|
|
|
|
|
if el_web_datetime_list_count > 0:
|
|
|
|
|
el_web_datetime = None
|
|
|
|
|
for el_web_datetime in el_web_datetime_list:
|
|
|
|
|
el_web_datetime_text = None
|
|
|
|
|
try:
|
|
|
|
|
el_web_datetime_text = el_web_datetime.text
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("el_web_datetime_text:", el_web_datetime_text)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print('parse web datetime fail:')
|
|
|
|
|
print(exc)
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
if not el_web_datetime_text is None:
|
|
|
|
|
if len(el_web_datetime_text) > 0:
|
|
|
|
|
now = datetime.now()
|
|
|
|
|
#print("now:", now)
|
|
|
|
|
for guess_year in range(now.year,now.year+3):
|
|
|
|
|
current_year = str(guess_year)
|
|
|
|
|
if current_year in el_web_datetime_text:
|
|
|
|
|
if '/' in el_web_datetime_text:
|
|
|
|
|
web_datetime = el_web_datetime_text
|
|
|
|
|
is_found_web_datetime = True
|
|
|
|
|
break
|
|
|
|
|
if is_found_web_datetime:
|
|
|
|
|
break
|
|
|
|
|
else:
|
|
|
|
|
print("find td.ng-binding fail")
|
|
|
|
|
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print('is_found_web_datetime:', is_found_web_datetime)
|
|
|
|
|
print('web_datetime:', web_datetime)
|
|
|
|
|
|
|
|
|
|
return web_datetime
|
|
|
|
|
|
|
|
|
|
def get_answer_string_from_web_date(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, registrationsNewApp_div, captcha_text_div_text):
|
|
|
|
|
show_debug_message = True # debug.
|
|
|
|
|
show_debug_message = False # online
|
|
|
|
|
|
|
|
|
|
inferred_answer_string = None
|
|
|
|
|
|
|
|
|
|
is_need_parse_web_datetime = False
|
|
|
|
|
# '半形阿拉伯數字' & '半形數字'
|
|
|
|
|
if '半形' in captcha_text_div_text and '字' in captcha_text_div_text:
|
|
|
|
|
if '演出日期' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_datetime = True
|
|
|
|
|
if '活動日期' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_datetime = True
|
|
|
|
|
if '表演日期' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_datetime = True
|
|
|
|
|
if '開始日期' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_datetime = True
|
|
|
|
|
if '演唱會日期' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_datetime = True
|
|
|
|
|
if '展覽日期' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_datetime = True
|
|
|
|
|
if '音樂會日期' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_datetime = True
|
|
|
|
|
if 'the date of the show you purchased' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_datetime = True
|
|
|
|
|
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("is_need_parse_web_datetime:", is_need_parse_web_datetime)
|
|
|
|
|
|
|
|
|
|
if is_need_parse_web_datetime:
|
|
|
|
|
web_datetime = kktix_get_web_datetime(registrationsNewApp_div)
|
|
|
|
|
if not web_datetime is None:
|
|
|
|
|
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)
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("captcha_text_formatted", captcha_text_formatted)
|
|
|
|
|
|
|
|
|
|
my_datetime_foramted = None
|
|
|
|
|
|
|
|
|
|
# MMDD
|
|
|
|
|
if my_datetime_foramted is None:
|
|
|
|
|
if '4位半形' in captcha_text_formatted:
|
|
|
|
|
my_datetime_foramted = "%m%d"
|
|
|
|
|
|
|
|
|
|
# for "如為2月30日,請輸入0230"
|
|
|
|
|
if my_datetime_foramted is None:
|
|
|
|
|
right_part = ""
|
|
|
|
|
if CONST_EXAMPLE_SYMBOL in captcha_text_formatted:
|
|
|
|
|
right_part = captcha_text_formatted.split(CONST_EXAMPLE_SYMBOL)[1]
|
|
|
|
|
|
|
|
|
|
if CONST_INPUT_SYMBOL in right_part:
|
|
|
|
|
right_part = right_part.split(CONST_INPUT_SYMBOL)[1]
|
|
|
|
|
number_text = find_continuous_number(right_part)
|
|
|
|
|
|
|
|
|
|
my_anwser_formated = 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]":
|
|
|
|
|
my_datetime_foramted = "%m%d"
|
|
|
|
|
#print("my_datetime_foramted:", my_datetime_foramted)
|
|
|
|
|
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("my_datetime_foramted", my_datetime_foramted)
|
|
|
|
|
|
|
|
|
|
if my_datetime_foramted is None:
|
|
|
|
|
now = datetime.now()
|
|
|
|
|
for guess_year in range(now.year-4,now.year+2):
|
|
|
|
|
current_year = str(guess_year)
|
|
|
|
|
if current_year in captcha_text_formatted:
|
|
|
|
|
my_hint_index = captcha_text_formatted.find(current_year)
|
|
|
|
|
my_hint_anwser = captcha_text_formatted[my_hint_index:]
|
|
|
|
|
#print("my_hint_anwser:", my_hint_anwser)
|
|
|
|
|
# get after.
|
|
|
|
|
my_delimitor_symbol = CONST_EXAMPLE_SYMBOL
|
|
|
|
|
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+len(my_delimitor_symbol):]
|
|
|
|
|
#print("my_hint_anwser:", my_hint_anwser)
|
|
|
|
|
# get before.
|
|
|
|
|
my_delimitor_symbol = ','
|
|
|
|
|
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_delimitor_symbol = '。'
|
|
|
|
|
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]
|
|
|
|
|
# PS: space may not is delimitor...
|
|
|
|
|
my_delimitor_symbol = ' '
|
|
|
|
|
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]
|
|
|
|
|
#remove last char.
|
|
|
|
|
remove_last_char_list = [')','(','.','。',')','(','[',']']
|
|
|
|
|
for check_char in remove_last_char_list:
|
|
|
|
|
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)
|
|
|
|
|
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]":
|
|
|
|
|
my_datetime_foramted = "%Y/%m/%d"
|
|
|
|
|
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("my_hint_anwser:", my_hint_anwser)
|
|
|
|
|
print("my_anwser_formated:", my_anwser_formated)
|
|
|
|
|
print("my_datetime_foramted:", my_datetime_foramted)
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if not my_datetime_foramted is None:
|
|
|
|
|
my_delimitor_symbol = ' '
|
|
|
|
|
if my_delimitor_symbol in web_datetime:
|
|
|
|
|
web_datetime = web_datetime[:web_datetime.find(my_delimitor_symbol)]
|
|
|
|
|
date_time = datetime.strptime(web_datetime,"%Y/%m/%d")
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("our web date_time:", date_time)
|
|
|
|
|
ans = None
|
|
|
|
|
try:
|
|
|
|
|
if not date_time is None:
|
|
|
|
|
ans = date_time.strftime(my_datetime_foramted)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
pass
|
|
|
|
|
inferred_answer_string = ans
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("web date_time anwser:", ans)
|
|
|
|
|
|
|
|
|
|
return inferred_answer_string
|
|
|
|
|
|
|
|
|
|
def get_answer_string_from_web_time(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, registrationsNewApp_div, captcha_text_div_text):
|
|
|
|
|
show_debug_message = True # debug.
|
|
|
|
|
show_debug_message = False # online
|
|
|
|
|
|
|
|
|
|
inferred_answer_string = None
|
|
|
|
|
|
|
|
|
|
# parse '演出時間'
|
|
|
|
|
is_need_parse_web_time = False
|
|
|
|
|
if '半形' in captcha_text_div_text:
|
|
|
|
|
if '演出時間' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_time = True
|
|
|
|
|
if '表演時間' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_time = True
|
|
|
|
|
if '開始時間' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_time = True
|
|
|
|
|
if '演唱會時間' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_time = True
|
|
|
|
|
if '展覽時間' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_time = True
|
|
|
|
|
if '音樂會時間' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_time = True
|
|
|
|
|
if 'the time of the show you purchased' in captcha_text_div_text:
|
|
|
|
|
is_need_parse_web_time = True
|
|
|
|
|
|
|
|
|
|
#print("is_need_parse_web_time", is_need_parse_web_time)
|
|
|
|
|
if is_need_parse_web_time:
|
|
|
|
|
web_datetime = None
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
my_datetime_foramted = None
|
|
|
|
|
|
|
|
|
|
if my_datetime_foramted is None:
|
|
|
|
|
my_hint_anwser = tmp_text
|
|
|
|
|
|
|
|
|
|
my_delimitor_symbol = CONST_EXAMPLE_SYMBOL
|
|
|
|
|
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+len(my_delimitor_symbol):]
|
|
|
|
|
#print("my_hint_anwser:", my_hint_anwser)
|
|
|
|
|
# get before.
|
|
|
|
|
my_delimitor_symbol = ','
|
|
|
|
|
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_delimitor_symbol = '。'
|
|
|
|
|
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]
|
|
|
|
|
# PS: space may not is delimitor...
|
|
|
|
|
my_delimitor_symbol = ' '
|
|
|
|
|
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)
|
|
|
|
|
#print("my_hint_anwser:", my_hint_anwser)
|
|
|
|
|
#print("my_anwser_formated:", my_anwser_formated)
|
|
|
|
|
if my_anwser_formated == "[\\d][\\d][\\d][\\d]":
|
|
|
|
|
my_datetime_foramted = "%H%M"
|
|
|
|
|
if '12小時' in tmp_text:
|
|
|
|
|
my_datetime_foramted = "%I%M"
|
|
|
|
|
|
|
|
|
|
if my_anwser_formated == "[\\d][\\d]:[\\d][\\d]":
|
|
|
|
|
my_datetime_foramted = "%H:%M"
|
|
|
|
|
if '12小時' in tmp_text:
|
|
|
|
|
my_datetime_foramted = "%I:%M"
|
|
|
|
|
|
|
|
|
|
if not my_datetime_foramted is None:
|
|
|
|
|
date_delimitor_symbol = '('
|
|
|
|
|
if date_delimitor_symbol in web_datetime:
|
|
|
|
|
date_delimitor_symbol_index = web_datetime.find(date_delimitor_symbol)
|
|
|
|
|
if date_delimitor_symbol_index > 8:
|
|
|
|
|
web_datetime = web_datetime[:date_delimitor_symbol_index-1]
|
|
|
|
|
date_time = datetime.strptime(web_datetime,"%Y/%m/%d %H:%M")
|
|
|
|
|
#print("date_time:", date_time)
|
|
|
|
|
ans = None
|
|
|
|
|
try:
|
|
|
|
|
ans = date_time.strftime(my_datetime_foramted)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
pass
|
|
|
|
|
inferred_answer_string = ans
|
|
|
|
|
#print("my_anwser:", ans)
|
|
|
|
|
|
|
|
|
|
return inferred_answer_string
|
|
|
|
|
|
|
|
|
|
def get_answer_list_from_question_string(registrationsNewApp_div, captcha_text_div_text):
|
|
|
|
|
show_debug_message = True # debug.
|
|
|
|
|
show_debug_message = False # online
|
|
|
|
|
|
|
|
|
|
inferred_answer_string = None
|
|
|
|
|
answer_list = []
|
|
|
|
|
|
|
|
|
|
CONST_EXAMPLE_SYMBOL = "範例"
|
|
|
|
|
CONST_INPUT_SYMBOL = "輸入"
|
|
|
|
|
|
|
|
|
|
if captcha_text_div_text is None:
|
|
|
|
|
captcha_text_div_text = ""
|
|
|
|
|
|
|
|
|
|
# 請在下方空白處輸入引號內文字:
|
|
|
|
|
# 請回答下列問題,請在下方空格輸入DELIGHT(請以半形輸入法作答,大小寫需要一模一樣)
|
|
|
|
|
if inferred_answer_string is None:
|
|
|
|
|
is_use_quota_message = False
|
|
|
|
|
if "「" in captcha_text_div_text and "」" in captcha_text_div_text:
|
|
|
|
|
# test for rule#1, it's seem very easy conflict...
|
|
|
|
|
match_quota_text_items = ["空白","輸入","引號","文字"]
|
|
|
|
|
is_match_quota_text = True
|
|
|
|
|
for each_quota_text in match_quota_text_items:
|
|
|
|
|
if not each_quota_text in captcha_text_div_text:
|
|
|
|
|
is_match_quota_text = False
|
|
|
|
|
if is_match_quota_text:
|
|
|
|
|
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 = temp_answer.strip()
|
|
|
|
|
if len(temp_answer) > 0:
|
|
|
|
|
inferred_answer_string = temp_answer
|
|
|
|
|
#print("find captcha text:" , inferred_answer_string)
|
|
|
|
|
|
|
|
|
|
# 請在下方空白處輸入括號內數字
|
|
|
|
|
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 = 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('數字','文字')
|
|
|
|
|
|
|
|
|
|
is_match_input_quota_text = False
|
|
|
|
|
if len(formated_html_text) <= 30:
|
|
|
|
|
if not '\n' in formated_html_text:
|
|
|
|
|
if '【' in formated_html_text and '】' in formated_html_text:
|
|
|
|
|
is_match_input_quota_text = True
|
|
|
|
|
|
|
|
|
|
# check target text terms.
|
|
|
|
|
if is_match_input_quota_text:
|
|
|
|
|
target_text_list = ["輸入","括號","文字"]
|
|
|
|
|
for item in target_text_list:
|
|
|
|
|
if not item in formated_html_text:
|
|
|
|
|
is_match_input_quota_text = False
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
if is_match_input_quota_text:
|
|
|
|
|
temp_answer = 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)
|
|
|
|
|
|
|
|
|
|
inferred_answer_string = temp_answer
|
|
|
|
|
|
|
|
|
|
if inferred_answer_string is None:
|
|
|
|
|
is_use_quota_message = False
|
|
|
|
|
if "【" in captcha_text_div_text and "】" in captcha_text_div_text:
|
|
|
|
|
if '下' in captcha_text_div_text and '空' in captcha_text_div_text and CONST_INPUT_SYMBOL in captcha_text_div_text and '引號' in captcha_text_div_text and '字' in captcha_text_div_text:
|
|
|
|
|
is_use_quota_message = True
|
|
|
|
|
if '半形' in captcha_text_div_text and CONST_INPUT_SYMBOL in captcha_text_div_text and '引號' in captcha_text_div_text and '字' in captcha_text_div_text:
|
|
|
|
|
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 = inferred_answer_string.strip()
|
|
|
|
|
#print("find captcha text:" , inferred_answer_string)
|
|
|
|
|
|
|
|
|
|
# parse '演出日期'
|
|
|
|
|
if inferred_answer_string is None:
|
|
|
|
|
inferred_answer_string = get_answer_string_from_web_date(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, registrationsNewApp_div, captcha_text_div_text)
|
|
|
|
|
|
|
|
|
|
# parse '演出時間'
|
|
|
|
|
if inferred_answer_string is None:
|
|
|
|
|
inferred_answer_string = get_answer_string_from_web_time(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, registrationsNewApp_div, captcha_text_div_text)
|
|
|
|
|
|
|
|
|
|
# name of event.
|
|
|
|
|
if inferred_answer_string is None:
|
|
|
|
|
if "name of event" in captcha_text_div_text:
|
|
|
|
|
if '(' in captcha_text_div_text and ')' in captcha_text_div_text and 'ans:' in captcha_text_div_text.lower():
|
|
|
|
|
target_symbol = "("
|
|
|
|
|
star_index = captcha_text_div_text.find(target_symbol)
|
|
|
|
|
target_symbol = ":"
|
|
|
|
|
star_index = captcha_text_div_text.find(target_symbol, star_index)
|
|
|
|
|
target_symbol = ")"
|
|
|
|
|
end_index = captcha_text_div_text.find(target_symbol, star_index)
|
|
|
|
|
inferred_answer_string = captcha_text_div_text[star_index+1:end_index]
|
|
|
|
|
#print("inferred_answer_string:", inferred_answer_string)
|
|
|
|
|
|
|
|
|
|
# 二題式,組合問題。
|
|
|
|
|
is_combine_two_question = False
|
|
|
|
|
if "第一題" in captcha_text_div_text and "第二題" in captcha_text_div_text:
|
|
|
|
|
is_combine_two_question = True
|
|
|
|
|
if "Q1." in captcha_text_div_text and "Q2." in captcha_text_div_text:
|
|
|
|
|
if "二題" in captcha_text_div_text:
|
|
|
|
|
is_combine_two_question = True
|
|
|
|
|
if "2題" in captcha_text_div_text:
|
|
|
|
|
is_combine_two_question = True
|
|
|
|
|
if "Q1:" in captcha_text_div_text and "Q2:" in captcha_text_div_text:
|
|
|
|
|
if "二題" in captcha_text_div_text:
|
|
|
|
|
is_combine_two_question = True
|
|
|
|
|
if "2題" in captcha_text_div_text:
|
|
|
|
|
is_combine_two_question = True
|
|
|
|
|
if "Q1 " in captcha_text_div_text and "Q2 " in captcha_text_div_text:
|
|
|
|
|
if "二題" in captcha_text_div_text:
|
|
|
|
|
is_combine_two_question = True
|
|
|
|
|
if "2題" in captcha_text_div_text:
|
|
|
|
|
is_combine_two_question = True
|
|
|
|
|
if is_combine_two_question:
|
|
|
|
|
inferred_answer_string = None
|
|
|
|
|
#print("is_combine_two_question:", is_combine_two_question)
|
|
|
|
|
|
|
|
|
|
# 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)
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("guess answer list:", answer_list)
|
|
|
|
|
else:
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("skip to guess answer because of combine question...")
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
if show_debug_message:
|
|
|
|
|
print("got an inferred_answer_string:", inferred_answer_string)
|
|
|
|
|
answer_list = [inferred_answer_string]
|
|
|
|
|
|
|
|
|
|
return answer_list
|
|
|
|
|
|
2024-04-03 04:05:10 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2024-04-04 17:27:01 +00:00
|
|
|
|
registerStatus = ""
|
2024-04-03 04:05:10 +00:00
|
|
|
|
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
|
|
|
|
|
|
2024-04-04 22:40:56 +00:00
|
|
|
|
def launch_maxbot(script_name="chrome_tixcraft", filename="", homepage="", kktix_account = "", kktix_password="", window_size="", headless=""):
|
2024-04-04 10:24:58 +00:00
|
|
|
|
cmd_argument = []
|
|
|
|
|
if len(filename) > 0:
|
|
|
|
|
cmd_argument.append('--input=' + filename)
|
|
|
|
|
if len(homepage) > 0:
|
|
|
|
|
cmd_argument.append('--homepage=' + homepage)
|
|
|
|
|
if len(kktix_account) > 0:
|
|
|
|
|
cmd_argument.append('--kktix_account=' + kktix_account)
|
|
|
|
|
if len(kktix_password) > 0:
|
|
|
|
|
cmd_argument.append('--kktix_password=' + kktix_password)
|
|
|
|
|
if len(window_size) > 0:
|
|
|
|
|
cmd_argument.append('--window_size=' + window_size)
|
2024-04-04 22:40:56 +00:00
|
|
|
|
if len(headless) > 0:
|
|
|
|
|
cmd_argument.append('--headless=' + headless)
|
2024-04-04 10:24:58 +00:00
|
|
|
|
|
|
|
|
|
working_dir = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
|
if hasattr(sys, 'frozen'):
|
|
|
|
|
print("execute in frozen mode")
|
|
|
|
|
# check platform here.
|
|
|
|
|
cmd = './' + script_name + ' '.join(cmd_argument)
|
|
|
|
|
if platform.system() == 'Darwin':
|
|
|
|
|
print("execute MacOS python script")
|
|
|
|
|
if platform.system() == 'Linux':
|
|
|
|
|
print("execute linux binary")
|
|
|
|
|
if platform.system() == 'Windows':
|
|
|
|
|
print("execute .exe binary.")
|
|
|
|
|
cmd = script_name + '.exe ' + ' '.join(cmd_argument)
|
|
|
|
|
subprocess.Popen(cmd, shell=True, cwd=working_dir)
|
|
|
|
|
else:
|
|
|
|
|
interpreter_binary = 'python'
|
|
|
|
|
interpreter_binary_alt = 'python3'
|
|
|
|
|
if platform.system() != 'Windows':
|
|
|
|
|
interpreter_binary = 'python3'
|
|
|
|
|
interpreter_binary_alt = 'python'
|
|
|
|
|
print("execute in shell mode.")
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
print('try', interpreter_binary)
|
|
|
|
|
cmd_array = [interpreter_binary, script_name + '.py'] + cmd_argument
|
|
|
|
|
s=subprocess.Popen(cmd_array, cwd=working_dir)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
print('try', interpreter_binary_alt)
|
|
|
|
|
try:
|
|
|
|
|
cmd_array = [interpreter_binary_alt, script_name + '.py'] + cmd_argument
|
|
|
|
|
s=subprocess.Popen(cmd_array, cwd=working_dir)
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
msg=str(exc)
|
|
|
|
|
print("exeption:", msg)
|
|
|
|
|
pass
|