tixcraft_bot/chrome_tixcraft.py

8089 lines
306 KiB
Python
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env python3
#encoding=utf-8
# 'seleniumwire' and 'selenium 4' raise error when running python 2.x
# PS: python 2.x will be removed in future.
#執行方式python chrome_tixcraft.py 或 python3 chrome_tixcraft.py
import os
import sys
import platform
import json
import random
from selenium import webdriver
# for close tab.
from selenium.common.exceptions import NoSuchWindowException
from selenium.common.exceptions import UnexpectedAlertPresentException
from selenium.common.exceptions import NoAlertPresentException
from selenium.common.exceptions import WebDriverException
# for alert 2
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import Select
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
# for selenium 4
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.action_chains import ActionChains
# for wait #1
import time
import re
from datetime import datetime
# for error output
import logging
logging.basicConfig()
logger = logging.getLogger('logger')
# for check reg_info
import requests
import warnings
from urllib3.exceptions import InsecureRequestWarning
warnings.simplefilter('ignore',InsecureRequestWarning)
# ocr
import base64
try:
import ddddocr
#PS: python 3.11.1 raise PIL conflict.
from NonBrowser import NonBrowser
except Exception as exc:
pass
import webbrowser
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
CONST_APP_VERSION = u"MaxBot (2023.02.23)"
CONST_HOMEPAGE_DEFAULT = "https://tixcraft.com"
URL_GOOGLE_OAUTH = 'https://accounts.google.com/o/oauth2/v2/auth/oauthchooseaccount?redirect_uri=https%3A%2F%2Fdevelopers.google.com%2Foauthplayground&prompt=consent&response_type=code&client_id=407408718192.apps.googleusercontent.com&scope=email&access_type=offline&flowName=GeneralOAuthFlow'
CONST_CHROME_VERSION_NOT_MATCH_EN="Please download the WebDriver version to match your browser version."
CONST_CHROME_VERSION_NOT_MATCH_TW="請下載與您瀏覽器相同版本的WebDriver版本或更新您的瀏覽器版本。"
CONST_KKTIX_SIGN_IN_URL = "https://kktix.com/users/sign_in?back_to=%s"
CONST_CITYLINE_SIGN_IN_URL = "https://www.cityline.com/Login.html?targetUrl=https%3A%2F%2Fwww.cityline.com%2FEvents.html"
CONST_URBTIX_SIGN_IN_URL = "https://www.urbtix.hk/member-login"
CONST_KHAM_SIGN_IN_URL = "https://kham.com.tw/application/UTK13/UTK1306_.aspx"
CONST_HKTICKETING_SIGN_IN_URL = "https://premier.hkticketing.com/Membership/Login.aspx"
CONST_FROM_TOP_TO_BOTTOM = u"from top to bottom"
CONST_FROM_BOTTOM_TO_TOP = u"from bottom to top"
CONST_RANDOM = u"random"
CONST_SELECT_ORDER_DEFAULT = CONST_FROM_TOP_TO_BOTTOM
CONST_SELECT_OPTIONS_DEFAULT = (CONST_FROM_TOP_TO_BOTTOM, CONST_FROM_BOTTOM_TO_TOP, CONST_RANDOM)
CONST_SELECT_OPTIONS_ARRAY = [CONST_FROM_TOP_TO_BOTTOM, CONST_FROM_BOTTOM_TO_TOP, CONST_RANDOM]
CONT_STRING_1_SEATS_REMAINING = [u'@1 seat(s) remaining',u'剩餘 1@',u'@1 席残り']
CONST_OCR_CAPTCH_IMAGE_SOURCE_NON_BROWSER = "NonBrowser"
CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS = "canvas"
CONST_WEBDRIVER_TYPE_SELENIUM = "selenium"
#CONST_WEBDRIVER_TYPE_STEALTH = "stealth"
CONST_WEBDRIVER_TYPE_UC = "undetected_chromedriver"
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 get_app_root():
# 讀取檔案裡的參數值
basis = ""
if hasattr(sys, 'frozen'):
basis = sys.executable
else:
basis = sys.argv[0]
app_root = os.path.dirname(basis)
return app_root
def get_config_dict():
config_json_filename = 'settings.json'
app_root = get_app_root()
config_filepath = os.path.join(app_root, config_json_filename)
config_dict = None
if os.path.isfile(config_filepath):
with open(config_filepath) as json_data:
config_dict = json.load(json_data)
# special case for headless.
is_headless_enable = False
if config_dict["advanced"]["headless"]:
# for tixcraft headless.
if len(config_dict["advanced"]["tixcraft_sid"]) > 1:
is_headless_enable = True
else:
print("If you are runnig headless mode on tixcraft, you need input your cookie SID.")
if is_headless_enable:
config_dict["ocr_captcha"]["enable"] = True
config_dict["ocr_captcha"]["force_submit"] = True
return config_dict
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 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 get_favoriate_extension_path(webdriver_path):
no_google_analytics_path = os.path.join(webdriver_path,"no_google_analytics_1.1.0.0.crx")
no_ad_path = os.path.join(webdriver_path,"Adblock_3.15.2.0.crx")
return no_google_analytics_path, no_ad_path
def get_chromedriver_path(webdriver_path):
chromedriver_path = os.path.join(webdriver_path,"chromedriver")
if platform.system().lower()=="windows":
chromedriver_path = os.path.join(webdriver_path,"chromedriver.exe")
return chromedriver_path
def get_chrome_options(webdriver_path, adblock_plus_enable, browser="chrome", headless = False):
chrome_options = webdriver.ChromeOptions()
if browser=="edge":
chrome_options = webdriver.EdgeOptions()
if browser=="safari":
chrome_options = webdriver.SafariOptions()
# some windows cause: timed out receiving message from renderer
if adblock_plus_enable:
# PS: this is ocx version.
no_google_analytics_path, no_ad_path = get_favoriate_extension_path(webdriver_path)
if os.path.exists(no_google_analytics_path):
chrome_options.add_extension(no_google_analytics_path)
if os.path.exists(no_ad_path):
chrome_options.add_extension(no_ad_path)
if headless:
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-features=TranslateUI')
chrome_options.add_argument('--disable-translate')
chrome_options.add_argument('--lang=zh-TW')
# for navigator.webdriver
chrome_options.add_experimental_option("excludeSwitches", ['enable-automation'])
# Deprecated chrome option is ignored: useAutomationExtension
#chrome_options.add_experimental_option('useAutomationExtension', False)
chrome_options.add_experimental_option("prefs", {"credentials_enable_service": False, "profile.password_manager_enabled": False})
#caps = DesiredCapabilities().CHROME
caps = chrome_options.to_capabilities()
#caps["pageLoadStrategy"] = u"normal" # complete
caps["pageLoadStrategy"] = u"eager" # interactive
#caps["pageLoadStrategy"] = u"none"
#caps["unhandledPromptBehavior"] = u"dismiss and notify" # default
#caps["unhandledPromptBehavior"] = u"ignore"
#caps["unhandledPromptBehavior"] = u"dismiss"
caps["unhandledPromptBehavior"] = u"accept"
return chrome_options, caps
def load_chromdriver_normal(webdriver_path, driver_type, adblock_plus_enable, headless):
chromedriver_path = get_chromedriver_path(webdriver_path)
chrome_service = Service(chromedriver_path)
chrome_options, caps = get_chrome_options(webdriver_path, adblock_plus_enable, headless=headless)
driver = None
try:
# method 6: Selenium Stealth
driver = webdriver.Chrome(service=chrome_service, options=chrome_options, desired_capabilities=caps)
except Exception as exc:
error_message = str(exc)
left_part = None
if "Stacktrace:" in error_message:
left_part = error_message.split("Stacktrace:")[0]
print(left_part)
if "This version of ChromeDriver only supports Chrome version" in error_message:
print(CONST_CHROME_VERSION_NOT_MATCH_EN)
print(CONST_CHROME_VERSION_NOT_MATCH_TW)
if driver_type=="stealth":
from selenium_stealth import stealth
# Selenium Stealth settings
stealth(driver,
languages=["zh-TW", "zh"],
vendor="Google Inc.",
platform="Win32",
webgl_vendor="Intel Inc.",
renderer="Intel Iris OpenGL Engine",
fix_hairline=True,
)
#print("driver capabilities", driver.capabilities)
return driver
def load_chromdriver_uc(webdriver_path, adblock_plus_enable, headless):
import undetected_chromedriver as uc
chromedriver_path = get_chromedriver_path(webdriver_path)
options = uc.ChromeOptions()
options.page_load_strategy="eager"
#print("strategy", options.page_load_strategy)
if adblock_plus_enable:
no_google_analytics_path, no_ad_path = get_favoriate_extension_path(webdriver_path)
no_google_analytics_folder_path = no_google_analytics_path.replace('.crx','')
no_ad_folder_path = no_ad_path.replace('.crx','')
load_extension_path = ""
if os.path.exists(no_google_analytics_folder_path):
load_extension_path += "," + no_google_analytics_folder_path
if os.path.exists(no_ad_folder_path):
load_extension_path += "," + no_ad_folder_path
if len(load_extension_path) > 0:
options.add_argument('--load-extension=' + load_extension_path[1:])
if headless:
options.add_argument('--headless')
options.add_argument('--disable-features=TranslateUI')
options.add_argument('--disable-translate')
options.add_argument('--lang=zh-TW')
options.add_argument("--password-store=basic")
options.add_experimental_option("prefs", {"credentials_enable_service": False, "profile.password_manager_enabled": False})
caps = options.to_capabilities()
caps["unhandledPromptBehavior"] = u"accept"
driver = None
if os.path.exists(chromedriver_path):
print("Use user driver path:", chromedriver_path)
#driver = uc.Chrome(service=chrome_service, options=options, suppress_welcome=False)
is_local_chrome_browser_lower = False
try:
driver = uc.Chrome(executable_path=chromedriver_path, options=options, desired_capabilities=caps, suppress_welcome=False)
except Exception as exc:
error_message = str(exc)
left_part = None
if "Stacktrace:" in error_message:
left_part = error_message.split("Stacktrace:")[0]
print(left_part)
if "This version of ChromeDriver only supports Chrome version" in error_message:
print(CONST_CHROME_VERSION_NOT_MATCH_EN)
print(CONST_CHROME_VERSION_NOT_MATCH_TW)
is_local_chrome_browser_lower = True
pass
if is_local_chrome_browser_lower:
print("Use local user downloaded chromedriver to lunch chrome browser.")
driver_type = "selenium"
driver = load_chromdriver_normal(webdriver_path, driver_type, adblock_plus_enable)
else:
print("Oops! web driver not on path:",chromedriver_path )
print('let uc automatically download chromedriver.')
try:
driver = uc.Chrome(options=options, desired_capabilities=caps, suppress_welcome=False)
except Exception as exc:
error_message = str(exc)
left_part = None
if "Stacktrace:" in error_message:
left_part = error_message.split("Stacktrace:")[0]
print(left_part)
if "This version of ChromeDriver only supports Chrome version" in error_message:
print(CONST_CHROME_VERSION_NOT_MATCH_EN)
print(CONST_CHROME_VERSION_NOT_MATCH_TW)
is_local_chrome_browser_lower = True
pass
if driver is None:
print("create web drive object fail!")
else:
download_dir_path="."
params = {
"behavior": "allow",
"downloadPath": os.path.realpath(download_dir_path)
}
#print("assign setDownloadBehavior.")
driver.execute_cdp_cmd("Page.setDownloadBehavior", params)
#print("driver capabilities", driver.capabilities)
return driver
def close_browser_tabs(driver):
if not driver is None:
try:
window_handles_count = len(driver.window_handles)
if window_handles_count > 1:
driver.switch_to.window(driver.window_handles[1])
driver.close()
driver.switch_to.window(driver.window_handles[0])
except Exception as excSwithFail:
pass
def get_driver_by_config(config_dict):
global driver
homepage = None
browser = None
language = "English"
ticket_number = "2"
auto_press_next_step_button = False # default not checked.
auto_fill_ticket_number = False # default not checked.
auto_guess_options = False # default not checked.
kktix_area_auto_select_mode = ""
kktix_area_keyword = ""
kktix_date_keyword = ""
pass_1_seat_remaining_enable = False # default not checked.
pass_date_is_sold_out_enable = False # default not checked.
auto_reload_coming_soon_page_enable = True # default checked.
area_keyword_1 = ""
area_keyword_2 = ""
area_keyword_3 = ""
area_keyword_4 = ""
date_keyword = ""
date_auto_select_enable = None
date_auto_select_mode = ""
area_auto_select_enable = None
area_auto_select_mode = ""
# read config.
homepage = config_dict["homepage"]
browser = config_dict["browser"]
# output debug message in client side.
ticket_number = str(config_dict["ticket_number"])
pass_1_seat_remaining_enable = config_dict["pass_1_seat_remaining"]
# for ["kktix"]
auto_press_next_step_button = config_dict["kktix"]["auto_press_next_step_button"]
auto_fill_ticket_number = config_dict["kktix"]["auto_fill_ticket_number"]
kktix_area_auto_select_mode = config_dict["kktix"]["area_mode"].strip()
if not kktix_area_auto_select_mode in CONST_SELECT_OPTIONS_ARRAY:
kktix_area_auto_select_mode = CONST_SELECT_ORDER_DEFAULT
kktix_area_keyword_1 = config_dict["kktix"]["area_keyword_1"].strip()
kktix_area_keyword_1_and = config_dict["kktix"]["area_keyword_1_and"].strip()
kktix_area_keyword_2 = config_dict["kktix"]["area_keyword_2"].strip()
kktix_area_keyword_2_and = config_dict["kktix"]["area_keyword_2_and"].strip()
# disable password brute force attack
# PS: because of the question is always variable.
auto_guess_options = config_dict["kktix"]["auto_guess_options"]
# for ["tixcraft"]
date_auto_select_enable = config_dict["tixcraft"]["date_auto_select"]["enable"]
date_auto_select_mode = config_dict["tixcraft"]["date_auto_select"]["mode"]
if not date_auto_select_mode in CONST_SELECT_OPTIONS_ARRAY:
date_auto_select_mode = CONST_SELECT_ORDER_DEFAULT
date_keyword = config_dict["tixcraft"]["date_auto_select"]["date_keyword"].strip()
area_auto_select_enable = config_dict["tixcraft"]["area_auto_select"]["enable"]
area_auto_select_mode = config_dict["tixcraft"]["area_auto_select"]["mode"]
if not area_auto_select_mode in CONST_SELECT_OPTIONS_ARRAY:
area_auto_select_mode = CONST_SELECT_ORDER_DEFAULT
area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"].strip()
area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"].strip()
area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"].strip()
area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"].strip()
pass_date_is_sold_out_enable = config_dict["tixcraft"]["pass_date_is_sold_out"]
auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"]
driver_type = config_dict["webdriver_type"]
# output config:
print("maxbot app version", CONST_APP_VERSION)
print("python version", platform.python_version())
print("platform", platform.platform())
print("homepage", homepage)
print("browser", browser)
print("ticket_number", ticket_number)
print("pass_1_seat_remaining", pass_1_seat_remaining_enable)
print("==[kktix]==")
print(config_dict["kktix"])
print("==[tixcraft]==")
print(config_dict["tixcraft"])
print("==[advanced]==")
print(config_dict["advanced"])
print("webdriver_type", driver_type)
# entry point
if homepage is None:
homepage = ""
if len(homepage) == 0:
homepage = CONST_HOMEPAGE_DEFAULT
Root_Dir = get_app_root()
webdriver_path = os.path.join(Root_Dir, "webdriver")
print("platform.system().lower():", platform.system().lower())
adblock_plus_enable = config_dict["advanced"]["adblock_plus_enable"]
print("adblock_plus_enable:", adblock_plus_enable)
headless = config_dict["advanced"]["headless"]
if browser == "chrome":
# method 6: Selenium Stealth
if driver_type != CONST_WEBDRIVER_TYPE_UC:
driver = load_chromdriver_normal(webdriver_path, driver_type, adblock_plus_enable, headless)
else:
# method 5: uc
# multiprocessing not work bug.
if platform.system().lower()=="windows":
if hasattr(sys, 'frozen'):
from multiprocessing import freeze_support
freeze_support()
driver = load_chromdriver_uc(webdriver_path, adblock_plus_enable, headless)
if browser == "firefox":
# default os is linux/mac
# download url: https://github.com/mozilla/geckodriver/releases
chromedriver_path = os.path.join(webdriver_path,"geckodriver")
if platform.system().lower()=="windows":
chromedriver_path = os.path.join(webdriver_path,"geckodriver.exe")
if "macos" in platform.platform().lower():
if "arm64" in platform.platform().lower():
chromedriver_path = os.path.join(webdriver_path,"geckodriver_arm")
webdriver_service = Service(chromedriver_path)
driver = None
try:
driver = webdriver.Firefox(service=webdriver_service)
except Exception as exc:
error_message = str(exc)
left_part = None
if "Stacktrace:" in error_message:
left_part = error_message.split("Stacktrace:")[0]
print(left_part)
if browser == "edge":
# default os is linux/mac
# download url: https://developer.microsoft.com/zh-tw/microsoft-edge/tools/webdriver/
chromedriver_path = os.path.join(webdriver_path,"msedgedriver")
if platform.system().lower()=="windows":
chromedriver_path = os.path.join(webdriver_path,"msedgedriver.exe")
webdriver_service = Service(chromedriver_path)
chrome_options, caps = get_chrome_options(webdriver_path, adblock_plus_enable, browser="edge", headless=headless)
driver = None
try:
driver = webdriver.Edge(service=webdriver_service, options=chrome_options)
except Exception as exc:
error_message = str(exc)
#print(error_message)
left_part = None
if "Stacktrace:" in error_message:
left_part = error_message.split("Stacktrace:")[0]
print(left_part)
if browser == "safari":
driver = None
try:
driver = webdriver.Safari()
except Exception as exc:
error_message = str(exc)
#print(error_message)
left_part = None
if "Stacktrace:" in error_message:
left_part = error_message.split("Stacktrace:")[0]
print(left_part)
#print("try to close opened tabs.")
'''
time.sleep(1.0)
for i in range(1):
close_browser_tabs(driver)
'''
if driver is None:
print("create web driver object fail @_@;")
else:
try:
if config_dict["advanced"]["open_google_oauth_url"]:
driver.execute_script("window.open('%s','_blank');" % (URL_GOOGLE_OAUTH));
if 'kktix.c' in homepage:
if len(config_dict["advanced"]["kktix_account"])>0:
if not 'https://kktix.com/users/sign_in?' in homepage:
homepage = CONST_KKTIX_SIGN_IN_URL % (homepage)
if 'famiticket.com' in homepage:
pass
if 'ibon.com' in homepage:
pass
if 'kham.com' in homepage:
if len(config_dict["advanced"]["kham_account"])>0:
homepage = CONST_KHAM_SIGN_IN_URL
if 'urbtix.hk' in homepage:
if len(config_dict["advanced"]["urbtix_account"])>0:
homepage = CONST_URBTIX_SIGN_IN_URL
if 'cityline.com' in homepage:
if len(config_dict["advanced"]["cityline_account"])>0:
homepage = CONST_CITYLINE_SIGN_IN_URL
if 'hkticketing.com' in homepage:
if len(config_dict["advanced"]["hkticketing_account"])>0:
homepage = CONST_HKTICKETING_SIGN_IN_URL
if 'galaxymacau.com' in homepage:
pass
print("goto url:", homepage)
driver.get(homepage)
tixcraft_family = False
if 'tixcraft.com' in homepage:
tixcraft_family = True
if 'indievox.com' in homepage:
tixcraft_family = True
if tixcraft_family:
if len(config_dict["advanced"]["tixcraft_sid"]) > 1:
for i in range(5):
time.sleep(0.5)
tixcraft_home_close_window(driver)
tixcraft_sid = decryptMe(config_dict["advanced"]["tixcraft_sid"])
driver.delete_cookie("SID")
driver.add_cookie({"name":"SID", "value": tixcraft_sid, "path" : "/", "secure":True})
except WebDriverException as exce2:
print('oh no not again, WebDriverException')
print('WebDriverException:', exce2)
except Exception as exce1:
print('get URL Exception:', exce1)
pass
return driver
# common functions.
def find_between( s, first, last ):
try:
start = s.index( first ) + len( first )
end = s.index( last, start )
return s[start:end]
except ValueError:
return ""
# 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 = u"()[]<>{}-"
for idx in range(my_hint_anwser_length):
char = my_str[idx:idx+1]
if char in my_anwser_symbols:
my_formated += (u'\\' + char)
continue
pattern = re.compile(u"[A-Z]")
match_result = pattern.match(char)
#print("match_result A:", match_result)
if not match_result is None:
my_formated += u"[A-Z]"
pattern = re.compile(u"[a-z]")
match_result = pattern.match(char)
#print("match_result a:", match_result)
if not match_result is None:
my_formated += u"[a-z]"
pattern = re.compile(u"[\d]")
match_result = pattern.match(char)
#print("match_result d:", match_result)
if not match_result is None:
my_formated += u"[\d]"
# for dynamic length
if dynamic_length:
for i in range(10):
my_formated = my_formated.replace(u"[A-Z][A-Z]",u"[A-Z]")
my_formated = my_formated.replace(u"[a-z][a-z]",u"[a-z]")
my_formated = my_formated.replace(u"[\d][\d]",u"[\d]")
my_formated = my_formated.replace(u"[A-Z]",u"[A-Z]+")
my_formated = my_formated.replace(u"[a-z]",u"[a-z]+")
my_formated = my_formated.replace(u"[\d]",u"[\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 = None
matched_pattern = ""
if options_list is None:
if u'' in tmp_text and u'' in tmp_text:
pattern = '【.*?】'
options_list = re.findall(pattern, tmp_text)
if len(options_list) <= 2:
options_list = None
else:
matched_pattern = pattern
if options_list is None:
if u'(' in tmp_text and u')' in tmp_text:
pattern = '\(.*?\)'
options_list = re.findall(pattern, tmp_text)
if len(options_list) <= 2:
options_list = None
else:
matched_pattern = pattern
if options_list is None:
if u'[' in tmp_text and u']' in tmp_text:
pattern = '\[.*?\]'
options_list = re.findall(pattern, tmp_text)
if len(options_list) <= 2:
options_list = None
else:
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 = None
if not options_list is None:
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 is_trim_quota:
return_list.append(each_option[1:-1])
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 those options.
if not return_list is None:
if len(return_list) <= 2:
return_list = None
return return_list
#PS: this may get a wrong answer list. XD
def guess_answer_list_from_symbols(captcha_text_div_text):
return_list = None
# need replace to space to get first options.
tmp_text = captcha_text_div_text
tmp_text = tmp_text.replace(u'?',u' ')
tmp_text = tmp_text.replace(u'',u' ')
tmp_text = tmp_text.replace(u'',u' ')
delimitor_symbols_left = [u"(",u"[",u"{", " ", " ", " ", " "]
delimitor_symbols_right = [u")",u"]",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 u'半形' in tmp_text:
hint_list = re.findall(u'\\'+ symbol_left + u'[\\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 not return_list is None:
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 u'' in tmp_text and u'' in tmp_text:
hint_list = re.findall(u'【.*?】', 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 u'(' in tmp_text and u')' in tmp_text:
hint_list = re.findall(u'\(.*?\)', 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 u'[' in tmp_text and u']' in tmp_text:
hint_list = re.findall(u'[.*?]', 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
return_list = None
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 u"?" in tmp_text:
question_index = tmp_text.find(u"?")
my_question = tmp_text[:question_index+1]
if my_question == "":
if u"" in tmp_text:
question_index = tmp_text.find(u"")
my_question = tmp_text[:question_index+1]
if my_question == "":
my_question = tmp_text
#print(u"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 u'答案' 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 = u"*"
if target_symbol in tmp_text :
star_index = tmp_text.find(target_symbol)
space_index = tmp_text.find(u" ", 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(u" ", next_block_index)
next_block = tmp_text[next_block_index: space_index]
if CONST_EXAMPLE_SYMBOL in next_block:
offical_hint_string += u' ' + next_block
# try rule5:
# get hint from rule 3: n個半形英文大寫
if len(offical_hint_string) == 0:
target_symbol = u"個半形英文大寫"
if target_symbol in tmp_text :
star_index = tmp_text.find(target_symbol)
space_index = tmp_text.find(u" ", star_index)
answer_char_count = tmp_text[star_index-1:star_index]
if answer_char_count.isnumeric():
star_index -= 1
offical_hint_string_anwser = u'A' * int(answer_char_count)
offical_hint_string = tmp_text[star_index: space_index]
target_symbol = u"個英文大寫"
if target_symbol in tmp_text :
star_index = tmp_text.find(target_symbol)
space_index = tmp_text.find(u" ", star_index)
answer_char_count = tmp_text[star_index-1:star_index]
if answer_char_count.isnumeric():
star_index -= 1
offical_hint_string_anwser = u'A' * int(answer_char_count)
offical_hint_string = tmp_text[star_index: space_index]
target_symbol = u"個半形英文小寫"
if target_symbol in tmp_text :
star_index = tmp_text.find(target_symbol)
space_index = tmp_text.find(u" ", star_index)
answer_char_count = tmp_text[star_index-1:star_index]
if answer_char_count.isnumeric():
star_index -= 1
offical_hint_string_anwser = u'a' * int(answer_char_count)
offical_hint_string = tmp_text[star_index: space_index]
target_symbol = u"個英文小寫"
if target_symbol in tmp_text :
star_index = tmp_text.find(target_symbol)
space_index = tmp_text.find(u" ", star_index)
answer_char_count = tmp_text[star_index-1:star_index]
if answer_char_count.isnumeric():
star_index -= 1
offical_hint_string_anwser = u'a' * int(answer_char_count)
offical_hint_string = tmp_text[star_index: space_index]
target_symbol = u"個英數半形字"
if target_symbol in tmp_text :
star_index = tmp_text.find(target_symbol)
space_index = tmp_text.find(u" ", star_index)
answer_char_count = tmp_text[star_index-1:star_index]
if answer_char_count.isnumeric():
star_index -= 1
my_anwser_formated = u'[A-Za-z\d]' * int(answer_char_count)
offical_hint_string = tmp_text[star_index: space_index]
target_symbol = u"個半形"
if target_symbol in tmp_text :
star_index = tmp_text.find(target_symbol)
space_index = tmp_text.find(u" ", star_index)
answer_char_count = tmp_text[star_index-1:star_index]
if answer_char_count.isnumeric():
star_index -= 1
my_anwser_formated = u'[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,u"")
my_options = my_options.replace(offical_hint_string,u"")
# 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(u'Ex:','ex:')
target_symbol = u"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()
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(u"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)
if len(my_anwser_formated) > 0:
new_pattern = my_anwser_formated
if len(my_answer_delimitor) > 0:
new_pattern = my_anwser_formated + u'\\' + 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)
# 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)
return return_list
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(u' ',u' ')
tmp_text = tmp_text.replace(u'',u':')
# for hint
tmp_text = tmp_text.replace(u'*',u'*')
# replace ex.
tmp_text = tmp_text.replace(u'例如', CONST_EXAMPLE_SYMBOL)
tmp_text = tmp_text.replace(u'如:', CONST_EXAMPLE_SYMBOL)
tmp_text = tmp_text.replace(u'如為', CONST_EXAMPLE_SYMBOL+'')
tmp_text = tmp_text.replace(u'舉例', CONST_EXAMPLE_SYMBOL)
if not CONST_EXAMPLE_SYMBOL in tmp_text:
tmp_text = tmp_text.replace(u'', CONST_EXAMPLE_SYMBOL)
# important, maybe 例 & ex occurs at same time.
tmp_text = tmp_text.replace(u'ex:', CONST_EXAMPLE_SYMBOL)
tmp_text = tmp_text.replace(u'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(u'填入', CONST_INPUT_SYMBOL)
#tmp_text = tmp_text.replace(u'[',u'(')
#tmp_text = tmp_text.replace(u']',u')')
tmp_text = tmp_text.replace(u'',u'?')
tmp_text = tmp_text.replace(u'',u'(')
tmp_text = tmp_text.replace(u'',u')')
return tmp_text
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 = None
tmp_text = format_question_string(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text)
# guess answer list from multi-options: 【】() []
if return_list is None:
return_list = guess_answer_list_from_multi_options(tmp_text)
if show_debug_message:
if not return_list is None:
print("guess_answer_list_from_multi_options:", return_list)
if return_list is None:
return_list = guess_answer_list_from_hint(CONST_EXAMPLE_SYMBOL, CONST_INPUT_SYMBOL, captcha_text_div_text)
if show_debug_message:
if not return_list is None:
print("guess_answer_list_from_hint:", return_list)
if return_list is None:
return_list = guess_answer_list_from_symbols(captcha_text_div_text)
if show_debug_message:
if not return_list is None:
print("guess_answer_list_from_symbols:", return_list)
return return_list
# close some div on home url.
def tixcraft_home_close_window(driver):
show_debug_message = True # debug.
show_debug_message = False # online
accept_all_cookies_btn = None
try:
accept_all_cookies_btn = driver.find_element(By.ID, 'onetrust-accept-btn-handler')
except Exception as exc:
if show_debug_message:
print("find accept_all_cookies_btn fail")
pass
if accept_all_cookies_btn is not None:
is_visible = False
try:
if accept_all_cookies_btn.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
if show_debug_message:
print("accept_all_cookies_btn visible. start to press.")
try:
accept_all_cookies_btn.click()
except Exception as exc:
print("try to click accept_all_cookies_btn fail, force click by js.")
try:
driver.execute_script("arguments[0].click();", accept_all_cookies_btn)
except Exception as exc:
pass
else:
if show_debug_message:
print("accept_all_cookies_btn invisible.")
close_all_alert_btns = None
try:
close_all_alert_btns = driver.find_elements(By.CSS_SELECTOR, "[class='close-alert']")
except Exception as exc:
print("find close_all_alert_btns fail")
if close_all_alert_btns is not None:
#print('alert count:', len(close_all_alert_btns))
for alert_btn in close_all_alert_btns:
# fix bug: Message: stale element reference: element is not attached to the page document
is_visible = False
try:
if alert_btn.is_enabled() and alert_btn.is_displayed():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
alert_btn.click()
except Exception as exc:
print("try to click alert_btn fail, force click by js.")
try:
driver.execute_script("arguments[0].click();", alert_btn)
except Exception as exc:
pass
# from detail to game
def tixcraft_redirect(driver, url):
ret = False
game_name = ""
# get game_name from url
url_split = url.split("/")
if len(url_split) >= 6:
game_name = url_split[5]
if "/activity/detail/%s" % (game_name,) in url:
# to support teamear
entry_url = url.replace("/activity/detail/","/activity/game/")
print("redirec to new url:", entry_url)
try:
driver.get(entry_url)
except Exception as exec1:
pass
ret = True
return ret
def tixcraft_date_auto_select(driver, url, config_dict, domain_name):
show_debug_message = True # debug.
show_debug_message = False # online
# read config.
date_auto_select_mode = config_dict["tixcraft"]["date_auto_select"]["mode"]
date_keyword = config_dict["tixcraft"]["date_auto_select"]["date_keyword"].strip()
pass_date_is_sold_out_enable = config_dict["tixcraft"]["pass_date_is_sold_out"]
auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"]
# PS: for big events, check sold out text maybe not helpful, due to database is too busy.
sold_out_text_list = ["選購一空","No tickets available","空席なし"]
game_name = ""
if "/activity/game/" in url:
url_split = url.split("/")
if len(url_split) >= 6:
game_name = url_split[5]
if show_debug_message:
print('get date game_name:', game_name)
print("date_auto_select_mode:", date_auto_select_mode)
print("date_keyword:", date_keyword)
check_game_detail = False
# choose date
if "/activity/game/%s" % (game_name,) in url:
if show_debug_message:
if len(date_keyword) == 0:
print("date keyword is empty.")
else:
print("date keyword:", date_keyword)
check_game_detail = True
date_list = None
if check_game_detail:
try:
date_list = driver.find_elements(By.CSS_SELECTOR, '#gameList > table > tbody > tr')
except Exception as exc:
print("find #gameList fail")
is_coming_soon = False
coming_soon_condictions_list = ['開賣','剩餘','','小時','分鐘','','0',':','/']
button_list = None
if date_list is not None:
button_list = []
for row in date_list:
# step 1: check keyword.
is_match_keyword_row = False
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
# should use continue or break?
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
is_match_all_coming_soon_condiction = True
for condiction_string in coming_soon_condictions_list:
if not condiction_string in row_text:
is_match_all_coming_soon_condiction = False
break
if is_match_all_coming_soon_condiction:
is_coming_soon = True
break
if len(date_keyword) == 0:
# no keyword, match all.
is_match_keyword_row = True
else:
# check keyword.
if date_keyword in row_text:
is_match_keyword_row = True
# step 2: check sold out.
if is_match_keyword_row:
if pass_date_is_sold_out_enable:
for sold_out_item in sold_out_text_list:
row_text_right_part = row_text[(len(sold_out_item)+5)*-1:]
if show_debug_message:
print("check right part text:", row_text_right_part)
if sold_out_item in row_text_right_part:
is_match_keyword_row = False
if show_debug_message:
print("match sold out text: %s, skip this row." % (sold_out_item))
# no need check next language item.
break
# step 3: add to list.
if is_match_keyword_row:
el = None
try:
el = row.find_element(By.CSS_SELECTOR, 'button')
except Exception as exc:
if show_debug_message:
print("find button fail")
pass
if el is not None:
button_list.append(el)
if date_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
# only need one row.
if show_debug_message:
print("match date row, only need first row, start to break")
break
is_date_selected = False
if button_list is not None:
if len(button_list) > 0:
# default first row.
target_row_index = 0
if date_auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(button_list) - 1
if date_auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(button_list)-1)
if show_debug_message:
print("clicking at button index:", target_row_index+1)
el = None
try:
el = button_list[target_row_index]
if show_debug_message:
print("pressing button...")
el.click()
'''
ticket_url = el.get_attribute('data-href')
is_redirected = False
if not ticket_url is None:
if len(ticket_url) > 0:
driver.get("https:%s%s" % (domain_name, ticket_url))
is_redirected = True
'''
is_date_selected = True
except Exception as exc:
print("try to click button fail, force click by js.")
print(exc)
try:
driver.execute_script("arguments[0].click();", el)
except Exception as exc:
pass
# PS: Is this case need to reload page?
# (A)user input keywords, with matched text, but no hyperlink to click.
# (B)user input keywords, but not no matched text with hyperlink to click.
# [PS]: current reload condition only when
if auto_reload_coming_soon_page_enable:
if is_coming_soon:
if show_debug_message:
print("match is_coming_soon, start to reload page.")
# case 2: match one row is coming soon.
try:
driver.refresh()
except Exception as exc:
pass
else:
if not is_date_selected:
# case 1: No hyperlink button.
el_list = None
try:
el_list = driver.find_elements(By.CSS_SELECTOR, 'button')
if el_list is None:
driver.refresh()
else:
if len(el_list) == 0:
driver.refresh()
except Exception as exc:
pass
return is_date_selected
# PURPOSE: get target area list.
# RETURN:
# is_need_refresh
# matched_blocks
# PS: matched_blocks will be None, if length equals zero.
def get_tixcraft_target_area(el, area_keyword, area_auto_select_mode, pass_1_seat_remaining_enable):
show_debug_message = True # debug.
show_debug_message = False # online
is_need_refresh = False
matched_blocks = None
area_list = None
area_list_count = 0
if el is not None:
try:
area_list = el.find_elements(By.TAG_NAME, 'a')
except Exception as exc:
#print("find area list a tag fail")
pass
if area_list is not None:
area_list_count = len(area_list)
if area_list_count == 0:
print("area list is empty, do refresh!")
is_need_refresh = True
else:
print("area list is None, do refresh!")
is_need_refresh = True
if area_list_count > 0:
matched_blocks = []
for row in area_list:
row_is_enabled=False
try:
row_is_enabled = row.is_enabled()
except Exception as exc:
pass
row_text = ""
if row_is_enabled:
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
# clean stop word.
row_text = format_keyword_string(row_text)
is_append_this_row = False
if len(area_keyword) > 0:
# clean stop word.
area_keyword = format_keyword_string(area_keyword)
# allow only input stop word in keyword fields.
# for keyword#2 to select all.
if len(area_keyword) > 0:
# must match keyword.
if area_keyword in row_text:
is_append_this_row = True
else:
# without keyword.
is_append_this_row = True
if is_append_this_row:
if show_debug_message:
print("pass_1_seat_remaining_enable:", pass_1_seat_remaining_enable)
if pass_1_seat_remaining_enable:
area_item_font_el = None
try:
#print('try to find font tag at row:', row_text)
area_item_font_el = row.find_element(By.TAG_NAME, 'font')
if not area_item_font_el is None:
font_el_text = area_item_font_el.text
if font_el_text is None:
font_el_text = ""
font_el_text = "@%s@" % (font_el_text)
if show_debug_message:
print('font tag text:', font_el_text)
pass
for check_item in CONT_STRING_1_SEATS_REMAINING:
if check_item in font_el_text:
if show_debug_message:
print("match pass 1 seats remaining 1 full text:", row_text)
print("match pass 1 seats remaining 2 font text:", font_el_text)
is_append_this_row = False
else:
#print("row withou font tag.")
pass
except Exception as exc:
#print("find font text in a tag fail:", exc)
pass
if show_debug_message:
print("is_append_this_row:", is_append_this_row)
if is_append_this_row:
matched_blocks.append(row)
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
print("only need first item, break area list loop.")
break
if show_debug_message:
print("row_text:" + row_text)
print("match:" + area_keyword)
if len(matched_blocks) == 0:
matched_blocks = None
is_need_refresh = True
return is_need_refresh, matched_blocks
# PS: auto refresh condition 1: no keyword + no hyperlink.
# PS: auto refresh condition 2: with keyword + no hyperlink.
def tixcraft_area_auto_select(driver, url, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
# read config.
area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"].strip()
area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"].strip()
area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"].strip()
area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"].strip()
area_auto_select_mode = config_dict["tixcraft"]["area_auto_select"]["mode"]
area_keyword_2_enable = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2_enable"]
area_keyword_3_enable = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3_enable"]
area_keyword_4_enable = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4_enable"]
pass_1_seat_remaining_enable = config_dict["pass_1_seat_remaining"]
# disable pass 1 seat remaining when target ticket number is 1.
ticket_number = config_dict["ticket_number"]
if ticket_number == 1:
pass_1_seat_remaining_enable = False
if show_debug_message:
print("area_keyword_1, area_keyword_2:", area_keyword_1, area_keyword_2)
print("area_keyword_3, area_keyword_4:", area_keyword_3, area_keyword_4)
if '/ticket/area/' in url:
#driver.switch_to.default_content()
el = None
try:
el = driver.find_element(By.CSS_SELECTOR, '.zone')
except Exception as exc:
print("find .zone fail, do nothing.")
if el is not None:
is_need_refresh, areas = get_tixcraft_target_area(el, area_keyword_1, area_auto_select_mode, pass_1_seat_remaining_enable)
if show_debug_message:
print("is_need_refresh for keyword1:", is_need_refresh)
if is_need_refresh:
if areas is None:
if show_debug_message:
print("use area keyword #2", area_keyword_2)
# only when keyword#2 filled to query.
if area_keyword_2_enable:
is_need_refresh, areas = get_tixcraft_target_area(el, area_keyword_2, area_auto_select_mode, pass_1_seat_remaining_enable)
if show_debug_message:
print("is_need_refresh for keyword2:", is_need_refresh)
if is_need_refresh:
if areas is None:
if show_debug_message:
print("use area keyword #3", area_keyword_3)
# only when keyword#3 filled to query.
if area_keyword_3_enable:
is_need_refresh, areas = get_tixcraft_target_area(el, area_keyword_3, area_auto_select_mode, pass_1_seat_remaining_enable)
if show_debug_message:
print("is_need_refresh for keyword3:", is_need_refresh)
if is_need_refresh:
if areas is None:
if show_debug_message:
print("use area keyword #4", area_keyword_4)
# only when keyword#4 filled to query.
if area_keyword_4_enable:
is_need_refresh, areas = get_tixcraft_target_area(el, area_keyword_4, area_auto_select_mode, pass_1_seat_remaining_enable)
if show_debug_message:
print("is_need_refresh for keyword4:", is_need_refresh)
area_target = None
if areas is not None:
#print("area_auto_select_mode", area_auto_select_mode)
#print("len(areas)", len(areas))
if len(areas) > 0:
target_row_index = 0
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if area_auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(areas)-1
if area_auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(areas)-1)
#print("target_row_index", target_row_index)
area_target = areas[target_row_index]
if area_target is not None:
try:
#print("area text:", area_target.text)
area_target.click()
except Exception as exc:
print("click area a link fail, start to retry...")
try:
driver.execute_script("arguments[0].click();", area_target)
except Exception as exc:
print("click area a link fail, after reftry still fail.")
print(exc)
pass
# auto refresh for area list page.
if is_need_refresh:
try:
driver.refresh()
except Exception as exc:
pass
'''
el_selectSeat_iframe = None
try:
el_selectSeat_iframe = driver.find_element_by_xpath("//iframe[contains(@src,'/ticket/selectSeat/')]")
except Exception as exc:
#print("find seat iframe fail")
pass
if el_selectSeat_iframe is not None:
driver.switch_to.frame(el_selectSeat_iframe)
# click one seat
el_seat = None
try:
el_seat = driver.find_element(By.CSS_SELECTOR, '.empty')
if el_seat is not None:
try:
el_seat.click()
except Exception as exc:
#print("click area button fail")
pass
except Exception as exc:
print("find empty seat fail")
# click submit button
el_confirm_seat = None
try:
el_confirm_seat = driver.find_element(By.ID, 'submitSeat')
if el_confirm_seat is not None:
try:
el_confirm_seat.click()
except Exception as exc:
#print("click area button fail")
pass
except Exception as exc:
print("find submitSeat fail")
'''
def tixcraft_ticket_agree(driver):
click_plan = "A"
#click_plan = "B"
# check agree
form_checkbox = None
if click_plan == "A":
try:
form_checkbox = driver.find_element(By.ID, 'TicketForm_agree')
except Exception as exc:
print("find TicketForm_agree fail")
is_finish_checkbox_click = False
if form_checkbox is not None:
try:
# TODO: check the status: checked.
if form_checkbox.is_enabled():
if not form_checkbox.is_selected():
form_checkbox.click()
is_finish_checkbox_click = True
except Exception as exc:
print("click TicketForm_agree fail")
pass
# 使用 plan B.
#if not is_finish_checkbox_click:
# alway not use Plan B.
if False:
try:
print("use plan_b to check TicketForm_agree.")
driver.execute_script("$(\"input[type='checkbox']\").prop('checked', true);")
#driver.execute_script("document.getElementById(\"TicketForm_agree\").checked;")
is_finish_checkbox_click = True
except Exception as exc:
print("javascript check TicketForm_agree fail")
print(exc)
pass
return is_finish_checkbox_click
def tixcraft_ticket_number_auto_fill(driver, select_obj, ticket_number):
is_ticket_number_assigned = False
if select_obj is not None:
try:
# target ticket number
select_obj.select_by_visible_text(ticket_number)
#select.select_by_value(ticket_number)
#select.select_by_index(int(ticket_number))
is_ticket_number_assigned = True
except Exception as exc:
print("select_by_visible_text ticket_number fail")
print(exc)
try:
# target ticket number
select_obj.select_by_visible_text(ticket_number)
#select.select_by_value(ticket_number)
#select.select_by_index(int(ticket_number))
is_ticket_number_assigned = True
except Exception as exc:
print("select_by_visible_text ticket_number fail...2")
print(exc)
# try buy one ticket
try:
select_obj.select_by_visible_text("1")
#select.select_by_value("1")
#select.select_by_index(int(ticket_number))
is_ticket_number_assigned = True
except Exception as exc:
print("select_by_visible_text 1 fail")
pass
# Plan B.
# if not is_ticket_number_assigned:
if False:
if select is not None:
try:
# target ticket number
#select.select_by_visible_text(ticket_number)
print("assign ticker number by jQuery:",ticket_number)
driver.execute_script("$(\"input[type='select']\").val(\""+ ticket_number +"\");")
is_ticket_number_assigned = True
except Exception as exc:
print("jQuery select_by_visible_text ticket_number fail (after click.)")
print(exc)
return is_ticket_number_assigned
def guess_tixcraft_question(driver):
show_debug_message = True # debug.
show_debug_message = False # online
inferred_answer_string = None
answer_list = []
form_select = None
try:
form_select = driver.find_element(By.CSS_SELECTOR, '.zone-verify')
except Exception as exc:
print("find verify textbox fail")
pass
question_text = None
if form_select is not None:
try:
question_text = form_select.text
except Exception as exc:
print("get text fail")
formated_html_text = ""
if question_text is not None:
if len(question_text) > 0:
# format question text.
formated_html_text = question_text
formated_html_text = formated_html_text.replace(u'',u'')
formated_html_text = formated_html_text.replace(u'',u'')
formated_html_text = formated_html_text.replace(u'',u'')
formated_html_text = formated_html_text.replace(u'',u'')
formated_html_text = formated_html_text.replace(u'[',u'')
formated_html_text = formated_html_text.replace(u'',u'')
formated_html_text = formated_html_text.replace(u'',u'')
formated_html_text = formated_html_text.replace(u'',u'')
formated_html_text = formated_html_text.replace(u'',u'')
formated_html_text = formated_html_text.replace(u']',u'')
if u'' in formated_html_text and u'' in formated_html_text:
# PS: 這個太容易沖突,因為問題類型太多,不能直接使用。
#inferred_answer_string = find_between(formated_html_text, u"【", u"】")
pass
if show_debug_message:
print("formated_html_text:", formated_html_text)
is_options_in_question = False
# 請輸入"YES",代表您已詳閱且瞭解並同意。
if inferred_answer_string is None:
if u'輸入"YES"' in formated_html_text:
if u'已詳閱' in formated_html_text or '請詳閱' in formated_html_text:
if u'同意' 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:
inferred_answer_string, answer_list = get_answer_list_from_question_string(None, question_text)
return inferred_answer_string, answer_list
def tixcraft_verify(driver, presale_code, presale_code_delimiter, answer_index):
show_debug_message = True # debug.
show_debug_message = False # online
inferred_answer_string = None
answer_list = []
is_retry_user_single_answer = False
if len(presale_code) > 0:
if len(presale_code_delimiter) > 0:
if presale_code_delimiter in presale_code:
answer_list = presale_code.split(presale_code_delimiter)
if len(answer_list) > 0:
if answer_index < len(answer_list)-1:
inferred_answer_string = answer_list[answer_index+1]
else:
is_retry_user_single_answer = True
if answer_index < 2:
inferred_answer_string = presale_code
if inferred_answer_string is None:
inferred_answer_string, answer_list = guess_tixcraft_question(driver)
if inferred_answer_string is None:
if not answer_list is None:
if len(answer_list) > 0:
if answer_index < len(answer_list)-1:
inferred_answer_string = answer_list[answer_index+1]
if show_debug_message:
print("answer_index:", answer_index)
print("inferred_answer_string:", inferred_answer_string)
print("answer_index:", answer_index)
print("is_retry_user_single_answer:", is_retry_user_single_answer)
form_input = None
try:
form_input = driver.find_element(By.CSS_SELECTOR, "input[name='checkCode']")
except Exception as exc:
print("find verify code fail")
pass
inputed_value = None
if form_input is not None:
try:
inputed_value = form_input.get_attribute('value')
except Exception as exc:
print("find verify code fail")
pass
if inputed_value is None:
inputed_value = ""
if not inferred_answer_string is None:
is_password_sent = False
if len(inputed_value)==0:
try:
# PS: sometime may send key twice...
form_input.clear()
form_input.send_keys(inferred_answer_string)
form_input.send_keys(Keys.ENTER)
is_password_sent = True
# guess answer mode.
answer_index += 1
if show_debug_message:
print("sent password by bot:", inferred_answer_string)
except Exception as exc:
pass
else:
if inputed_value == inferred_answer_string:
if show_debug_message:
print("sent password by previous time.")
is_password_sent = True
try:
form_input.send_keys(Keys.ENTER)
except Exception as exc:
pass
if is_retry_user_single_answer:
# increase counter for waiting for stop retry.
answer_index += 1
else:
# guess answer mode.
if answer_index > -1:
# here not is first option.
inferred_answer_previous = None
if answer_index < len(answer_list)-1:
inferred_answer_previous = answer_list[answer_index]
if inputed_value == inferred_answer_previous:
try:
form_input.clear()
form_input.send_keys(inferred_answer_string)
form_input.send_keys(Keys.ENTER)
is_password_sent = True
if show_debug_message:
print("sent password by bot:", inferred_answer_string, "at index:", answer_index+2)
answer_index += 1
except Exception as exc:
pass
if is_password_sent:
for i in range(3):
time.sleep(0.1)
alert_ret = check_pop_alert(driver)
if alert_ret:
if show_debug_message:
print("press accept button at time #", i+1)
break
else:
if len(inputed_value)==0:
try:
form_input.click()
except Exception as exc:
pass
return answer_index
def tixcraft_change_captcha(driver,url):
try:
driver.execute_script(f"document.querySelector('.verify-img').children[0].setAttribute('src','{url}');")
except Exception as exc:
print("edit captcha element fail")
def tixcraft_toast(driver, message):
toast_element = None
try:
my_css_selector = ".remark-word"
toast_element = driver.find_element(By.CSS_SELECTOR, my_css_selector)
if not toast_element is None:
driver.execute_script("arguments[0].innerHTML='%s';" % message, toast_element)
except Exception as exc:
print("find toast element fail")
def tixcraft_keyin_captcha_code(driver, answer = "", auto_submit = False):
is_verifyCode_editing = False
is_form_sumbited = False
# manually keyin verify code.
# start to input verify code.
form_verifyCode = None
try:
form_verifyCode = driver.find_element(By.ID, 'TicketForm_verifyCode')
except Exception as exc:
print("find form_verifyCode fail")
if form_verifyCode is not None:
is_visible = False
try:
if form_verifyCode.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
form_verifyCode.click()
is_verifyCode_editing = True
except Exception as exc:
print("click form_verifyCode fail, tring to use javascript.")
# plan B
try:
driver.execute_script("document.getElementById(\"TicketForm_verifyCode\").focus();")
is_verifyCode_editing = True
except Exception as exc:
print("click form_verifyCode fail.")
#print("start to fill answer.")
try:
if len(answer) > 0:
form_verifyCode.send_keys(answer)
if auto_submit:
form_verifyCode.send_keys(Keys.ENTER)
is_verifyCode_editing = False
is_form_sumbited = True
else:
driver.execute_script("document.getElementById(\"TicketForm_verifyCode\").select();")
if len(answer) > 0:
tixcraft_toast(driver, "※ 按 Enter 如果答案是: " + answer)
except Exception as exc:
print("send_keys ocr answer fail.")
return is_verifyCode_editing, is_form_sumbited
def tixcraft_reload_captcha(driver, domain_name):
# manually keyin verify code.
# start to input verify code.
ret = False
form_captcha = None
try:
image_id = 'TicketForm_verifyCode-image'
if 'indievox.com' in domain_name:
image_id = 'TicketForm_verifyCode-image'
form_captcha = driver.find_element(By.ID, image_id)
if not form_captcha is None:
form_captcha.click()
ret = True
except Exception as exc:
print("find form_captcha fail")
return ret
#PS: credit to LinShihJhang's share
def tixcraft_auto_ocr(driver, ocr, away_from_keyboard_enable, previous_answer, Captcha_Browser, ocr_captcha_image_source, domain_name):
show_debug_message = True # debug.
show_debug_message = False # online
print("start to ddddocr")
is_need_redo_ocr = False
is_form_sumbited = False
orc_answer = None
if not ocr is None:
if show_debug_message:
print("away_from_keyboard_enable:", away_from_keyboard_enable)
print("previous_answer:", previous_answer)
print("ocr_captcha_image_source:", ocr_captcha_image_source)
ocr_start_time = time.time()
img_base64 = None
if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_NON_BROWSER:
if not Captcha_Browser is None:
img_base64 = base64.b64decode(Captcha_Browser.Request_Captcha())
if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS:
image_id = 'TicketForm_verifyCode-image'
if 'indievox.com' in domain_name:
image_id = 'TicketForm_verifyCode-image'
try:
form_verifyCode_base64 = driver.execute_async_script("""
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var img = document.getElementById('%s');
canvas.height = img.naturalHeight;
canvas.width = img.naturalWidth;
context.drawImage(img, 0, 0);
callback = arguments[arguments.length - 1];
callback(canvas.toDataURL());
""" % (image_id))
img_base64 = base64.b64decode(form_verifyCode_base64.split(',')[1])
except Exception as exc:
if show_debug_message:
print("canvas exception:", str(exc))
pass
if not img_base64 is None:
try:
orc_answer = ocr.classification(img_base64)
except Exception as exc:
pass
else:
if previous_answer is None:
# page is not ready, retry again.
# PS: usually occur in async script get captcha image.
is_need_redo_ocr = True
time.sleep(0.1)
ocr_done_time = time.time()
ocr_elapsed_time = ocr_done_time - ocr_start_time
print("ocr elapsed time:", "{:.3f}".format(ocr_elapsed_time))
else:
print("ddddocr is None")
if not orc_answer is None:
orc_answer = orc_answer.strip()
print("orc_answer:", orc_answer)
if len(orc_answer)==4:
who_care_var, is_form_sumbited = tixcraft_keyin_captcha_code(driver, answer = orc_answer, auto_submit = away_from_keyboard_enable)
else:
if not away_from_keyboard_enable:
tixcraft_keyin_captcha_code(driver)
tixcraft_toast(driver, "※ OCR辨識失敗Q_Q驗證碼請手動輸入...")
else:
is_need_redo_ocr = True
if previous_answer != orc_answer:
previous_answer = orc_answer
print("click captcha again.")
if True:
# selenium solution.
tixcraft_reload_captcha(driver, domain_name)
if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS:
time.sleep(0.1)
else:
# Non_Browser solution.
if not Captcha_Browser is None:
new_captcha_url = Captcha_Browser.Request_Refresh_Captcha() #取得新的CAPTCHA
if new_captcha_url != "":
tixcraft_change_captcha(driver, new_captcha_url) #更改CAPTCHA圖
else:
print("orc_answer is None")
print("previous_answer:", previous_answer)
if previous_answer is None:
tixcraft_keyin_captcha_code(driver)
else:
# page is not ready, retry again.
# PS: usually occur in async script get captcha image.
# PS: previous answer is not none means OCR object works.
# some user enable OCR feature, but component create fail, ex: macOS arm CPU.
is_need_redo_ocr = True
return is_need_redo_ocr, previous_answer, is_form_sumbited
def tixcraft_ticket_main(driver, config_dict, ocr, Captcha_Browser, domain_name):
auto_check_agree = config_dict["auto_check_agree"]
ocr_captcha_enable = config_dict["ocr_captcha"]["enable"]
away_from_keyboard_enable = config_dict["ocr_captcha"]["force_submit"]
if not ocr_captcha_enable:
away_from_keyboard_enable = False
ocr_captcha_image_source = config_dict["ocr_captcha"]["image_source"]
if auto_check_agree:
for i in range(3):
is_finish_checkbox_click = tixcraft_ticket_agree(driver)
if is_finish_checkbox_click:
break
# allow agree not enable to assign ticket number.
form_select = None
try:
#form_select = driver.find_element(By.TAG_NAME, 'select')
#PS: select box may appear many in the page with different price.
form_select = driver.find_element(By.CSS_SELECTOR, '.mobile-select')
except Exception as exc:
print("find select fail")
pass
select_obj = None
if form_select is not None:
is_visible = False
try:
if form_select.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
select_obj = Select(form_select)
except Exception as exc:
pass
is_ticket_number_assigned = False
if not select_obj is None:
row_text = None
try:
row_text = select_obj.first_selected_option.text
except Exception as exc:
pass
if not row_text is None:
if len(row_text) > 0:
if row_text != "0":
# ticket assign.
is_ticket_number_assigned = True
is_verifyCode_editing = False
# must wait select object ready to assign ticket number.
if not is_ticket_number_assigned:
# only this case:"ticket number changed by bot" to play sound!
# PS: I assume each time assign ticket number will succufully changed, so let sound play first.
check_and_play_sound_for_captcha(config_dict)
ticket_number = str(config_dict["ticket_number"])
is_ticket_number_assigned = tixcraft_ticket_number_auto_fill(driver, select_obj, ticket_number)
# must wait ticket number assign to focus captcha.
if is_ticket_number_assigned:
if not ocr_captcha_enable:
is_verifyCode_editing = tixcraft_keyin_captcha_code(driver)
else:
previous_answer = None
is_verifyCode_editing = True
for redo_ocr in range(999):
is_need_redo_ocr, previous_answer, is_form_sumbited = tixcraft_auto_ocr(driver, ocr, away_from_keyboard_enable, previous_answer, Captcha_Browser, ocr_captcha_image_source, domain_name)
if is_form_sumbited:
# start next loop.
is_verifyCode_editing = False
break
if not away_from_keyboard_enable:
break
if not is_need_redo_ocr:
break
if is_verifyCode_editing:
print("goto is_verifyCode_editing == True")
return is_verifyCode_editing
def kktix_confirm_order_button(driver):
ret = False
wait = WebDriverWait(driver, 1)
next_step_button = None
try:
# method #3 wait
next_step_button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'div.form-actions a.btn-primary')))
if not next_step_button is None:
if next_step_button.is_enabled():
next_step_button.click()
ret = True
except Exception as exc:
print("wait form-actions div wait to be clickable Exception:")
#print(exc)
pass
if not next_step_button is None:
is_visible = False
try:
if next_step_button.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
driver.execute_script("arguments[0].click();", next_step_button)
ret = True
except Exception as exc:
pass
return ret
# PS: There are two "Next" button in kktix.
# : 1: /events/xxx
# : 2: /events/xxx/registrations/new
# : This is ONLY for case-1, because case-2 lenght >5
def kktix_events_press_next_button(driver):
ret = False
wait = WebDriverWait(driver, 1)
next_step_button = None
try:
# method #3 wait
next_step_button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'div.tickets a.btn-point')))
if not next_step_button is None:
if next_step_button.is_enabled():
next_step_button.click()
ret = True
except Exception as exc:
print("wait form-actions div wait to be clickable Exception:")
#print(exc)
pass
if not next_step_button is None:
is_visible = False
try:
if next_step_button.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
driver.execute_script("arguments[0].click();", next_step_button)
ret = True
except Exception as exc:
pass
return ret
# : This is for case-2 next button.
def kktix_press_next_button(driver):
ret = False
wait = WebDriverWait(driver, 1)
next_step_button = None
try:
# method #1
#form_actions_div = None
#form_actions_div = driver.find_element(By.ID, 'registrationsNewApp')
#next_step_button = form_actions_div.find_element(By.CSS_SELECTOR, 'div.form-actions button.btn-primary')
# method #2
# next_step_button = driver.find_element(By.CSS_SELECTOR, '#registrationsNewApp div.form-actions button.btn-primary')
# method #3 wait
next_step_button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#registrationsNewApp div.form-actions button.btn-primary')))
if not next_step_button is None:
if next_step_button.is_enabled():
next_step_button.click()
ret = True
except Exception as exc:
print("wait form-actions div wait to be clickable Exception:")
print(exc)
#pass
if not next_step_button is None:
is_visible = False
try:
if next_step_button.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
driver.execute_script("arguments[0].click();", next_step_button)
ret = True
except Exception as exc:
pass
return ret
def kktix_captcha_text_value(captcha_inner_div):
ret = ""
if captcha_inner_div is not None:
try:
captcha_password_text = captcha_inner_div.find_element(By.TAG_NAME, "input")
if not captcha_password_text is None:
ret = captcha_password_text.get_attribute('value')
else:
print("find captcha input field fail")
except Exception as exc:
print("find captcha_inner_div Exception:")
#print(exc)
pass
return ret
def kktix_input_captcha_text(captcha_password_input_tag, inferred_answer_string, force_overwrite = False):
show_debug_message = True # debug.
show_debug_message = False # online
is_cpatcha_sent = False
inputed_captcha_text = ""
if not captcha_password_input_tag is None:
if force_overwrite:
try:
captcha_password_input_tag.send_keys(inferred_answer_string)
print("send captcha keys:" + inferred_answer_string)
is_cpatcha_sent = True
inputed_captcha_text = inferred_answer_string
except Exception as exc:
pass
else:
# not force overwrite:
inputed_captcha_text = None
try:
inputed_captcha_text = captcha_password_input_tag.get_attribute('value')
except Exception as exc:
pass
if inputed_captcha_text is None:
inputed_captcha_text = ""
if len(inputed_captcha_text) == 0:
try:
captcha_password_input_tag.send_keys(inferred_answer_string)
print("send captcha keys:" + inferred_answer_string)
is_cpatcha_sent = True
except Exception as exc:
pass
return is_cpatcha_sent
def kktix_travel_price_list(driver, ticket_number, pass_1_seat_remaining_enable, kktix_area_keyword_1, kktix_area_keyword_1_and):
show_debug_message = True # debug.
show_debug_message = False # online
areas = None
is_ticket_number_assigned = False
ticket_price_list = None
try:
ticket_price_list = driver.find_elements(By.CSS_SELECTOR, '.display-table-row')
except Exception as exc:
ticket_price_list = None
print("find ticket-price span Exception:")
print(exc)
pass
price_list_count = 0
if ticket_price_list is not None:
price_list_count = len(ticket_price_list)
if show_debug_message:
print("found price count:", price_list_count)
print("start to travel rows..........")
else:
print("find ticket-price span fail")
is_travel_interrupted = False
if price_list_count > 0:
areas = []
# 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)
if show_debug_message:
print('kktix_area_keyword_1:', kktix_area_keyword_1)
print('kktix_area_keyword_1_and:', kktix_area_keyword_1_and)
row_index = 0
for row in ticket_price_list:
row_index += 1
row_text = ""
try:
row_text = row.text
if show_debug_message:
print("get text:", row_text, ",at row:", row_index)
except Exception as exc:
row_text = ""
is_travel_interrupted = True
print("get text fail.")
if row_text is None:
row_text = ""
if len(row_text) > 0:
# clean stop word.
row_text = format_keyword_string(row_text)
# check ticket input textbox.
ticket_price_input = None
try:
ticket_price_input = row.find_element(By.CSS_SELECTOR, "input[type='text']")
except Exception as exc:
pass
if ticket_price_input is not None:
current_ticket_number = ""
is_visible = False
try:
current_ticket_number = str(ticket_price_input.get_attribute('value')).strip()
is_visible = ticket_price_input.is_enabled()
except Exception as exc:
pass
if len(current_ticket_number) > 0:
if current_ticket_number != "0":
is_ticket_number_assigned = True
if is_ticket_number_assigned:
# no need to travel
break
is_danger_notice = False
if ticket_number > 1:
# start to check danger notice.
span_danger_popup = None
try:
span_danger_popup = row.find_element(By.CSS_SELECTOR, "span.danger")
if span_danger_popup.is_displayed():
is_danger_notice = True
except Exception as exc:
pass
if is_danger_notice:
# skip this row, because assign will fail, or fill ticket number as 1.
if pass_1_seat_remaining_enable:
continue
if is_visible:
is_match_area = False
match_area_code = 0
if len(kktix_area_keyword_1) == 0:
# keyword #1, empty, direct add to list.
is_match_area = True
match_area_code = 1
else:
# MUST match keyword #1.
if kktix_area_keyword_1 in row_text:
#print('match keyword#1')
# because of logic between keywords is AND!
if len(kktix_area_keyword_1_and) == 0:
#print('keyword#2 is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if kktix_area_keyword_1_and in row_text:
#print('match keyword#2')
is_match_area = True
match_area_code = 3
else:
#print('not match keyword#2')
pass
else:
#print('not match keyword#1')
pass
if show_debug_message:
print("is_match_area:", is_match_area)
print("match_area_code:", match_area_code)
if is_match_area:
areas.append(row)
if is_travel_interrupted:
# not sure to break or continue..., maybe break better.
break
else:
if show_debug_message:
print("no any price list found.")
pass
# unknow issue...
if is_travel_interrupted:
pass
return is_ticket_number_assigned, areas
def kktix_assign_ticket_number(driver, ticket_number, pass_1_seat_remaining_enable, kktix_area_auto_select_mode, kktix_area_keyword_1, kktix_area_keyword_1_and):
show_debug_message = True # debug.
show_debug_message = False # online
ticket_number_str = str(ticket_number)
is_ticket_number_assigned, areas = kktix_travel_price_list(driver, ticket_number, pass_1_seat_remaining_enable, kktix_area_keyword_1, kktix_area_keyword_1_and)
target_area = None
if not is_ticket_number_assigned:
if areas is not None:
if len(areas) > 0:
target_row_index = 0
if kktix_area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if kktix_area_auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(areas)-1
if kktix_area_auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(areas)-1)
if show_debug_message:
print("target_row_index", target_row_index)
target_area = areas[target_row_index]
ticket_price_input = None
if target_area is not None:
if show_debug_message:
print('try to get input box element.')
try:
#print("target_area text", target_area.text)
ticket_price_input = target_area.find_element(By.CSS_SELECTOR, "input[type='text']")
except Exception as exc:
pass
current_ticket_number = ""
is_visible = False
if ticket_price_input is not None:
if show_debug_message:
print("try to get input box value.")
try:
current_ticket_number = str(ticket_price_input.get_attribute('value')).strip()
is_visible = ticket_price_input.is_enabled()
except Exception as exc:
pass
if is_visible and len(current_ticket_number) > 0:
if current_ticket_number == "0":
try:
print("asssign ticket number:%s" % ticket_number_str)
ticket_price_input.clear()
ticket_price_input.send_keys(ticket_number_str)
is_ticket_number_assigned = True
except Exception as exc:
print("asssign ticket number to ticket-price field Exception:")
print(exc)
try:
ticket_price_input.clear()
ticket_price_input.send_keys("1")
is_ticket_number_assigned = True
except Exception as exc2:
pass
else:
if show_debug_message:
print("value already assigned.")
# already assigned.
is_ticket_number_assigned = True
return is_ticket_number_assigned
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 el_web_datetime_list is not 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 el_web_datetime_text is not 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 u'/' 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 kktix_check_agree_checkbox(driver):
is_need_refresh = False
is_finish_checkbox_click = False
person_agree_terms_checkbox = None
try:
person_agree_terms_checkbox = driver.find_element(By.ID, 'person_agree_terms')
except Exception as exc:
print("find person_agree_terms checkbox Exception")
pass
if person_agree_terms_checkbox is not None:
is_visible = False
try:
if person_agree_terms_checkbox.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
is_checkbox_checked = False
try:
if person_agree_terms_checkbox.is_selected():
is_checkbox_checked = True
except Exception as exc:
pass
if not is_checkbox_checked:
#print('send check to checkbox')
try:
person_agree_terms_checkbox.click()
is_finish_checkbox_click = True
except Exception as exc:
pass
else:
#print('checked')
is_finish_checkbox_click = True
else:
is_need_refresh = True
else:
is_need_refresh = True
if is_need_refresh:
print("find person_agree_terms checkbox fail, do refresh page.")
return is_need_refresh, is_finish_checkbox_click
def kktix_check_register_status(url):
#ex: https://xxx.kktix.cc/events/xxx
prefix_list = ['.com/events/','.cc/events/']
postfix = '/registrations/new'
is_match_event_code = False
event_code = ""
for prefix in prefix_list:
event_code = find_between(url,prefix,postfix)
if len(event_code) > 0:
is_match_event_code = True
#print('event_code:',event_code)
break
html_result = None
if is_match_event_code:
url = "https://kktix.com/g/events/%s/register_info" % (event_code)
#print('event_code:',event_code)
#print("url:", url)
user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36'
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 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 u'半形' in captcha_text_div_text and u'' in captcha_text_div_text:
if u'演出日期' in captcha_text_div_text:
is_need_parse_web_datetime = True
if u'活動日期' in captcha_text_div_text:
is_need_parse_web_datetime = True
if u'表演日期' in captcha_text_div_text:
is_need_parse_web_datetime = True
if u'開始日期' in captcha_text_div_text:
is_need_parse_web_datetime = True
if u'演唱會日期' in captcha_text_div_text:
is_need_parse_web_datetime = True
if u'展覽日期' in captcha_text_div_text:
is_need_parse_web_datetime = True
if u'音樂會日期' in captcha_text_div_text:
is_need_parse_web_datetime = True
if u'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 u'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 == u"[\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d]":
my_datetime_foramted = "%Y%m%d"
if my_anwser_formated == u"[\\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 = u''
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 = u''
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 = u' '
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 == u"[\\d][\\d][\\d][\\d][\\d][\\d][\\d][\\d]":
my_datetime_foramted = "%Y%m%d"
if my_anwser_formated == u"[\\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,u"%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 u'半形' in captcha_text_div_text:
if u'演出時間' in captcha_text_div_text:
is_need_parse_web_time = True
if u'表演時間' in captcha_text_div_text:
is_need_parse_web_time = True
if u'開始時間' in captcha_text_div_text:
is_need_parse_web_time = True
if u'演唱會時間' in captcha_text_div_text:
is_need_parse_web_time = True
if u'展覽時間' in captcha_text_div_text:
is_need_parse_web_time = True
if u'音樂會時間' in captcha_text_div_text:
is_need_parse_web_time = True
if u'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 = u''
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 = u''
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 = u' '
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(u"my_anwser_formated:", my_anwser_formated)
if my_anwser_formated == u"[\\d][\\d][\\d][\\d]":
my_datetime_foramted = "%H%M"
if u'12小時' in tmp_text:
my_datetime_foramted = "%I%M"
if my_anwser_formated == u"[\\d][\\d]:[\\d][\\d]":
my_datetime_foramted = "%H:%M"
if u'12小時' in tmp_text:
my_datetime_foramted = "%I:%M"
if not my_datetime_foramted is None:
date_delimitor_symbol = u'('
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,u"%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(u"my_anwser:", ans)
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(u'',u'')
keep_symbol_tmp = keep_symbol_tmp.replace(u'必須',u'')
keep_symbol_tmp = keep_symbol_tmp.replace(u'全都',u'')
keep_symbol_tmp = keep_symbol_tmp.replace(u'全部都',u'')
keep_symbol_tmp = keep_symbol_tmp.replace(u'一致',u'相同')
keep_symbol_tmp = keep_symbol_tmp.replace(u'一樣',u'相同')
keep_symbol_tmp = keep_symbol_tmp.replace(u'相等',u'相同')
if u'符號須都相同' in keep_symbol_tmp:
is_need_keep_symbol = True
if u'符號都相同' in keep_symbol_tmp:
is_need_keep_symbol = True
if u'符號須相同' in keep_symbol_tmp:
is_need_keep_symbol = True
# for: 大小寫含括號需一模一樣
keep_symbol_tmp = keep_symbol_tmp.replace(u'', '')
keep_symbol_tmp = keep_symbol_tmp.replace(u'', '')
keep_symbol_tmp = keep_symbol_tmp.replace(u'', '')
keep_symbol_tmp = keep_symbol_tmp.replace(u'還有', '')
keep_symbol_tmp = keep_symbol_tmp.replace(u'', '')
keep_symbol_tmp = keep_symbol_tmp.replace(u'以及', '')
keep_symbol_tmp = keep_symbol_tmp.replace(u'', '')
keep_symbol_tmp = keep_symbol_tmp.replace(u'必須', '')
keep_symbol_tmp = keep_symbol_tmp.replace(u'而且', '')
keep_symbol_tmp = keep_symbol_tmp.replace(u'', '')
keep_symbol_tmp = keep_symbol_tmp.replace(u'一模', '')
#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.
show_debug_message = False # online
inferred_answer_string = None
answer_list = None
CONST_EXAMPLE_SYMBOL = "範例"
CONST_INPUT_SYMBOL = "輸入"
# 請在下方空白處輸入引號內文字:
if inferred_answer_string is None:
is_use_quota_message = False
if u"" in captcha_text_div_text and u"" in captcha_text_div_text:
if u'' in captcha_text_div_text and u'' in captcha_text_div_text and CONST_INPUT_SYMBOL in captcha_text_div_text and u'引號' in captcha_text_div_text and u'' in captcha_text_div_text:
is_use_quota_message = True
if u'半形' in captcha_text_div_text and CONST_INPUT_SYMBOL in captcha_text_div_text and u'引號' in captcha_text_div_text and u'' 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, u"", u"")
#print("find captcha text:" , inferred_answer_string)
if inferred_answer_string is None:
is_use_quota_message = False
if u"" in captcha_text_div_text and u"" in captcha_text_div_text:
if u'' in captcha_text_div_text and u'' in captcha_text_div_text and CONST_INPUT_SYMBOL in captcha_text_div_text and u'引號' in captcha_text_div_text and u'' in captcha_text_div_text:
is_use_quota_message = True
if u'半形' in captcha_text_div_text and CONST_INPUT_SYMBOL in captcha_text_div_text and u'引號' in captcha_text_div_text and u'' 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, u"", u"")
#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 u"name of event" in captcha_text_div_text:
if u'(' in captcha_text_div_text and u')' in captcha_text_div_text and u'ans:' in captcha_text_div_text.lower():
target_symbol = u"("
star_index = captcha_text_div_text.find(target_symbol)
target_symbol = u":"
star_index = captcha_text_div_text.find(target_symbol, star_index)
target_symbol = u")"
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 u"第一題" in captcha_text_div_text and u"第二題" in captcha_text_div_text:
is_combine_two_question = True
if u"Q1." in captcha_text_div_text and u"Q2." in captcha_text_div_text:
if u"二題" in captcha_text_div_text:
is_combine_two_question = True
if u"2題" in captcha_text_div_text:
is_combine_two_question = True
if u"Q1:" in captcha_text_div_text and u"Q2:" in captcha_text_div_text:
if u"二題" in captcha_text_div_text:
is_combine_two_question = True
if u"2題" in captcha_text_div_text:
is_combine_two_question = True
if u"Q1 " in captcha_text_div_text and u"Q2 " in captcha_text_div_text:
if u"二題" in captcha_text_div_text:
is_combine_two_question = True
if u"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)
return inferred_answer_string, answer_list
def kktix_reg_new_captcha(registrationsNewApp_div, captcha_inner_div):
show_debug_message = True # debug.
show_debug_message = False # online
captcha_text_div = None
try:
captcha_text_div = captcha_inner_div.find_element(By.TAG_NAME, "p")
except Exception as exc:
pass
print("find p tag(captcha_text_div) fail")
print(exc)
captcha_text_div_text = None
if captcha_text_div is not None:
try:
captcha_text_div_text = captcha_text_div.text
except Exception as exc:
pass
# try to auto answer options.
answer_list = None
inferred_answer_string = None
if not captcha_text_div_text is None:
if show_debug_message:
print("captcha_text_div_text:", captcha_text_div_text)
inferred_answer_string, answer_list = get_answer_list_from_question_string(registrationsNewApp_div, captcha_text_div_text)
return inferred_answer_string, answer_list
def kktix_double_check_all_text_value(driver, ticket_number_str):
is_do_press_next_button = False
# double check ticket input textbox.
ticket_price_input_list = None
try:
# PS: unable directly access text's value attribute via css selector or xpath on KKTix!
my_css_selector = "input[type='text']"
#print("my_css_selector:", my_css_selector)
ticket_price_input_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
if ticket_price_input_list is not None:
#print("bingo, found one of ticket number textbox.")
row_index = 0
for ticket_price_input in ticket_price_input_list:
row_index += 1
current_ticket_number = ""
try:
current_ticket_number = str(ticket_price_input.get_attribute('value')).strip()
except Exception as exc:
pass
if current_ticket_number is None:
current_ticket_number = ""
if len(current_ticket_number) > 0:
#print(row_index, "current_ticket_number:", current_ticket_number)
if current_ticket_number == ticket_number_str:
#print("bingo, match target ticket number.")
# ONLY, this case to auto press next button.
is_do_press_next_button = True
break
return is_do_press_next_button
def kktix_reg_new_main(driver, answer_index, is_finish_checkbox_click, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
# part 1: check div.
registrationsNewApp_div = None
try:
registrationsNewApp_div = driver.find_element(By.CSS_SELECTOR, '#registrationsNewApp')
except Exception as exc:
pass
#print("find input fail:", exc)
# part 2: assign ticket number
ticket_number_str = str(config_dict["ticket_number"])
pass_1_seat_remaining_enable = config_dict["pass_1_seat_remaining"]
# disable pass 1 seat remaining when target ticket number is 1.
ticket_number = config_dict["ticket_number"]
if ticket_number == 1:
pass_1_seat_remaining_enable = False
is_ticket_number_assigned = False
if not registrationsNewApp_div is None:
kktix_area_auto_select_mode = config_dict["kktix"]["area_mode"]
kktix_area_keyword_1 = config_dict["kktix"]["area_keyword_1"].strip()
kktix_area_keyword_1_and = config_dict["kktix"]["area_keyword_1_and"].strip()
kktix_area_keyword_2 = config_dict["kktix"]["area_keyword_2"].strip()
kktix_area_keyword_2_and = config_dict["kktix"]["area_keyword_2_and"].strip()
kktix_area_keyword_2_enable = config_dict["kktix"]["area_keyword_2_enable"]
for retry_index in range(2):
is_ticket_number_assigned = kktix_assign_ticket_number(driver, ticket_number, pass_1_seat_remaining_enable, kktix_area_auto_select_mode, kktix_area_keyword_1, kktix_area_keyword_1_and)
if not is_ticket_number_assigned:
is_ticket_number_assigned = kktix_assign_ticket_number(driver, ticket_number, pass_1_seat_remaining_enable, kktix_area_auto_select_mode, kktix_area_keyword_1, kktix_area_keyword_1_and)
#PS: keyword_2 not input, means all rows are match.
if not is_ticket_number_assigned:
if kktix_area_keyword_2_enable:
is_ticket_number_assigned = kktix_assign_ticket_number(driver, ticket_number, pass_1_seat_remaining_enable, kktix_area_auto_select_mode, kktix_area_keyword_2, kktix_area_keyword_2_and)
if is_ticket_number_assigned:
break
#print('is_ticket_number_assigned:', is_ticket_number_assigned)
# part 3: captcha
is_captcha_appear = False
is_captcha_appear_and_filled_password = False
answer_list = None
# TODO: in guess options mode, no need to travel div again.
captcha_inner_div = None
if is_ticket_number_assigned:
try:
captcha_inner_div = driver.find_element(By.CSS_SELECTOR, '.custom-captcha-inner')
except Exception as exc:
pass
captcha_password_input_tag = None
if not captcha_inner_div is None:
try:
captcha_password_input_tag = captcha_inner_div.find_element(By.TAG_NAME, "input")
if show_debug_message:
print("found captcha input field")
except Exception as exc:
pass
if not captcha_password_input_tag is None:
inferred_answer_string = None
if captcha_inner_div is not None:
is_captcha_appear = True
if show_debug_message:
print("found captcha_inner_div layor.")
auto_guess_options = config_dict["kktix"]["auto_guess_options"]
user_guess_string = config_dict["kktix"]["user_guess_string"]
if len(user_guess_string) > 0:
inferred_answer_string = user_guess_string
else:
if auto_guess_options:
inferred_answer_string, answer_list = kktix_reg_new_captcha(registrationsNewApp_div, captcha_inner_div)
if inferred_answer_string is not None:
# password is not None, try to send.
is_cpatcha_sent = kktix_input_captcha_text(captcha_password_input_tag, inferred_answer_string)
if is_cpatcha_sent:
is_captcha_appear_and_filled_password = True
else:
is_try_to_focus = False
if answer_list is None:
is_try_to_focus = True
else:
if len(answer_list)==0:
is_try_to_focus = True
if is_try_to_focus:
# password is None, focus to input, and play sound.
inputed_captcha_text = None
try:
inputed_captcha_text = captcha_password_input_tag.get_attribute('value')
except Exception as exc:
pass
if inputed_captcha_text is None:
inputed_captcha_text = ""
if len(inputed_captcha_text) == 0:
try:
#print("focus() captcha to input.")
check_and_play_sound_for_captcha(config_dict)
captcha_password_input_tag.click()
time.sleep(1)
# let user to input answer, bot sleep 1 second.
except Exception as exc:
pass
if show_debug_message:
print("is_captcha_appear:", is_captcha_appear)
print("is_captcha_appear_and_filled_password:", is_captcha_appear_and_filled_password)
# retry check agree checkbox again.
if not is_finish_checkbox_click:
auto_check_agree = config_dict["auto_check_agree"]
if auto_check_agree:
is_need_refresh, is_finish_checkbox_click = kktix_check_agree_checkbox(driver)
is_do_press_next_button = False
if is_ticket_number_assigned:
auto_press_next_step_button = config_dict["kktix"]["auto_press_next_step_button"]
if auto_press_next_step_button:
if is_finish_checkbox_click:
is_do_press_next_button = kktix_double_check_all_text_value(driver, ticket_number_str)
else:
print("still unable to assign checkbox as selected.")
if show_debug_message:
print("is_do_press_next_button:", is_do_press_next_button)
if is_do_press_next_button:
if not is_captcha_appear:
click_ret = kktix_press_next_button(driver)
else:
if is_captcha_appear_and_filled_password:
# for easy guest mode, we can fill the password correct.
#print("for easy guest mode, we can fill the password correct.")
click_ret = kktix_press_next_button(driver)
else:
# not is easy guest mode.
#print("# not is easy guest mode.")
# merge with password dictionary, so need remove duplicate list
# PS: now, there are no password dictionary.
if not answer_list is None:
if len(answer_list) > 1:
unique = [x for i, x in enumerate(answer_list) if answer_list.index(x) == i]
answer_list = unique
# start to try answers.
if not answer_list is None:
# for popular event
if len(answer_list) > 0:
if answer_index < len(answer_list)-1:
if kktix_captcha_text_value(captcha_inner_div) == "":
answer_index += 1
answer_string = answer_list[answer_index]
if len(answer_string) > 0:
print("send answer:" + answer_string)
is_cpatcha_sent = kktix_input_captcha_text(captcha_password_input_tag, answer_string)
if is_cpatcha_sent:
kktix_press_next_button(driver)
else:
# exceed index, do nothing.
pass
else:
# captcha appeared, but we don't have answer list.
pass
return answer_index
def kktix_reg_new(driver, url, answer_index, kktix_register_status_last, config_dict):
registerStatus = kktix_register_status_last
# auto refresh for area list page.
is_need_refresh = False
is_finish_checkbox_click = False
if not is_need_refresh:
if registerStatus is None:
registerStatus = kktix_check_register_status(url)
if not registerStatus is None:
print("registerStatus:", registerStatus)
# OUT_OF_STOCK
if registerStatus != 'IN_STOCK':
is_need_refresh = True
auto_check_agree = config_dict["auto_check_agree"]
if auto_check_agree:
if not is_need_refresh:
is_need_refresh, is_finish_checkbox_click = kktix_check_agree_checkbox(driver)
if not is_need_refresh:
if not is_finish_checkbox_click:
# retry again.
is_need_refresh, is_finish_checkbox_click = kktix_check_agree_checkbox(driver)
#print('check agree_terms_checkbox, is_need_refresh:',is_need_refresh)
if is_need_refresh:
try:
print("try to refresh page...")
driver.refresh()
except Exception as exc:
#print("refresh fail")
pass
# reset answer_index
answer_index = -1
registerStatus = None
else:
# check is able to buy.
auto_fill_ticket_number = config_dict["kktix"]["auto_fill_ticket_number"]
if auto_fill_ticket_number:
answer_index = kktix_reg_new_main(driver, answer_index, is_finish_checkbox_click, config_dict)
return answer_index, registerStatus
# PURPOSE: get target area list.
# PS: this is main block, use keyword to get rows.
# PS: it seems use date_auto_select_mode instead of area_auto_select_mode
def get_fami_target_area(driver, date_keyword, area_keyword_1, area_keyword_2, area_keyword_3, area_keyword_4, area_auto_select_mode):
show_debug_message = True # debug.
show_debug_message = False # online
date_keyword = format_keyword_string(date_keyword)
area_keyword_1 = format_keyword_string(area_keyword_1)
area_keyword_2 = format_keyword_string(area_keyword_2)
area_keyword_3 = format_keyword_string(area_keyword_3)
area_keyword_4 = format_keyword_string(area_keyword_4)
if show_debug_message:
print("try to find area block by keywords...")
area_list = None
try:
my_css_selector = "table.session__list > tbody > tr"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #session date list fail")
if show_debug_message:
print(exc)
#PS: some blocks are generate by ajax, not appear at first time.
formated_area_list = None
if area_list is not None:
area_list_length = len(area_list)
if show_debug_message:
print("lenth of area rows:", area_list_length)
if area_list_length > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
row_is_enabled=True
el_btn = None
try:
my_css_selector = "button"
el_btn = row.find_element(By.TAG_NAME, my_css_selector)
if el_btn is not None:
if not el_btn.is_enabled():
#print("row's button disabled!")
row_is_enabled=False
except Exception as exc:
if show_debug_message:
print(exc)
pass
if row_is_enabled:
formated_area_list.append(row)
matched_blocks = None
if not formated_area_list is None:
if len(formated_area_list) > 0:
matched_blocks = []
if len(date_keyword)==0 and len(area_keyword_1)==0 and len(area_keyword_2) == 0:
# select all.
matched_blocks = formated_area_list
else:
# match keyword.
row_index = 0
for row in formated_area_list:
row_index += 1
#print("row index:", row_index)
date_html_text = ""
area_html_text = ""
row_text = ""
try:
my_css_selector = "td:nth-child(1)"
td_date = row.find_element(By.CSS_SELECTOR, my_css_selector)
if td_date is not None:
#print("date:", td_date.text)
date_html_text = 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 td_area is not None:
#print("area:", td_area.text)
area_html_text = format_keyword_string(td_area.text)
row_text = row.text
except Exception as exc:
print("get row text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
# check date.
is_match_date = False
if len(date_keyword) > 0:
if date_keyword in date_html_text:
#print("is_match_date")
is_match_date = True
else:
is_match_date = True
# check area.
is_match_area = False
if len(area_keyword_1) > 0:
if area_keyword_1 in area_html_text:
#print("is_match_area area_keyword_1")
is_match_area = True
# check keyword 2
if len(area_keyword_2) > 0:
if area_keyword_2 in area_html_text:
#print("is_match_area area_keyword_2")
is_match_area = True
# check keyword 3
if len(area_keyword_3) > 0:
if area_keyword_3 in area_html_text:
#print("is_match_area area_keyword_3")
is_match_area = True
# check keyword 4
if len(area_keyword_4) > 0:
if area_keyword_4 in area_html_text:
#print("is_match_area area_keyword_4")
is_match_area = True
else:
is_match_area = True
if is_match_date and is_match_area:
matched_blocks.append(row)
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
print("only need first item, break area list loop.")
break
return_row_count = 0
if not matched_blocks is None:
return_row_count = len(matched_blocks)
if return_row_count==0:
matched_blocks = None
if show_debug_message:
print("return_row_count:", return_row_count)
return matched_blocks
def fami_activity(driver):
#print("fami_activity bingo")
#---------------------------
# part 1: press "buy" button.
#---------------------------
fami_start_to_buy_button = None
try:
fami_start_to_buy_button = driver.find_element(By.ID, 'buyWaiting')
except Exception as exc:
pass
is_visible = False
if fami_start_to_buy_button is not None:
try:
if fami_start_to_buy_button.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
fami_start_to_buy_button.click()
except Exception as exc:
print("click buyWaiting button fail...")
#print(exc)
#pass
try:
driver.execute_script("arguments[0].click();", fami_start_to_buy_button)
except Exception as exc:
pass
def fami_home(driver, url, config_dict):
#print("fami_home bingo")
is_ticket_number_assigned = False
ticket_number = str(config_dict["ticket_number"])
date_keyword = config_dict["tixcraft"]["date_auto_select"]["date_keyword"].strip()
area_auto_select_mode = config_dict["tixcraft"]["area_auto_select"]["mode"]
area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"].strip()
area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"].strip()
area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"].strip()
area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"].strip()
#---------------------------
# part 3: fill ticket number.
#---------------------------
ticket_el = None
try:
my_css_selector = "tr.ticket > td > select"
ticket_el = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
print("click buyWaiting button fail")
#print(exc)
is_select_box_visible = False
if ticket_el is not None:
try:
if ticket_el.is_enabled():
is_select_box_visible = True
except Exception as exc:
pass
is_ticket_number_assigned = False
if is_select_box_visible:
ticket_number_select = None
try:
ticket_number_select = Select(ticket_el)
except Exception as exc:
pass
if ticket_number_select is not None:
try:
#print("get select ticket value:" + Select(ticket_number_select).first_selected_option.text)
if ticket_number_select.first_selected_option.text=="0" or ticket_number_select.first_selected_option.text=="選擇張數":
# target ticket number
ticket_number_select.select_by_visible_text(ticket_number)
is_ticket_number_assigned = True
except Exception as exc:
print("select_by_visible_text ticket_number fail")
print(exc)
try:
# try target ticket number twice
ticket_number_select.select_by_visible_text(ticket_number)
is_ticket_number_assigned = True
except Exception as exc:
print("select_by_visible_text ticket_number fail...2")
print(exc)
# try buy one ticket
try:
ticket_number_select.select_by_visible_text("1")
is_ticket_number_assigned = True
except Exception as exc:
print("select_by_visible_text 1 fail")
pass
#---------------------------
# part 4: press "next" button.
#---------------------------
if is_ticket_number_assigned:
fami_assign_site_button = None
try:
my_css_selector = "div.col > a.btn"
fami_assign_site_button = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
if fami_assign_site_button is not None:
is_visible = False
try:
if fami_assign_site_button.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
fami_assign_site_button.click()
except Exception as exc:
print("click buyWaiting button fail")
#print(exc)
try:
driver.execute_script("arguments[0].click();", fami_assign_site_button)
except Exception as exc:
pass
areas = None
if not is_select_box_visible:
#---------------------------
# part 2: select keywords
#---------------------------
areas = get_fami_target_area(driver, date_keyword, area_keyword_1, area_keyword_2, area_keyword_3, area_keyword_4, area_auto_select_mode)
area_target = None
if areas is not None:
#print("area_auto_select_mode", area_auto_select_mode)
#print("len(areas)", len(areas))
if len(areas) > 0:
target_row_index = 0
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if area_auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(areas)-1
if area_auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(areas)-1)
#print("target_row_index", target_row_index)
area_target = areas[target_row_index]
if area_target is not None:
el_btn = None
is_visible = False
try:
my_css_selector = "button"
el_btn = area_target.find_element(By.TAG_NAME, my_css_selector)
if el_btn is not None:
if el_btn.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
el_btn.click()
except Exception as exc:
print("click buy button fail, start to retry...")
try:
driver.execute_script("arguments[0].click();", el_btn)
except Exception as exc:
pass
# purpose: date auto select
def urbtix_date_auto_select(driver, auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable):
show_debug_message = True # debug.
show_debug_message = False # online
ret = False
matched_blocks = None
# clean stop word.
date_keyword = format_keyword_string(date_keyword)
date_keyword_and = ""
area_list = None
try:
#print("try to find cityline area block")
my_css_selector = "div.conent-wrapper > div.list-wrapper > ul"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #date-time-position date list fail")
print(exc)
#PS: some blocks are generate by ajax, not appear at first time.
formated_area_list = None
if area_list is not None:
area_list_count = len(area_list)
if show_debug_message:
print("date_list_count:", area_list_count)
if area_list_count > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
row_is_enabled=True
el_btn = None
try:
my_css_selector = "div.buy-icon"
el_btn = row.find_element(By.CSS_SELECTOR, my_css_selector)
if el_btn is not None:
button_class_string = str(el_btn.get_attribute('class'))
if len(button_class_string) > 1:
if 'disabled' in button_class_string:
if show_debug_message:
print("found disabled activity at row:", row_index)
row_is_enabled=False
except Exception as exc:
if show_debug_message:
print(exc)
pass
if row_is_enabled:
formated_area_list.append(row)
if show_debug_message:
print("formated_area_list count:", len(formated_area_list))
if len(date_keyword) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
if show_debug_message:
print("start to match keyword:", date_keyword)
matched_blocks = []
row_index = 0
for row in formated_area_list:
row_index += 1
#row_is_enabled=False
row_is_enabled=True
if row_is_enabled:
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
row_text = format_keyword_string(row_text)
if show_debug_message:
print("row_text:", row_text)
is_match_area = False
match_area_code = 0
if date_keyword in row_text:
if len(date_keyword_and) == 0:
if show_debug_message:
print('keyword_and # is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if date_keyword_and in row_text:
if show_debug_message:
print('match keyword_and')
is_match_area = True
match_area_code = 3
else:
if show_debug_message:
print('not match keyword_and')
pass
if is_match_area:
matched_blocks.append(row)
if show_debug_message:
if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks))
else:
print("not found date-time-position")
pass
else:
print("date date-time-position is None")
pass
target_area = None
if matched_blocks is not None:
if len(matched_blocks) > 0:
target_row_index = 0
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(matched_blocks)-1
if auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(matched_blocks)-1)
target_area = matched_blocks[target_row_index]
if target_area is not None:
el_btn = None
try:
#print("target_area text", target_area.text)
my_css_selector = "div.buy-icon"
el_btn = target_area.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
if el_btn is not None:
is_button_enable = True
try:
if not el_btn.is_enabled():
is_button_enable = False
else:
# button enable, but class disable.
button_class_string = str(el_btn.get_attribute('class'))
if len(button_class_string) > 1:
if 'disabled' in button_class_string:
is_button_enable = False
if is_button_enable:
el_btn.click()
ret = True
print("buy icon pressed.")
except Exception as exc:
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_btn)
ret = True
except Exception as exc:
pass
else:
# no target.
if auto_reload_coming_soon_page_enable:
# auto refresh for date list page.
if not formated_area_list is None:
if len(formated_area_list) == 0:
try:
driver.refresh()
time.sleep(1.0)
except Exception as exc:
pass
return ret
def urbtix_purchase_ticket(driver, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
date_auto_select_mode = config_dict["tixcraft"]["date_auto_select"]["mode"]
date_keyword = config_dict["tixcraft"]["date_auto_select"]["date_keyword"].strip()
auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"]
if show_debug_message:
print("date_keyword:", date_keyword)
is_date_assign_by_bot = urbtix_date_auto_select(driver, date_auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable)
return is_date_assign_by_bot
# purpose: area auto select
def urbtix_area_auto_select(driver, area_auto_select_mode, area_keyword_1, area_keyword_1_and):
show_debug_message = True # debug.
show_debug_message = False # online
is_price_assign_by_bot = False
is_need_refresh = False
matched_blocks = None
# clean stop word.
area_keyword_1 = format_keyword_string(area_keyword_1)
area_keyword_1_and = format_keyword_string(area_keyword_1_and)
area_list = None
try:
#print("try to find cityline area block")
my_css_selector = "div.area-info"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #ticket-price-tbl date list fail")
print(exc)
formated_area_list = None
if area_list is not None:
area_list_count = len(area_list)
if show_debug_message:
print("area_list_count:", area_list_count)
if area_list_count > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
row_is_enabled=True
try:
button_class_string = str(row.get_attribute('class'))
if len(button_class_string) > 1:
if 'disabled' in button_class_string:
row_is_enabled=False
if 'selected' in button_class_string:
# someone is selected. skip this process.
row_is_enabled=False
is_price_assign_by_bot = True
break
except Exception as exc:
pass
if row_is_enabled:
formated_area_list.append(row)
else:
if show_debug_message:
print("area_list_count is empty.")
pass
else:
if show_debug_message:
print("area_list_count is None.")
pass
if is_price_assign_by_bot:
formated_area_list = None
if formated_area_list is not None:
area_list_count = len(formated_area_list)
if show_debug_message:
print("formated_area_list count:", area_list_count)
if area_list_count > 0:
if len(area_keyword_1) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
if show_debug_message:
print("start to match keyword:", area_keyword_1)
print("keyword and:", area_keyword_1_and)
matched_blocks = []
row_index = 0
for row in formated_area_list:
row_index += 1
row_is_enabled=True
if row_is_enabled:
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
row_text = format_keyword_string(row_text)
if show_debug_message:
print("row_text:", row_text)
is_match_area = False
match_area_code = 0
if area_keyword_1 in row_text:
if len(area_keyword_1_and) == 0:
if show_debug_message:
print('keyword_and is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if area_keyword_1_and in row_text:
if show_debug_message:
print('match keyword_and')
is_match_area = True
match_area_code = 3
else:
if show_debug_message:
print('not match keyword_and')
pass
if is_match_area:
matched_blocks.append(row)
if show_debug_message:
if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks))
else:
is_need_refresh = True
if show_debug_message:
print("formated_area_list is empty.")
target_area = None
if matched_blocks is not None:
if len(matched_blocks) > 0:
target_row_index = 0
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if area_auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(matched_blocks)-1
if area_auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(matched_blocks)-1)
target_area = matched_blocks[target_row_index]
if target_area is not None:
try:
if target_area.is_enabled():
target_area.click()
is_price_assign_by_bot = True
except Exception as exc:
print("click target_area link fail")
print(exc)
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", target_area)
is_price_assign_by_bot = True
except Exception as exc:
pass
return is_need_refresh, is_price_assign_by_bot
def urbtix_ticket_number_auto_select(driver, ticket_number):
show_debug_message = True # debug.
show_debug_message = False # online
is_ticket_number_assigned = False
ticket_number_str = str(ticket_number)
# check ticket input textbox.
ticket_price_input = None
try:
ticket_price_input = driver.find_element(By.CSS_SELECTOR, "input.ticket-count")
except Exception as exc:
pass
if ticket_price_input is not None:
current_ticket_number = ""
is_visible = False
try:
current_ticket_number = str(ticket_price_input.get_attribute('value')).strip()
is_visible = ticket_price_input.is_enabled()
except Exception as exc:
pass
if len(current_ticket_number) > 0:
if current_ticket_number == "0":
try:
print("asssign ticket number:%s" % ticket_number_str)
ticket_price_input.clear()
ticket_price_input.send_keys(ticket_number_str)
is_ticket_number_assigned = True
except Exception as exc:
print("asssign ticket number to ticket-price field Exception:")
print(exc)
try:
ticket_price_input.clear()
ticket_price_input.send_keys("1")
is_ticket_number_assigned = True
except Exception as exc2:
pass
else:
# already assigned.
is_ticket_number_assigned = True
if is_ticket_number_assigned:
el_btn = None
try:
my_css_selector = "div.footer > div > div"
el_btn = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
if el_btn is not None:
try:
if el_btn.is_enabled():
el_btn.click()
print("varify site icon pressed.")
except Exception as exc:
# use plan B
'''
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_btn)
ret = True
except Exception as exc:
pass
'''
pass
else:
if show_debug_message:
print("varify site icon is None.")
if is_ticket_number_assigned:
el_btn = None
try:
my_css_selector = "div.button-inner > div > div.button-text"
el_btn = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
if el_btn is not None:
try:
if el_btn.is_enabled():
el_btn.click()
print("shopping-cart icon pressed.")
except Exception as exc:
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_btn)
ret = True
except Exception as exc:
pass
else:
if show_debug_message:
print("shopping-cart site icon is None.")
return is_ticket_number_assigned
def urbtix_performance(driver, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
ret = False
is_price_assign_by_bot = False
is_need_refresh = False
auto_fill_ticket_number = True
if auto_fill_ticket_number:
# click price row.
area_auto_select_mode = config_dict["tixcraft"]["area_auto_select"]["mode"]
area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"].strip()
area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"].strip()
area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"].strip()
area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"].strip()
area_keyword_1_and = ""
area_keyword_2_and = ""
if show_debug_message:
print("area_keyword_1:", area_keyword_1)
#print("area_keyword_1_and:", area_keyword_1_and)
print("area_keyword_2:", area_keyword_2)
#print("area_keyword_2_and:", area_keyword_2_and)
is_need_refresh, is_price_assign_by_bot = urbtix_area_auto_select(driver, area_auto_select_mode, area_keyword_1, area_keyword_1_and)
if not is_need_refresh:
if not is_price_assign_by_bot:
# try keyword_2
if len(area_keyword_2) > 0:
is_need_refresh, is_price_assign_by_bot = urbtix_area_auto_select(driver, area_auto_select_mode, area_keyword_2, area_keyword_2_and)
if not is_need_refresh:
if not is_price_assign_by_bot:
if len(area_keyword_3) > 0:
is_need_refresh, is_price_assign_by_bot = urbtix_area_auto_select(driver, area_auto_select_mode, area_keyword_3, "")
if not is_need_refresh:
if not is_price_assign_by_bot:
if len(area_keyword_4) > 0:
is_need_refresh, is_price_assign_by_bot = urbtix_area_auto_select(driver, area_auto_select_mode, area_keyword_4, "")
# un-tested. disable refresh for now.
is_need_refresh = False
if is_need_refresh:
try:
driver.refresh()
except Exception as exc:
pass
# choose ticket.
ticket_number = str(config_dict["ticket_number"])
is_ticket_number_assigned = urbtix_ticket_number_auto_select(driver, ticket_number)
if show_debug_message:
print("ticket_number:", ticket_number)
print("is_ticket_number_assigned:", is_ticket_number_assigned)
return ret
# purpose: date auto select
def cityline_date_auto_select(driver, auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable):
show_debug_message = True # debug.
show_debug_message = False # online
ret = False
matched_blocks = None
# clean stop word.
date_keyword = format_keyword_string(date_keyword)
date_keyword_and = ""
area_list = None
try:
#print("try to find cityline area block")
my_css_selector = "button.date-time-position"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #date-time-position date list fail")
print(exc)
#PS: some blocks are generate by ajax, not appear at first time.
formated_area_list = None
if area_list is not None:
area_list_count = len(area_list)
if show_debug_message:
print("date_list_count:", area_list_count)
if area_list_count > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
row_is_enabled=True
el_btn = None
try:
if not row.is_enabled():
row_is_enabled=False
except Exception as exc:
if show_debug_message:
print(exc)
pass
if row_is_enabled:
formated_area_list.append(row)
if show_debug_message:
print("formated_area_list count:", len(formated_area_list))
if len(date_keyword) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
if show_debug_message:
print("start to match keyword:", date_keyword)
matched_blocks = []
row_index = 0
for row in formated_area_list:
row_index += 1
#row_is_enabled=False
row_is_enabled=True
if row_is_enabled:
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
row_text = format_keyword_string(row_text)
if show_debug_message:
print("row_text:", row_text)
is_match_area = False
match_area_code = 0
if date_keyword in row_text:
if len(date_keyword_and) == 0:
if show_debug_message:
print('keyword_and # is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if date_keyword_and in row_text:
if show_debug_message:
print('match keyword_and')
is_match_area = True
match_area_code = 3
else:
if show_debug_message:
print('not match keyword_and')
pass
if is_match_area:
matched_blocks.append(row)
if show_debug_message:
if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks))
else:
print("not found date-time-position")
pass
else:
print("date date-time-position is None")
pass
target_area = None
if matched_blocks is not None:
if len(matched_blocks) > 0:
target_row_index = 0
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(matched_blocks)-1
if auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(matched_blocks)-1)
target_area = matched_blocks[target_row_index]
if target_area is not None:
try:
if target_area.is_enabled():
target_area.click()
ret = True
except Exception as exc:
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", target_area)
ret = True
except Exception as exc:
pass
else:
# no target.
if auto_reload_coming_soon_page_enable:
# auto refresh for date list page.
if not formated_area_list is None:
if len(formated_area_list) == 0:
try:
driver.refresh()
time.sleep(0.4)
except Exception as exc:
pass
return ret
# purpose: area auto select
# return:
# True: area block appear.
# False: area block not appear.
# ps: return is successfully click on the price radio.
def cityline_area_auto_select(driver, area_auto_select_mode, area_keyword_1, area_keyword_1_and):
show_debug_message = True # debug.
show_debug_message = False # online
is_price_assign_by_bot = False
is_need_refresh = False
matched_blocks = None
# clean stop word.
area_keyword_1 = format_keyword_string(area_keyword_1)
area_keyword_1_and = format_keyword_string(area_keyword_1_and)
area_list = None
try:
#print("try to find cityline area block")
my_css_selector = ".form-check"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #ticket-price-tbl date list fail")
print(exc)
formated_area_list = None
if area_list is not None:
area_list_count = len(area_list)
if show_debug_message:
print("area_list_count:", area_list_count)
if area_list_count > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
row_is_enabled=True
try:
my_css_selector = "span.price-limited > span"
span_price_limited = row.find_element(By.CSS_SELECTOR, my_css_selector)
if not span_price_limited is None:
#print("found span limited at idx:", row_index)
span_i18n_string = str(span_price_limited.get_attribute('data-i18n'))
if len(span_i18n_string) > 1:
if 'soldout' in span_i18n_string:
#print("found span limited soldout at idx:", row_index)
row_is_enabled=False
except Exception as exc:
pass
if row_is_enabled:
formated_area_list.append(row)
else:
if show_debug_message:
print("area_list_count is empty.")
pass
else:
if show_debug_message:
print("area_list_count is None.")
pass
if formated_area_list is not None:
area_list_count = len(formated_area_list)
if show_debug_message:
print("formated_area_list count:", area_list_count)
if area_list_count > 0:
if len(area_keyword_1) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
if show_debug_message:
print("start to match keyword:", area_keyword_1)
print("keyword and:", area_keyword_1_and)
matched_blocks = []
row_index = 0
for row in formated_area_list:
row_index += 1
#row_is_enabled=False
row_is_enabled=True
if row_is_enabled:
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
row_text = format_keyword_string(row_text)
if show_debug_message:
print("row_text:", row_text)
is_match_area = False
match_area_code = 0
if area_keyword_1 in row_text:
if len(area_keyword_1_and) == 0:
if show_debug_message:
print('keyword_and is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if area_keyword_1_and in row_text:
if show_debug_message:
print('match keyword_and')
is_match_area = True
match_area_code = 3
else:
if show_debug_message:
print('not match keyword_and')
pass
if is_match_area:
matched_blocks.append(row)
if show_debug_message:
if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks))
else:
is_need_refresh = True
if show_debug_message:
print("formated_area_list is empty.")
target_area = None
if matched_blocks is not None:
if len(matched_blocks) > 0:
target_row_index = 0
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if area_auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(matched_blocks)-1
if area_auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(matched_blocks)-1)
target_area = matched_blocks[target_row_index]
if target_area is not None:
el_btn = None
try:
#print("target_area text", target_area.text)
my_css_selector = "input[type=radio]"
el_btn = target_area.find_element(By.CSS_SELECTOR, my_css_selector)
if el_btn is not None:
if el_btn.is_enabled():
if not el_btn.is_selected():
el_btn.click()
is_price_assign_by_bot = True
else:
is_price_assign_by_bot = True
#print("bingo, click target_area radio")
except Exception as exc:
print("click target_area radio a link fail")
print(exc)
pass
return is_need_refresh, is_price_assign_by_bot
#[TODO]:
# double check selected radio matched by keyword/keyword_and.
def cityline_area_selected_text(driver):
ret = False
return ret
def cityline_ticket_number_auto_select(driver, ticket_number):
selector_string = 'select.select-num'
by_method = By.CSS_SELECTOR
return assign_ticket_number_by_select(driver, ticket_number, by_method, selector_string)
def ibon_ticket_number_auto_select(driver, ticket_number):
selector_string = 'table.table > tbody > tr > td > select'
by_method = By.CSS_SELECTOR
return assign_ticket_number_by_select(driver, ticket_number, by_method, selector_string)
def assign_ticket_number_by_select(driver, ticket_number, by_method, selector_string):
show_debug_message = True # debug.
show_debug_message = False # online
form_select = None
try:
form_select = driver.find_element(by_method, selector_string)
except Exception as exc:
if show_debug_message:
print("find ticket_number select fail")
print(exc)
pass
select_obj = None
if form_select is not None:
is_visible = False
try:
is_visible = form_select.is_enabled()
except Exception as exc:
pass
if is_visible:
try:
select_obj = Select(form_select)
except Exception as exc:
pass
is_ticket_number_assigned = False
if not select_obj is None:
row_text = None
try:
row_text = select_obj.first_selected_option.text
except Exception as exc:
pass
if not row_text is None:
if len(row_text) > 0:
if row_text != "0":
# ticket assign.
is_ticket_number_assigned = True
if not is_ticket_number_assigned:
is_ticket_number_assigned = tixcraft_ticket_number_auto_fill(driver, select_obj, ticket_number)
else:
if show_debug_message:
print("ticket_number assigned by previous action.")
return is_ticket_number_assigned
def cityline_purchase_button_press(driver, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
ret = False
date_auto_select_mode = config_dict["tixcraft"]["date_auto_select"]["mode"]
date_keyword = config_dict["tixcraft"]["date_auto_select"]["date_keyword"].strip()
auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"]
if show_debug_message:
print("date_keyword:", date_keyword)
is_date_assign_by_bot = cityline_date_auto_select(driver, date_auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable)
el_btn = None
try:
el_btn = driver.find_element(By.CSS_SELECTOR, 'button.purchase-btn')
except Exception as exc:
print("find next button fail")
#print(exc)
pass
if el_btn is not None:
print("bingo, found next button")
try:
if el_btn.is_enabled():
el_btn.click()
ret = True
except Exception as exc:
print("press next button fail")
print(exc)
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_btn)
ret = True
except Exception as exc:
pass
return ret
def cityline_next_button_press(driver):
ret = False
el_nav = None
el_btn = None
try:
el_nav = driver.find_element(By.CSS_SELECTOR, '.puchase-bottom')
el_btn = driver.find_element(By.CSS_SELECTOR, '#expressPurchaseBtn')
except Exception as exc:
print("find next button fail...")
print(exc)
if el_btn is not None and el_nav is not None:
print("bingo, found next button, start to press")
try:
if el_btn.is_enabled():
#el_btn.click()
builder = ActionChains(driver)
builder.move_to_element(el_nav)
builder.click(el_btn)
builder.perform()
ret = True
except Exception as exc:
print("click next button fail...")
print(exc)
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_btn)
ret = True
except Exception as exc:
pass
return ret
def cityline_performance(driver, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
is_price_assign_by_bot = False
is_need_refresh = False
auto_fill_ticket_number = True
if auto_fill_ticket_number:
# click price row.
area_auto_select_mode = config_dict["tixcraft"]["area_auto_select"]["mode"]
area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"].strip()
area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"].strip()
area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"].strip()
area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"].strip()
area_keyword_1_and = ""
area_keyword_2_and = ""
if show_debug_message:
print("area_keyword_1:", area_keyword_1)
#print("area_keyword_1_and:", area_keyword_1_and)
print("area_keyword_2:", area_keyword_2)
#print("area_keyword_2_and:", area_keyword_2_and)
# PS: cityline price default value is selected at the first option.
is_need_refresh, is_price_assign_by_bot = cityline_area_auto_select(driver, area_auto_select_mode, area_keyword_1, area_keyword_1_and)
if not is_need_refresh:
if not is_price_assign_by_bot:
# try keyword_2
if len(area_keyword_2) > 0:
is_need_refresh, is_price_assign_by_bot = cityline_area_auto_select(driver, area_auto_select_mode, area_keyword_2, area_keyword_2_and)
if not is_need_refresh:
if not is_price_assign_by_bot:
if len(area_keyword_3) > 0:
is_need_refresh, is_price_assign_by_bot = cityline_area_auto_select(driver, area_auto_select_mode, area_keyword_3, "")
if not is_need_refresh:
if not is_price_assign_by_bot:
if len(area_keyword_4) > 0:
is_need_refresh, is_price_assign_by_bot = cityline_area_auto_select(driver, area_auto_select_mode, area_keyword_4, "")
# un-tested. disable refresh for now.
is_need_refresh = False
if is_need_refresh:
try:
driver.refresh()
except Exception as exc:
pass
# choose ticket.
ticket_number = str(config_dict["ticket_number"])
is_ticket_number_assigned = cityline_ticket_number_auto_select(driver, ticket_number)
if show_debug_message:
print("ticket_number:", ticket_number)
print("is_ticket_number_assigned:", is_ticket_number_assigned)
if is_ticket_number_assigned:
auto_press_next_step_button = True
if auto_press_next_step_button:
if not is_price_assign_by_bot:
#[TODO]:
# double check selected radio matched by keyword/keyword_and.
# cityline_area_selected_text(driver)
pass
if is_price_assign_by_bot:
for i in range(2):
click_ret = cityline_next_button_press(driver)
if click_ret:
break
def ibon_date_auto_select(driver, auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable):
show_debug_message = True # debug.
show_debug_message = False # online
ret = False
matched_blocks = None
# clean stop word.
date_keyword = format_keyword_string(date_keyword)
date_keyword_and = ""
area_list = None
try:
#print("try to find cityline area block")
my_css_selector = "div.single-content > div > div.row > div > div.tr"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find date-time rows fail")
print(exc)
#PS: some blocks are generate by ajax, not appear at first time.
formated_area_list = None
if area_list is not None:
area_list_count = len(area_list)
if show_debug_message:
print("date_list_count:", area_list_count)
if area_list_count > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
# default is enabled.
row_is_enabled=True
el_btn = None
try:
my_css_selector = "button"
el_btn = row.find_element(By.TAG_NAME, my_css_selector)
if el_btn is not None:
if not el_btn.is_enabled():
#print("row's button disabled!")
row_is_enabled=False
except Exception as exc:
if show_debug_message:
print(exc)
pass
if row_is_enabled:
formated_area_list.append(row)
if formated_area_list is not None:
area_list_count = len(formated_area_list)
if show_debug_message:
print("formated_area_list count:", area_list_count)
if area_list_count > 0:
if len(date_keyword) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
if show_debug_message:
print("start to match keyword:", date_keyword)
matched_blocks = []
row_index = 0
for row in formated_area_list:
row_index += 1
row_is_enabled=True
if row_is_enabled:
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
row_text = format_keyword_string(row_text)
if show_debug_message:
print("row_text:", row_text)
is_match_area = False
match_area_code = 0
if date_keyword in row_text:
if len(date_keyword_and) == 0:
if show_debug_message:
print('keyword_and # is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if date_keyword_and in row_text:
if show_debug_message:
print('match keyword_and')
is_match_area = True
match_area_code = 3
else:
if show_debug_message:
print('not match keyword_and')
pass
if is_match_area:
matched_blocks.append(row)
if show_debug_message:
if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks))
else:
print("not found date-time-position")
pass
else:
print("date date-time-position is None")
pass
target_area = None
if matched_blocks is not None:
if len(matched_blocks) > 0:
target_row_index = 0
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(matched_blocks)-1
if auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(matched_blocks)-1)
target_area = matched_blocks[target_row_index]
if target_area is not None:
el_btn = None
try:
my_css_selector = "button.btn"
el_btn = target_area.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
if el_btn is not None:
try:
if el_btn.is_enabled():
el_btn.click()
print("buy icon pressed.")
ret = True
except Exception as exc:
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_btn)
ret = True
except Exception as exc:
pass
else:
# no target to click.
if auto_reload_coming_soon_page_enable:
# auto refresh for date list page.
if not formated_area_list is None:
if len(formated_area_list) == 0:
try:
driver.refresh()
time.sleep(0.4)
except Exception as exc:
pass
return ret
def ibon_activity_info(driver, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
date_auto_select_mode = config_dict["tixcraft"]["date_auto_select"]["mode"]
date_keyword = config_dict["tixcraft"]["date_auto_select"]["date_keyword"].strip()
auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"]
if show_debug_message:
print("date_keyword:", date_keyword)
print("auto_reload_coming_soon_page_enable:", auto_reload_coming_soon_page_enable)
is_date_assign_by_bot = ibon_date_auto_select(driver, date_auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable)
return is_date_assign_by_bot
def ibon_area_auto_select(driver, area_auto_select_mode, area_keyword_1, area_keyword_1_and):
show_debug_message = True # debug.
show_debug_message = False # online
is_price_assign_by_bot = False
is_need_refresh = False
matched_blocks = None
# clean stop word.
area_keyword_1 = format_keyword_string(area_keyword_1)
area_keyword_1_and = format_keyword_string(area_keyword_1_and)
area_list = None
try:
#print("try to find cityline area block")
my_css_selector = "div.col-md-5 > table > tbody > tr"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #ticket-price-tbl date list fail")
print(exc)
formated_area_list = None
if area_list is not None:
area_list_count = len(area_list)
if show_debug_message:
print("area_list_count:", area_list_count)
if area_list_count > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
row_is_enabled=True
try:
button_class_string = str(row.get_attribute('class'))
if len(button_class_string) > 1:
if 'disabled' in button_class_string:
row_is_enabled=False
if 'sold-out' in button_class_string:
row_is_enabled=False
if 'selected' in button_class_string:
# someone is selected. skip this process.
is_price_assign_by_bot = True
break
except Exception as exc:
pass
if row_is_enabled:
formated_area_list.append(row)
else:
if show_debug_message:
print("area_list_count is empty.")
pass
else:
if show_debug_message:
print("area_list_count is None.")
pass
if is_price_assign_by_bot:
formated_area_list = None
if formated_area_list is not None:
area_list_count = len(formated_area_list)
if show_debug_message:
print("formated_area_list count:", area_list_count)
if area_list_count > 0:
if len(area_keyword_1) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
if show_debug_message:
print("start to match keyword:", area_keyword_1)
print("keyword and:", area_keyword_1_and)
matched_blocks = []
row_index = 0
for row in formated_area_list:
row_index += 1
row_is_enabled=True
if row_is_enabled:
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
row_text = format_keyword_string(row_text)
if show_debug_message:
print("row_text:", row_text)
is_match_area = False
match_area_code = 0
if area_keyword_1 in row_text:
if len(area_keyword_1_and) == 0:
if show_debug_message:
print('keyword_and is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if area_keyword_1_and in row_text:
if show_debug_message:
print('match keyword_and')
is_match_area = True
match_area_code = 3
else:
if show_debug_message:
print('not match keyword_and')
pass
if is_match_area:
matched_blocks.append(row)
if show_debug_message:
if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks))
else:
is_need_refresh = True
if show_debug_message:
print("formated_area_list is empty.")
target_area = None
if matched_blocks is not None:
if len(matched_blocks) > 0:
target_row_index = 0
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if area_auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(matched_blocks)-1
if area_auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(matched_blocks)-1)
target_area = matched_blocks[target_row_index]
if target_area is not None:
try:
if target_area.is_enabled():
target_area.click()
is_price_assign_by_bot = True
except Exception as exc:
print("click target_area link fail")
print(exc)
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", target_area)
is_price_assign_by_bot = True
except Exception as exc:
pass
return is_need_refresh, is_price_assign_by_bot
def ibon_performance(driver, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
is_price_assign_by_bot = False
is_need_refresh = False
auto_fill_ticket_number = True
if auto_fill_ticket_number:
# click price row.
area_auto_select_mode = config_dict["tixcraft"]["area_auto_select"]["mode"]
area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"].strip()
area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"].strip()
area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"].strip()
area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"].strip()
area_keyword_1_and = ""
area_keyword_2_and = ""
if show_debug_message:
print("area_keyword_1:", area_keyword_1)
#print("area_keyword_1_and:", area_keyword_1_and)
print("area_keyword_2:", area_keyword_2)
#print("area_keyword_2_and:", area_keyword_2_and)
is_need_refresh = False
if not is_price_assign_by_bot:
is_need_refresh, is_price_assign_by_bot = ibon_area_auto_select(driver, area_auto_select_mode, area_keyword_1, area_keyword_1_and)
if not is_need_refresh:
if not is_price_assign_by_bot:
# try keyword_2
if len(area_keyword_2) > 0:
is_need_refresh, is_price_assign_by_bot = ibon_area_auto_select(driver, area_auto_select_mode, area_keyword_2, area_keyword_2_and)
if not is_need_refresh:
if not is_price_assign_by_bot:
if len(area_keyword_3) > 0:
is_need_refresh, is_price_assign_by_bot = ibon_area_auto_select(driver, area_auto_select_mode, area_keyword_3, "")
if not is_need_refresh:
if not is_price_assign_by_bot:
if len(area_keyword_4) > 0:
is_need_refresh, is_price_assign_by_bot = ibon_area_auto_select(driver, area_auto_select_mode, area_keyword_4, "")
if is_need_refresh:
try:
driver.refresh()
except Exception as exc:
pass
return is_price_assign_by_bot
def ibon_purchase_button_press(driver):
ret = False
el_btn = None
try:
el_btn = driver.find_element(By.CSS_SELECTOR, '#ticket-wrap > a.btn')
except Exception as exc:
print("find next button fail...")
print(exc)
if el_btn is not None:
print("bingo, found next button, start to press")
try:
if el_btn.is_enabled():
el_btn.click()
ret = True
except Exception as exc:
print("click next button fail...")
print(exc)
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_btn)
ret = True
except Exception as exc:
pass
return ret
def facebook_login(driver, account, password):
ret = False
el_email = None
try:
el_email = driver.find_element(By.CSS_SELECTOR, '#email')
except Exception as exc:
pass
is_visible = False
if el_email is not None:
try:
if el_email.is_enabled():
is_visible = True
except Exception as exc:
pass
is_email_sent = False
if is_visible:
try:
inputed_text = el_email.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_email.send_keys(account)
is_email_sent = True
else:
if inputed_text == account:
is_email_sent = True
except Exception as exc:
pass
el_pass = None
if is_email_sent:
try:
el_pass = driver.find_element(By.CSS_SELECTOR, '#pass')
except Exception as exc:
pass
is_password_sent = False
if el_pass is not None:
try:
if el_pass.is_enabled():
inputed_text = el_pass.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_pass.click()
if(len(password)>0):
el_pass.send_keys(password)
el_pass.send_keys(Keys.ENTER)
is_password_sent = True
time.sleep(0.1)
except Exception as exc:
pass
ret = is_password_sent
return ret
def kktix_login(driver, account, password):
ret = False
el_email = None
try:
el_email = driver.find_element(By.CSS_SELECTOR, '#user_login')
except Exception as exc:
pass
is_visible = False
if el_email is not None:
try:
if el_email.is_enabled():
is_visible = True
except Exception as exc:
pass
is_email_sent = False
if is_visible:
try:
inputed_text = el_email.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_email.send_keys(account)
is_email_sent = True
else:
if inputed_text == account:
is_email_sent = True
except Exception as exc:
pass
el_pass = None
if is_email_sent:
try:
el_pass = driver.find_element(By.CSS_SELECTOR, '#user_password')
except Exception as exc:
pass
is_password_sent = False
if el_pass is not None:
try:
if el_pass.is_enabled():
inputed_text = el_pass.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_pass.click()
if(len(password)>0):
el_pass.send_keys(password)
el_pass.send_keys(Keys.ENTER)
is_password_sent = True
time.sleep(0.1)
except Exception as exc:
pass
ret = is_password_sent
return ret
def cityline_login(driver, account, password):
ret = False
el_email = None
try:
el_email = driver.find_element(By.CSS_SELECTOR, 'input.ant-input')
except Exception as exc:
pass
is_visible = False
if el_email is not None:
try:
if el_email.is_enabled():
is_visible = True
except Exception as exc:
pass
is_email_sent = False
if is_visible:
try:
inputed_text = el_email.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_email.send_keys(account)
is_email_sent = True
else:
if inputed_text == account:
is_email_sent = True
except Exception as exc:
pass
el_pass = None
if is_email_sent:
try:
el_pass = driver.find_element(By.CSS_SELECTOR, 'input[type="password"]')
except Exception as exc:
pass
is_password_sent = False
if el_pass is not None:
try:
if el_pass.is_enabled():
inputed_text = el_pass.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_pass.click()
if(len(password)>0):
el_pass.send_keys(password)
el_pass.send_keys(Keys.ENTER)
is_password_sent = True
time.sleep(0.1)
except Exception as exc:
pass
ret = is_password_sent
return ret
def urbtix_login(driver, account, password):
ret = False
el_email = None
try:
el_email = driver.find_element(By.CSS_SELECTOR, 'input[name="loginId"]')
except Exception as exc:
#print("find #email fail")
#print(exc)
pass
is_visible = False
if el_email is not None:
try:
if el_email.is_enabled():
is_visible = True
except Exception as exc:
pass
is_email_sent = False
if is_visible:
try:
inputed_text = el_email.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_email.send_keys(account)
is_email_sent = True
else:
if inputed_text == account:
is_email_sent = True
except Exception as exc:
pass
el_pass = None
if is_email_sent:
try:
el_pass = driver.find_element(By.CSS_SELECTOR, 'input[name="password"]')
except Exception as exc:
pass
is_password_sent = False
if el_pass is not None:
try:
if el_pass.is_enabled():
inputed_text = el_pass.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_pass.click()
if(len(password)>0):
el_pass.send_keys(password)
is_password_sent = True
except Exception as exc:
pass
el_btn = None
if is_password_sent:
try:
el_btn = driver.find_element(By.CSS_SELECTOR, '.login-button')
if not el_btn is None:
el_btn.click()
except Exception as exc:
pass
return ret
def kham_login(driver, account, password):
ret = False
el_email = None
try:
my_css_selector = 'table#blockLogin > tbody > tr > td > input[type="text"]'
el_email = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
is_visible = False
if el_email is not None:
try:
if el_email.is_enabled():
is_visible = True
except Exception as exc:
pass
is_email_sent = False
if is_visible:
try:
inputed_text = el_email.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_email.send_keys(account)
is_email_sent = True
else:
if inputed_text == account:
is_email_sent = True
except Exception as exc:
pass
el_pass = None
if is_email_sent:
try:
my_css_selector = 'table#blockLogin > tbody > tr > td > input[type="password"]'
el_pass = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
is_password_sent = False
if el_pass is not None:
try:
if el_pass.is_enabled():
inputed_text = el_pass.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_pass.click()
if(len(password)>0):
el_pass.send_keys(password)
is_password_sent = True
time.sleep(0.1)
except Exception as exc:
pass
el_btn = None
if is_password_sent:
try:
el_btn = driver.find_element(By.CSS_SELECTOR, '#ctl00_ContentPlaceHolder1_LOGIN_BTN')
if not el_btn is None:
el_btn.click()
except Exception as exc:
pass
ret = is_password_sent
return ret
def hkticketing_login(driver, account, password):
ret = False
el_email = None
try:
my_css_selector = 'div#myTick2Col > div.formMod2Col > div.formModule > div.loginContentContainer > input.borInput'
el_email = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
#print("find_element exception")
#print(exc)
pass
is_visible = False
if el_email is not None:
try:
if el_email.is_enabled():
is_visible = True
else:
el_email.click()
except Exception as exc:
pass
else:
#print("account field is None.")
pass
is_email_sent = False
if is_visible:
try:
# PS: this is special case...
el_email.click()
inputed_text = el_email.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
#print("send account text:", account)
el_email.send_keys(account)
is_email_sent = True
else:
if inputed_text == account:
is_email_sent = True
except Exception as exc:
pass
el_pass = None
if is_email_sent:
try:
my_css_selector = 'div.loginContentContainer > input[type="password"]'
el_pass = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
is_password_sent = False
if el_pass is not None:
try:
if el_pass.is_enabled():
el_pass.click()
inputed_text = el_pass.get_attribute('value')
if inputed_text is not None:
if len(inputed_text) == 0:
el_pass.click()
if(len(password)>0):
#print("send password text:", password)
el_pass.send_keys(password)
el_pass.send_keys(Keys.ENTER)
is_password_sent = True
time.sleep(0.1)
else:
el_pass.click()
except Exception as exc:
pass
ret = is_password_sent
return ret
def check_and_play_sound_for_captcha(config_dict):
play_captcha_sound = config_dict["advanced"]["play_captcha_sound"]["enable"]
captcha_sound_filename = config_dict["advanced"]["play_captcha_sound"]["filename"].strip()
if play_captcha_sound:
app_root = get_app_root()
captcha_sound_filename = os.path.join(app_root, captcha_sound_filename)
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):
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
# purpose: check alert poped.
# PS: current version not enable...
def check_pop_alert(driver):
is_alert_popup = False
# https://stackoverflow.com/questions/57481723/is-there-a-change-in-the-handling-of-unhandled-alert-in-chromedriver-and-chrome
default_close_alert_text = [""]
if len(default_close_alert_text) > 0:
try:
alert = None
if not driver is None:
alert = driver.switch_to.alert
if not alert is None:
alert_text = str(alert.text)
if not alert_text is None:
is_match_auto_close_text = False
for txt in default_close_alert_text:
if len(txt) > 0:
if txt in alert.text:
is_match_auto_close_text = True
else:
is_match_auto_close_text = True
#print("is_match_auto_close_text:", is_match_auto_close_text)
#print("alert3 text:", alert.text)
if is_match_auto_close_text:
alert.accept()
#print("alert3 accepted")
is_alert_popup = True
else:
print("alert3 not detected")
except NoAlertPresentException as exc1:
#logger.error('NoAlertPresentException for alert')
pass
except NoSuchWindowException:
pass
except Exception as exc:
logger.error('Exception2 for alert')
logger.error(exc, exc_info=True)
return is_alert_popup
def list_all_cookies(driver):
all_cookies=driver.get_cookies();
cookies_dict = {}
for cookie in all_cookies:
cookies_dict[cookie['name']] = cookie['value']
print(cookies_dict)
def tixcraft_main(driver, url, config_dict, tixcraft_dict, ocr, Captcha_Browser):
home_url_list = ['https://tixcraft.com/','https://www.tixcraft.com/','https://indievox.com/','https://www.indievox.com/','https://teamear.tixcraft.com/activity']
for each_url in home_url_list:
if each_url == url:
tixcraft_home_close_window(driver)
if config_dict["ocr_captcha"]["enable"]:
domain_name = url.split('/')[2]
#PS: need set cookies once, if user change domain.
if not Captcha_Browser is None:
Captcha_Browser.Set_cookies(driver.get_cookies())
Captcha_Browser.Set_Domain(domain_name)
break
if "/activity/detail/" in url:
is_redirected = tixcraft_redirect(driver, url)
is_date_selected = False
if "/activity/game/" in url:
date_auto_select_enable = config_dict["tixcraft"]["date_auto_select"]["enable"]
if date_auto_select_enable:
domain_name = url.split('/')[2]
is_date_selected = tixcraft_date_auto_select(driver, url, config_dict, domain_name)
# choose area
if '/ticket/area/' in url:
area_auto_select_enable = config_dict["tixcraft"]["area_auto_select"]["enable"]
if area_auto_select_enable:
tixcraft_area_auto_select(driver, url, config_dict)
if '/ticket/verify/' in url:
presale_code = config_dict["tixcraft"]["presale_code"]
presale_code_delimiter = config_dict["tixcraft"]["presale_code_delimiter"]
tixcraft_dict["answer_index"] = tixcraft_verify(driver, presale_code, presale_code_delimiter, tixcraft_dict["answer_index"])
else:
tixcraft_dict["answer_index"] = -1
# main app, to select ticket number.
if '/ticket/ticket/' in url:
if not tixcraft_dict["is_verifyCode_editing"]:
domain_name = url.split('/')[2]
tixcraft_dict["is_verifyCode_editing"] = tixcraft_ticket_main(driver, config_dict, ocr, Captcha_Browser, domain_name)
else:
tixcraft_dict["is_verifyCode_editing"] = False
if '/ticket/checkout' in url:
if config_dict["advanced"]["headless"]:
if not tixcraft_dict["is_popup_checkout"]:
domain_name = url.split('/')[2]
checkout_url = "https://%s/ticket/checkout" % (domain_name)
print("搶票成功, 請前往該帳號訂單查看: %s" % (checkout_url))
webbrowser.open_new(checkout_url)
tixcraft_dict["is_popup_checkout"] = True
else:
tixcraft_dict["is_popup_checkout"] = False
return tixcraft_dict
def kktix_main(driver, url, config_dict, kktix_dict):
auto_press_next_step_button = config_dict["kktix"]["auto_press_next_step_button"]
kktix_account = config_dict["advanced"]["kktix_account"]
is_url_contain_sign_in = False
# fix https://kktix.com/users/sign_in?back_to=https://kktix.com/events/xxxx and registerStatus: SOLD_OUT cause page refresh.
if '/users/sign_in?' in url:
if len(kktix_account) > 4:
kktix_login(driver, kktix_account, decryptMe(config_dict["advanced"]["kktix_password"]))
is_url_contain_sign_in = True
if not is_url_contain_sign_in:
if '/registrations/new' in url:
kktix_dict["answer_index"], kktix_dict["kktix_register_status_last"] = kktix_reg_new(driver, url, kktix_dict["answer_index"], kktix_dict["kktix_register_status_last"], config_dict)
else:
is_event_page = False
if '/events/' in url:
# ex: https://xxx.kktix.cc/events/xxx-copy-1
if len(url.split('/'))<=5:
is_event_page = True
if is_event_page:
if auto_press_next_step_button:
# pass switch check.
#print("should press next here.")
kktix_events_press_next_button(driver)
kktix_dict["answer_index"] = -1
kktix_dict["kktix_register_status_last"] = None
if '/events/' in url and '/registrations/' in url and "-" in url:
if config_dict["advanced"]["headless"]:
if not kktix_dict["is_popup_checkout"]:
is_event_page = False
if len(url.split('/'))==8:
is_event_page = True
if is_event_page:
confirm_clicked = kktix_confirm_order_button(driver)
if confirm_clicked:
domain_name = url.split('/')[2]
checkout_url = "https://%s/account/orders" % (domain_name)
print("搶票成功, 請前往該帳號訂單查看: %s" % (checkout_url))
webbrowser.open_new(checkout_url)
tixcraft_dict["is_popup_checkout"] = True
else:
kktix_dict["is_popup_checkout"] = False
return kktix_dict
def famiticket_main(driver, url, config_dict):
try:
window_handles_count = len(driver.window_handles)
if window_handles_count > 1:
driver.switch_to.window(driver.window_handles[0])
driver.close()
driver.switch_to.window(driver.window_handles[0])
except Exception as excSwithFail:
pass
if '/Home/Activity/Info/' in url:
fami_activity(driver)
if '/Sales/Home/Index/' in url:
fami_home(driver, url, config_dict)
def urbtix_performance_confirm_dialog_popup(driver):
ret = False
el_div = None
try:
el_div = driver.find_element(By.CSS_SELECTOR, 'div.notification-confirm-btn > div.button-text')
except Exception as exc:
#print("find modal-dialog fail")
#print(exc)
pass
if el_div is not None:
print("bingo, found notification-confirm-btn")
is_visible = False
try:
if el_div.is_enabled():
if el_div.is_displayed():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
el_div.click()
ret = True
except Exception as exc:
# use plan B
'''
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_div)
ret = True
except Exception as exc:
pass
'''
pass
if ret:
time.sleep(0.4)
return ret
def urbtix_main(driver, url, config_dict):
# http://msg.urbtix.hk
waiting_for_access_url = ['/session/landing-timer/','msg.urbtix.hk','busy.urbtix.hk']
for waiting_url in waiting_for_access_url:
if waiting_url in url:
# delay to avoid ip block.
time.sleep(1.0)
try:
driver.get('https://www.urbtix.hk/')
except Exception as exec1:
pass
pass
if '/logout?' in url:
try:
driver.get('https://www.urbtix.hk/')
except Exception as exec1:
pass
pass
if '.hk/member-login' in url:
urbtix_account = config_dict["advanced"]["urbtix_account"]
if len(urbtix_account) > 2:
urbtix_login(driver, urbtix_account, decryptMe(config_dict["advanced"]["urbtix_password"]))
# https://www.urbtix.hk/event-detail/00000/
if '/event-detail/' in url:
date_auto_select_enable = config_dict["tixcraft"]["date_auto_select"]["enable"]
if date_auto_select_enable:
is_event_page = False
if len(url.split('/'))<=6:
is_event_page = True
urbtix_purchase_ticket(driver, config_dict)
# https://www.urbtix.hk/performance-detail/?eventId=00000&performanceId=00000
is_performace_page = False
if '/performance-detail/?eventId=' in url:
is_performace_page = True
if 'performance-detail?eventId' in url:
is_performace_page = True
if is_performace_page:
area_auto_select_enable = config_dict["tixcraft"]["area_auto_select"]["enable"]
if area_auto_select_enable:
is_confirm_dialog_popup = urbtix_performance_confirm_dialog_popup(driver)
if is_confirm_dialog_popup:
print("is_confirm_dialog_popup! auto press confirm...")
else:
urbtix_performance(driver, config_dict)
def check_modal_dialog_popup(driver):
ret = False
el_div = None
try:
el_div = driver.find_element(By.CSS_SELECTOR, 'div.modal-dialog > div.modal-content')
except Exception as exc:
#print("find modal-dialog fail")
#print(exc)
pass
if el_div is not None:
#print("bingo, found modal-dialog")
try:
if el_div.is_enabled():
if el_div.is_displayed():
ret = True
except Exception as exc:
pass
return ret
def cityline_shows_goto_cta(driver):
ret = False
el_btn = None
try:
el_btn = driver.find_element(By.CSS_SELECTOR, '.btn_cta')
except Exception as exc:
#print("find next button fail...")
#print(exc)
pass
if el_btn is not None:
#print("bingo, found next button, start to press")
try:
if el_btn.is_enabled() and el_btn.is_displayed():
el_btn.click()
ret = True
except Exception as exc:
print("click next button fail...")
print(exc)
return ret
def cityline_home_close_window(driver):
show_debug_message = True # debug.
show_debug_message = False # online
close_styles_list = ['.anticon-close', '.cookieWrapper_closeBtn']
for close_styles in close_styles_list:
close_all_alert_btns = None
try:
close_all_alert_btns = driver.find_elements(By.CSS_SELECTOR, close_styles)
except Exception as exc:
print("find close button fail")
if close_all_alert_btns is not None:
if show_debug_message:
print('all close button count:', len(close_all_alert_btns))
for alert_btn in close_all_alert_btns:
is_visible = False
try:
if alert_btn.is_enabled() and alert_btn.is_displayed():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
alert_btn.click()
except Exception as exc:
print("try to click close button fail, force click by js.")
try:
driver.execute_script("arguments[0].click();", alert_btn)
except Exception as exc:
pass
def cityline_main(driver, url, config_dict):
#https://www.cityline.com/Events.html
if 'cityline.com/Events.html' in url:
cityline_home_close_window(driver)
# https://www.cityline.com/Login.html?targetUrl=https%3A%2F%2F
# ignore url redirect
if '/Login.html' in url:
cityline_account = config_dict["advanced"]["cityline_account"]
if len(cityline_account) > 2:
cityline_login(driver, cityline_account, decryptMe(config_dict["advanced"]["cityline_password"]))
return
# https://msg.cityline.com/ https://event.cityline.com/
if 'msg.cityline.com' or 'event.cityline.com' in url:
try:
WebDriverWait(driver, 10, poll_frequency=0.01).until(
EC.element_to_be_clickable((By.XPATH, "//button[@id='btn-retry-en-1']"))
)
driver.execute_script("goEvent();")
except Exception as exec1:
pass
pass
try:
window_handles_count = len(driver.window_handles)
if window_handles_count > 1:
driver.switch_to.window(driver.window_handles[0])
driver.close()
driver.switch_to.window(driver.window_handles[0])
time.sleep(0.2)
except Exception as excSwithFail:
pass
if '/eventDetail?' in url:
is_modal_dialog_popup = check_modal_dialog_popup(driver)
if is_modal_dialog_popup:
print("is_modal_dialog_popup! skip...")
else:
date_auto_select_enable = config_dict["tixcraft"]["date_auto_select"]["enable"]
if date_auto_select_enable:
cityline_purchase_button_press(driver, config_dict)
if '/performance?' in url:
is_modal_dialog_popup = check_modal_dialog_popup(driver)
if is_modal_dialog_popup:
print("is_modal_dialog_popup! skip...")
else:
area_auto_select_enable = config_dict["tixcraft"]["area_auto_select"]["enable"]
if area_auto_select_enable:
cityline_performance(driver, config_dict)
if '.htm' in url:
if not '/slim_end.htm' in url:
if len(url.split('/'))>=5:
cityline_shows_goto_cta(driver)
def ibon_verification_question(driver, answer_index, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
user_guess_string = config_dict["kktix"]["user_guess_string"]
# part 1: check div.
question_div = None
try:
question_div = driver.find_element(By.CSS_SELECTOR, '')
except Exception as exc:
pass
#print("find input fail:", exc)
#captcha_text_div_text
captcha_password_inputbox = None
try:
captcha_password_inputbox = driver.find_element(By.CSS_SELECTOR, '')
except Exception as exc:
pass
if not captcha_password_inputbox is None:
inferred_answer_string = None
if len(user_guess_string) > 0:
inferred_answer_string = user_guess_string
else:
inferred_answer_string, answer_list = get_answer_list_from_question_string(None, captcha_text_div_text)
return answer_index
def ibon_main(driver, url, config_dict, answer_index):
#https://ticket.ibon.com.tw/ActivityInfo/Details/0000?pattern=entertainment
if '/ActivityInfo/Details/' in url:
is_event_page = False
if len(url.split('/'))<=6:
is_event_page = True
if is_event_page:
date_auto_select_enable = config_dict["tixcraft"]["date_auto_select"]["enable"]
if date_auto_select_enable:
ibon_activity_info(driver, config_dict)
# validation question url:
# https://orders.ibon.com.tw/application/UTK02/UTK0201_0.aspx?rn=1180872370&PERFORMANCE_ID=B04M7XZT&PRODUCT_ID=B04KS88E&SHOW_PLACE_MAP=True
if '/application/UTK02/' in url and '.aspx?rn=' in url:
#PS: not sure, use 'kktix' block or 'tixcraft' block for this feature.
#auto_guess_options = config_dict["kktix"]["auto_guess_options"]
auto_guess_options = True
if auto_guess_options:
#ibon_dict["answer_index"] = ibon_verification_question(driver, ibon_dict["answer_index"], config_dict)
pass
else:
ibon_dict["answer_index"] = -1
# https://orders.ibon.com.tw/application/UTK02/UTK0201_000.aspx?PERFORMANCE_ID=0000
if '/application/UTK02/' in url and '.aspx?PERFORMANCE_ID=' in url:
is_event_page = False
if len(url.split('/'))<=6:
is_event_page = True
if is_event_page:
area_auto_select_enable = config_dict["tixcraft"]["area_auto_select"]["enable"]
if area_auto_select_enable:
if 'PERFORMANCE_PRICE_AREA_ID=' in url:
# step 2: assign ticket number.
ticket_number = str(config_dict["ticket_number"])
is_ticket_number_assigned = ibon_ticket_number_auto_select(driver, ticket_number)
if is_ticket_number_assigned:
click_ret = ibon_purchase_button_press(driver)
else:
# step 1: select area.
ibon_performance(driver, config_dict)
return ibon_dict
def hkticketing_home(driver):
show_debug_message = True # debug.
show_debug_message = False # online
is_hotshow_popup = False
body_iframe = None
try:
body_iframe_list = driver.find_elements(By.CSS_SELECTOR, 'body > iframe')
except Exception as exc:
if show_debug_message:
print("find body_iframe fail")
pass
hotshow_btn = None
if not body_iframe_list is None:
if show_debug_message:
print("iframe count:", len(body_iframe_list))
for each_iframe in body_iframe_list:
try:
driver.switch_to.frame(each_iframe)
hotshow_btn = driver.find_element(By.CSS_SELECTOR, 'div.hotshow > a.btn')
if hotshow_btn is not None:
if hotshow_btn.is_enabled() and hotshow_btn.is_displayed():
is_hotshow_popup = True
driver.switch_to.default_content()
except Exception as exc:
if show_debug_message:
print("find hotshow btn fail:", exc)
driver.switch_to.default_content()
if show_debug_message:
print("is_hotshow_popup", is_hotshow_popup)
accept_all_cookies_btn = None
if not is_hotshow_popup:
try:
accept_all_cookies_btn = driver.find_element(By.ID, 'closepolicy_new')
except Exception as exc:
if show_debug_message:
print("find closepolicy_new fail")
pass
else:
print("reCaptcha popup, do nothing.")
if accept_all_cookies_btn is not None:
is_visible = False
try:
if accept_all_cookies_btn.is_enabled() and accept_all_cookies_btn.is_displayed():
is_visible = True
except Exception as exc:
pass
if is_visible:
if show_debug_message:
print("closepolicy_new visible. start to press.")
try:
accept_all_cookies_btn.click()
except Exception as exc:
print("try to click closepolicy_new fail")
try:
driver.execute_script("arguments[0].click();", accept_all_cookies_btn)
except Exception as exc:
pass
else:
if show_debug_message:
print("closepolicy_new invisible.")
def hkticketing_date_auto_select(driver, auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable):
show_debug_message = True # debug.
show_debug_message = False # online
ret = False
matched_blocks = None
# clean stop word.
date_keyword = format_keyword_string(date_keyword)
date_keyword_and = ""
form_select = None
try:
form_select = driver.find_element(By.CSS_SELECTOR, '#p')
except Exception as exc:
print("find select fail")
pass
select_obj = None
if form_select is not None:
is_visible = False
try:
if form_select.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
select_obj = Select(form_select)
except Exception as exc:
pass
is_date_assigned = False
if not select_obj is None:
row_text = None
try:
row_text = select_obj.first_selected_option.text
except Exception as exc:
pass
if not row_text is None:
if len(row_text) > 8:
if '20' in row_text:
# ticket assign.
is_date_assigned = True
if show_debug_message:
print("is_date_assigned:", is_date_assigned)
#PS: some blocks are generate by ajax, not appear at first time.
formated_area_list = None
if not is_date_assigned:
area_list = None
try:
my_css_selector = "#p > option"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #p options date list fail")
print(exc)
if area_list is not None:
area_list_count = len(area_list)
if show_debug_message:
print("date_list_count:", area_list_count)
if area_list_count > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
row_is_enabled=False
option_value_string = None
try:
if row.is_enabled():
option_value_string = str(row.get_attribute('value'))
if len(option_value_string) > 4:
row_is_enabled=True
# alway disable.
option_text_string = str(row.text)
if ' Exhausted' in option_text_string:
row_is_enabled=False
if '配售完畢' in option_text_string:
row_is_enabled=False
if '配售完毕' in option_text_string:
row_is_enabled=False
if 'No Longer On Sale' in option_text_string:
row_is_enabled=False
if '已停止發售' in option_text_string:
row_is_enabled=False
if '已停止发售' in option_text_string:
row_is_enabled=False
except Exception as exc:
if show_debug_message:
print(exc)
pass
if row_is_enabled:
formated_area_list.append(row)
if formated_area_list is not None:
area_list_count = len(formated_area_list)
if show_debug_message:
print("formated_area_list count:", area_list_count)
if area_list_count > 0:
if len(date_keyword) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
if show_debug_message:
print("start to match keyword:", date_keyword)
matched_blocks = []
row_index = 0
for row in formated_area_list:
row_index += 1
row_is_enabled=True
if row_is_enabled:
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
row_text = format_keyword_string(row_text)
if show_debug_message:
print("row_text:", row_text)
is_match_area = False
match_area_code = 0
if date_keyword in row_text:
if len(date_keyword_and) == 0:
if show_debug_message:
print('keyword_and # is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if date_keyword_and in row_text:
if show_debug_message:
print('match keyword_and')
is_match_area = True
match_area_code = 3
else:
if show_debug_message:
print('not match keyword_and')
pass
if is_match_area:
matched_blocks.append(row)
if show_debug_message:
if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks))
else:
print("not found date-time-position")
pass
else:
print("date date-time-position is None")
pass
target_area = None
if matched_blocks is not None:
if len(matched_blocks) > 0:
target_row_index = 0
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(matched_blocks)-1
if auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(matched_blocks)-1)
target_area = matched_blocks[target_row_index]
if target_area is not None:
try:
if target_area.is_enabled():
target_area.click()
is_date_assigned = True
except Exception as exc:
print("click target_area link fail")
print(exc)
# use plan B
'''
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", target_area)
is_date_assigned = True
except Exception as exc:
pass
'''
# alway, auto submit
el_btn = None
try:
my_css_selector = "#buyButton > input"
el_btn = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
if el_btn is not None:
try:
if el_btn.is_enabled() and el_btn.is_displayed():
el_btn.click()
print("buy button pressed.")
ret = True
except Exception as exc:
# use plan B
'''
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_btn)
ret = True
except Exception as exc:
pass
'''
else:
if auto_reload_coming_soon_page_enable:
# auto refresh for date list page.
is_need_refresh = True
if is_date_assigned:
# if select box assign.
is_need_refresh = False
else:
if not formated_area_list is None:
if len(formated_area_list) > 0:
# option waiting to assign at next loop.
is_need_refresh = False
if is_need_refresh:
try:
driver.refresh()
time.sleep(0.3)
except Exception as exc:
pass
return ret
def hkticketing_show(driver, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
date_auto_select_mode = config_dict["tixcraft"]["date_auto_select"]["mode"]
date_keyword = config_dict["tixcraft"]["date_auto_select"]["date_keyword"].strip()
auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"]
if show_debug_message:
print("date_keyword:", date_keyword)
print("auto_reload_coming_soon_page_enable:", auto_reload_coming_soon_page_enable)
is_date_assign_by_bot = hkticketing_date_auto_select(driver, date_auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable)
return is_date_assign_by_bot
def hkticketing_area_auto_select(driver, area_auto_select_mode, area_keyword_1, area_keyword_1_and):
show_debug_message = True # debug.
show_debug_message = False # online
is_price_assign_by_bot = False
is_need_refresh = False
matched_blocks = None
# clean stop word.
area_keyword_1 = format_keyword_string(area_keyword_1)
area_keyword_1_and = format_keyword_string(area_keyword_1_and)
area_list = None
try:
my_css_selector = "#ticketSelectorContainer > ul > li"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #ticket-price-tbl date list fail")
print(exc)
formated_area_list = None
if area_list is not None:
area_list_count = len(area_list)
if show_debug_message:
print("area_list_count:", area_list_count)
if area_list_count > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
row_is_enabled=True
try:
button_class_string = str(row.get_attribute('class'))
if len(button_class_string) > 1:
if 'disabled' in button_class_string:
row_is_enabled=False
if 'unavailable' in button_class_string:
row_is_enabled=False
if 'selected' in button_class_string:
# someone is selected. skip this process.
is_price_assign_by_bot = True
break
except Exception as exc:
pass
if row_is_enabled:
formated_area_list.append(row)
else:
if show_debug_message:
print("area_list_count is empty.")
pass
else:
if show_debug_message:
print("area_list_count is None.")
pass
if is_price_assign_by_bot:
formated_area_list = None
if formated_area_list is not None:
area_list_count = len(formated_area_list)
if show_debug_message:
print("formated_area_list count:", area_list_count)
if area_list_count > 0:
if len(area_keyword_1) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
if show_debug_message:
print("start to match keyword:", area_keyword_1)
print("keyword and:", area_keyword_1_and)
matched_blocks = []
row_index = 0
for row in formated_area_list:
row_index += 1
row_is_enabled=True
if row_is_enabled:
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
row_text = format_keyword_string(row_text)
if show_debug_message:
print("row_text:", row_text)
is_match_area = False
match_area_code = 0
if area_keyword_1 in row_text:
if len(area_keyword_1_and) == 0:
if show_debug_message:
print('keyword_and is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if area_keyword_1_and in row_text:
if show_debug_message:
print('match keyword_and')
is_match_area = True
match_area_code = 3
else:
if show_debug_message:
print('not match keyword_and')
pass
if is_match_area:
matched_blocks.append(row)
if show_debug_message:
if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks))
else:
is_need_refresh = True
if show_debug_message:
print("formated_area_list is empty.")
target_area = None
if matched_blocks is not None:
if len(matched_blocks) > 0:
target_row_index = 0
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if area_auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(matched_blocks)-1
if area_auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(matched_blocks)-1)
target_area = matched_blocks[target_row_index]
if target_area is not None:
try:
if target_area.is_enabled():
target_area.click()
is_price_assign_by_bot = True
except Exception as exc:
print("click target_area link fail")
print(exc)
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", target_area)
is_price_assign_by_bot = True
except Exception as exc:
pass
return is_need_refresh, is_price_assign_by_bot
def hkticketing_ticket_number_auto_select(driver, ticket_number):
selector_string = 'select.shortSelect'
by_method = By.CSS_SELECTOR
return assign_ticket_number_by_select(driver, ticket_number, by_method, selector_string)
def hkticketing_nav_to_footer(driver):
try:
el_nav = None
el_nav = driver.find_element(By.CSS_SELECTOR, '#wrapFooter')
if not el_nav is None:
builder = ActionChains(driver)
builder.move_to_element(el_nav)
builder.click(el_nav)
builder.perform()
except Exception as exc:
pass
def hkticketing_next_button_press(driver):
ret = False
el_btn = None
try:
el_btn = driver.find_element(By.CSS_SELECTOR, '#continueBar > div.chooseTicketsOfferDiv > button')
except Exception as exc:
print("find next button fail...")
print(exc)
if el_btn is not None:
print("bingo, found next button, start to press")
hkticketing_nav_to_footer(driver)
try:
if el_btn.is_enabled() and el_btn.is_displayed():
el_btn.click()
ret = True
except Exception as exc:
print("click next button fail...")
print(exc)
return ret
def hkticketing_go_to_payment(driver):
ret = False
el_btn = None
try:
el_btn = driver.find_element(By.CSS_SELECTOR, '#goToPaymentButton')
except Exception as exc:
print("find next button fail...")
print(exc)
if el_btn is not None:
print("bingo, found next button, start to press")
try:
if el_btn.is_enabled() and el_btn.is_displayed():
el_btn.click()
ret = True
except Exception as exc:
print("click next button fail...")
print(exc)
return ret
def hkticketing_ticket_delivery_option(driver):
show_debug_message = True # debug.
show_debug_message = False # online
is_delivery_option_assigned = False
form_select = None
try:
selector_string = '#selectDeliveryType'
form_select = driver.find_element(By.CSS_SELECTOR, selector_string)
except Exception as exc:
if show_debug_message:
print("find selectDeliveryType select fail")
print(exc)
pass
select_obj = None
if form_select is not None:
is_visible = False
try:
is_visible = form_select.is_enabled()
except Exception as exc:
pass
if is_visible:
try:
select_obj = Select(form_select)
except Exception as exc:
pass
if select_obj is not None:
try:
select_obj.select_by_value("1")
is_delivery_option_assigned = True
except Exception as exc:
print("delivery_option fail")
print(exc)
return is_delivery_option_assigned
def hkticketing_hide_tickets_blocks(driver):
show_debug_message = True # debug.
show_debug_message = False # online
actionBlock_divs = None
try:
selector_string = 'div.actionBlock.note'
actionBlock_divs = driver.find_elements(By.CSS_SELECTOR, selector_string)
for each_div in actionBlock_divs:
driver.execute_script("arguments[0].innerHTML='';", each_div);
except Exception as exc:
if show_debug_message:
print("find selectDeliveryType select fail")
print(exc)
pass
detailModuleCopy_divs = None
try:
selector_string = 'div.detailModuleCopy'
detailModuleCopy_divs = driver.find_elements(By.CSS_SELECTOR, selector_string)
if not detailModuleCopy_divs is None:
driver.execute_script("arguments[0].innerHTML='';", detailModuleCopy_divs);
except Exception as exc:
pass
mapWrapper_divs = None
try:
selector_string = 'div.mapWrapper'
mapWrapper_divs = driver.find_elements(By.CSS_SELECTOR, selector_string)
if not mapWrapper_divs is None:
driver.execute_script("arguments[0].innerHTML='';", mapWrapper_divs);
except Exception as exc:
pass
def hkticketing_performance(driver, config_dict, domain_name):
show_debug_message = True # debug.
show_debug_message = False # online
is_price_assign_by_bot = False
is_need_refresh = False
auto_fill_ticket_number = True
if auto_fill_ticket_number:
# click price row.
area_auto_select_mode = config_dict["tixcraft"]["area_auto_select"]["mode"]
area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"].strip()
area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"].strip()
area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"].strip()
area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"].strip()
area_keyword_1_and = ""
area_keyword_2_and = ""
if show_debug_message:
print("area_keyword_1:", area_keyword_1)
#print("area_keyword_1_and:", area_keyword_1_and)
print("area_keyword_2:", area_keyword_2)
#print("area_keyword_2_and:", area_keyword_2_and)
is_need_refresh = False
if not is_price_assign_by_bot:
is_need_refresh, is_price_assign_by_bot = hkticketing_area_auto_select(driver, area_auto_select_mode, area_keyword_1, area_keyword_1_and)
if not is_need_refresh:
if not is_price_assign_by_bot:
# try keyword_2
if len(area_keyword_2) > 0:
is_need_refresh, is_price_assign_by_bot = hkticketing_area_auto_select(driver, area_auto_select_mode, area_keyword_2, area_keyword_2_and)
if not is_need_refresh:
if not is_price_assign_by_bot:
if len(area_keyword_3) > 0:
is_need_refresh, is_price_assign_by_bot = hkticketing_area_auto_select(driver, area_auto_select_mode, area_keyword_3, "")
if not is_need_refresh:
if not is_price_assign_by_bot:
if len(area_keyword_4) > 0:
is_need_refresh, is_price_assign_by_bot = hkticketing_area_auto_select(driver, area_auto_select_mode, area_keyword_4, "")
if is_need_refresh:
if show_debug_message:
print("is_need_refresh:", is_need_refresh)
try:
driver.refresh()
except Exception as exc:
pass
# hide blocks.
hkticketing_hide_tickets_blocks(driver)
# goto bottom.
hkticketing_nav_to_footer(driver)
# choose ticket.
ticket_number = str(config_dict["ticket_number"])
is_ticket_number_assigned = hkticketing_ticket_number_auto_select(driver, ticket_number)
if show_debug_message:
print("ticket_number:", ticket_number)
print("is_ticket_number_assigned:", is_ticket_number_assigned)
# Select a delivery option
is_delivery_option_assigned = True
if not 'galaxymacau.com' in domain_name:
# hkticketing
is_delivery_option_assigned = False
if is_ticket_number_assigned:
is_delivery_option_assigned = hkticketing_ticket_delivery_option(driver)
if show_debug_message:
print("is_delivery_option_assigned:", is_delivery_option_assigned)
if is_delivery_option_assigned:
auto_press_next_step_button = True
if auto_press_next_step_button:
if is_price_assign_by_bot:
for i in range(2):
click_ret = hkticketing_next_button_press(driver)
time.sleep(0.2)
if click_ret:
break
return is_price_assign_by_bot
def hkticketing_escape_robot_detection(driver):
ret = False
el_main_iframe = None
try:
el_main_iframe = driver.find_element(By.ID, 'main-iframe')
except Exception as exc:
print("find el_main_iframe fail...")
#print(exc)
pass
if el_main_iframe is not None:
print("bingo, found el_main_iframe, start to escape")
entry_url="https://queue.hkticketing.com/hotshow.html"
try:
driver.get(entry_url)
except Exception as exc:
print(exc)
return ret
def hkticketing_main(driver, url, config_dict):
home_url_list = ['https://premier.hkticketing.com/'
,'https://hotshow.hkticketing.com/'
,'https://premier.hkticketing.com/default.aspx'
,'https://hotshow.hkticketing.com/default.aspx'
,'https://premier.hkticketing.com/Membership/Login.aspx'
,'https://hotshow.hkticketing.com/Membership/Login.aspx'
]
for each_url in home_url_list:
if each_url == url:
hkticketing_home(driver)
time.sleep(0.2)
break
if 'queue.hkticketing.com/hotshow.html' in url:
entry_url = 'http://entry-hotshow.hkticketing.com/'
try:
driver.get(entry_url)
except Exception as exc:
pass
# PS: share function with galaxymacau, but memeber is not shared.
if 'hkticketing.com/Membership/Login.aspx' in url:
account = config_dict["advanced"]["hkticketing_account"].strip()
if len(account) > 4:
hkticketing_login(driver, account, decryptMe(config_dict["advanced"]["hkticketing_password"]))
#https://premier.hkticketing.com/shows/show.aspx?sh=XXXX
if 'shows/show.aspx?' in url:
is_modal_dialog_popup = check_modal_dialog_popup(driver)
if is_modal_dialog_popup:
print("is_modal_dialog_popup! skip...")
else:
is_event_page = False
if len(url.split('/'))==5:
is_event_page = True
if is_event_page:
date_auto_select_enable = config_dict["tixcraft"]["date_auto_select"]["enable"]
if date_auto_select_enable:
hkticketing_show(driver, config_dict)
pass
# https://premier.hkticketing.com/events/XXX/venues/KSH/performances/XXX/tickets
if '/events/' in url and '/performances/' in url:
robot_detection = hkticketing_escape_robot_detection(driver)
is_modal_dialog_popup = check_modal_dialog_popup(driver)
if is_modal_dialog_popup:
print("is_modal_dialog_popup! skip...")
else:
if '/tickets' in url:
domain_name = url.split('/')[2]
area_auto_select_enable = config_dict["tixcraft"]["area_auto_select"]["enable"]
if area_auto_select_enable:
hkticketing_performance(driver, config_dict, domain_name)
pass
if '/seatmap' in url:
# goto bottom.
hkticketing_nav_to_footer(driver)
hkticketing_go_to_payment(driver)
def khan_go_buy_redirect(driver):
ret = False
el_btn = None
try:
el_btn = driver.find_element(By.CSS_SELECTOR, 'div.btn_go > input[type="image"]')
except Exception as exc:
#print("find next button fail...")
#print(exc)
pass
if el_btn is not None:
print("bingo, found next button, start to press")
try:
if el_btn.is_enabled() and el_btn.is_displayed():
el_btn.click()
ret = True
except Exception as exc:
print("click next button fail...")
print(exc)
return ret
def hkam_date_auto_select(driver, auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable):
show_debug_message = True # debug.
show_debug_message = False # online
ret = False
matched_blocks = None
# clean stop word.
date_keyword = format_keyword_string(date_keyword)
date_keyword_and = ""
# default not selected.
is_date_assigned = False
if not is_date_assigned:
area_list = None
try:
my_css_selector = "td.contentCenterBg > table > tbody > tr > td > table > tbody > tr > td > table > tbody > tr > td > div > table > tbody > tr"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #date-time tr list fail")
print(exc)
#PS: some blocks are generate by ajax, not appear at first time.
formated_area_list = None
if area_list is not None:
area_list_count = len(area_list)
if show_debug_message:
print("date_list_count:", area_list_count)
if area_list_count > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
row_is_enabled=False
try:
row_text = row.text
if '立即訂購' in row_text:
my_css_selector = "a.showoder"
el_btn = row.find_element(By.CSS_SELECTOR, my_css_selector)
if el_btn is not None:
if el_btn.is_enabled():
#print("row's button enabled.")
row_is_enabled=True
except Exception as exc:
if show_debug_message:
print(exc)
pass
if row_is_enabled:
formated_area_list.append(row)
else:
if show_debug_message:
print("area_list is None...")
if formated_area_list is not None:
area_list_count = len(formated_area_list)
if show_debug_message:
print("formated_area_list count:", area_list_count)
if area_list_count > 0:
if len(date_keyword) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
if show_debug_message:
print("start to match keyword:", date_keyword)
matched_blocks = []
row_index = 0
for row in formated_area_list:
row_index += 1
row_is_enabled=True
if row_is_enabled:
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
row_text = format_keyword_string(row_text)
if show_debug_message:
print("row_text:", row_text)
is_match_area = False
match_area_code = 0
if date_keyword in row_text:
if len(date_keyword_and) == 0:
if show_debug_message:
print('keyword_and # is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if date_keyword_and in row_text:
if show_debug_message:
print('match keyword_and')
is_match_area = True
match_area_code = 3
else:
if show_debug_message:
print('not match keyword_and')
pass
if is_match_area:
matched_blocks.append(row)
if show_debug_message:
if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks))
else:
print("not found date-time-position")
pass
else:
print("date date-time-position is None")
pass
target_area = None
if matched_blocks is not None:
if len(matched_blocks) > 0:
target_row_index = 0
if auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(matched_blocks)-1
if auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(matched_blocks)-1)
target_area = matched_blocks[target_row_index]
if target_area is not None:
el_btn = None
try:
my_css_selector = "a.showoder"
el_btn = target_area.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
if el_btn is not None:
try:
if el_btn.is_enabled() and el_btn.is_displayed():
el_btn.click()
print("buy button pressed.")
ret = True
except Exception as exc:
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_btn)
ret = True
except Exception as exc:
pass
'''
if auto_reload_coming_soon_page_enable:
# auto refresh for date list page.
if not formated_area_list is None:
if len(formated_area_list) == 0:
try:
driver.refresh()
time.sleep(0.4)
except Exception as exc:
pass
'''
return ret
def kham_product(driver, config_dict):
show_debug_message = True # debug.
show_debug_message = False # online
date_auto_select_mode = config_dict["tixcraft"]["date_auto_select"]["mode"]
date_keyword = config_dict["tixcraft"]["date_auto_select"]["date_keyword"].strip()
auto_reload_coming_soon_page_enable = config_dict["tixcraft"]["auto_reload_coming_soon_page"]
if show_debug_message:
print("date_keyword:", date_keyword)
print("auto_reload_coming_soon_page_enable:", auto_reload_coming_soon_page_enable)
is_date_assign_by_bot = hkam_date_auto_select(driver, date_auto_select_mode, date_keyword, auto_reload_coming_soon_page_enable)
return is_date_assign_by_bot
def kham_area_auto_select(driver, area_auto_select_mode, area_keyword_1, area_keyword_1_and, ticket_number):
show_debug_message = True # debug.
show_debug_message = False # online
is_price_assign_by_bot = False
is_need_refresh = False
matched_blocks = None
# clean stop word.
area_keyword_1 = format_keyword_string(area_keyword_1)
area_keyword_1_and = format_keyword_string(area_keyword_1_and)
area_list = None
try:
my_css_selector = "table.salesTable > tbody > tr > td > table > tbody > tr"
area_list = driver.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #ticket-price-tbl date list fail")
print(exc)
readme_table_mode = False
if area_list is None:
readme_table_mode = True
else:
if len(area_list)==0:
readme_table_mode = True
if readme_table_mode:
if show_debug_message:
print("for without table.salesTable")
try:
my_css_selector = "#readmeTable"
readme_table = driver.find_element(By.CSS_SELECTOR, my_css_selector)
if not readme_table is None:
if show_debug_message:
print("found readme_table")
target_table = readme_table.find_element(By.XPATH, '../..')
if not target_table is None:
if show_debug_message:
print("found target_table")
my_css_selector = "td > table > tbody > tr"
area_list = target_table.find_elements(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find #ticket-price-tbl date list fail")
print(exc)
formated_area_list = None
if area_list is not None:
area_list_count = len(area_list)
if show_debug_message:
print("area_list_count:", area_list_count)
if area_list_count > 0:
formated_area_list = []
# filter list.
row_index = 0
for row in area_list:
row_index += 1
row_is_enabled=False
try:
is_row_with_id = False
tr_id_string = str(row.get_attribute('id'))
if len(tr_id_string) > 1:
is_row_with_id = True
if is_row_with_id:
my_css_selector = "span.textPrice"
el_remaining = row.find_element(By.CSS_SELECTOR, my_css_selector)
if el_remaining is not None:
remaining_value = str(el_remaining.text).strip()
if remaining_value.isnumeric():
if int(remaining_value) >= ticket_number:
row_is_enabled=True
else:
# text directly allow.
row_is_enabled=True
if '售完' in remaining_value:
row_is_enabled=False
except Exception as exc:
pass
if row_is_enabled:
formated_area_list.append(row)
else:
if show_debug_message:
print("area_list_count is empty.")
pass
else:
if show_debug_message:
print("area_list_count is None.")
pass
if formated_area_list is not None:
area_list_count = len(formated_area_list)
if show_debug_message:
print("formated_area_list count:", area_list_count)
if area_list_count > 0:
if len(area_keyword_1) == 0:
matched_blocks = formated_area_list
else:
# match keyword.
if show_debug_message:
print("start to match keyword:", area_keyword_1)
print("keyword and:", area_keyword_1_and)
matched_blocks = []
row_index = 0
for row in formated_area_list:
row_index += 1
row_is_enabled=True
if row_is_enabled:
row_text = ""
try:
row_text = row.text
except Exception as exc:
print("get text fail")
break
if row_text is None:
row_text = ""
if len(row_text) > 0:
row_text = format_keyword_string(row_text)
if show_debug_message:
print("row_text:", row_text)
is_match_area = False
match_area_code = 0
if area_keyword_1 in row_text:
if len(area_keyword_1_and) == 0:
if show_debug_message:
print('keyword_and is empty, directly match.')
# keyword #2 is empty, direct append.
is_match_area = True
match_area_code = 2
else:
if area_keyword_1_and in row_text:
if show_debug_message:
print('match keyword_and')
is_match_area = True
match_area_code = 3
else:
if show_debug_message:
print('not match keyword_and')
pass
if is_match_area:
matched_blocks.append(row)
if show_debug_message:
if not matched_blocks is None:
print("after match keyword, found count:", len(matched_blocks))
else:
is_need_refresh = True
if show_debug_message:
print("formated_area_list is empty.")
target_area = None
if matched_blocks is not None:
if len(matched_blocks) > 0:
target_row_index = 0
if area_auto_select_mode == CONST_FROM_TOP_TO_BOTTOM:
pass
if area_auto_select_mode == CONST_FROM_BOTTOM_TO_TOP:
target_row_index = len(matched_blocks)-1
if area_auto_select_mode == CONST_RANDOM:
target_row_index = random.randint(0,len(matched_blocks)-1)
target_area = matched_blocks[target_row_index]
else:
if show_debug_message:
print("matched_blocks is None.")
if target_area is not None:
try:
if target_area.is_enabled():
target_area.click()
is_price_assign_by_bot = True
except Exception as exc:
print("click target_area link fail")
print(exc)
# use plan B
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", target_area)
is_price_assign_by_bot = True
except Exception as exc:
pass
else:
if show_debug_message:
print("target_area is None, no target to click.")
if show_debug_message:
print("is_need_refresh:", is_need_refresh)
print("is_price_assign_by_bot:", is_price_assign_by_bot)
return is_need_refresh, is_price_assign_by_bot
def kham_performance_ticket_number(driver, ticket_number):
ret = False
form_input = None
try:
form_input = driver.find_element(By.CSS_SELECTOR, 'td.tdtext_orangeunderline > input[type="text"]')
except Exception as exc:
#print("find modal-dialog fail")
#print(exc)
pass
inputed_value = None
if form_input is not None:
try:
inputed_value = form_input.get_attribute('value')
except Exception as exc:
print("find verify code fail")
pass
if inputed_value is None:
inputed_value = ""
if inputed_value == "":
is_visible = False
try:
if form_input.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
form_input.click()
form_input.send_keys(str(ticket_number))
ret = True
except Exception as exc:
# use plan B
'''
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_div)
ret = True
except Exception as exc:
pass
'''
pass
return ret
def kham_performance(driver, config_dict, ocr, Captcha_Browser, model_name):
show_debug_message = True # debug.
show_debug_message = False # online
is_price_assign_by_bot = False
is_need_refresh = False
auto_fill_ticket_number = True
if auto_fill_ticket_number:
# click price row.
area_auto_select_mode = config_dict["tixcraft"]["area_auto_select"]["mode"]
area_keyword_1 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_1"].strip()
area_keyword_2 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_2"].strip()
area_keyword_3 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_3"].strip()
area_keyword_4 = config_dict["tixcraft"]["area_auto_select"]["area_keyword_4"].strip()
area_keyword_1_and = ""
area_keyword_2_and = ""
ticket_number = config_dict["ticket_number"]
if show_debug_message:
print("area_keyword_1:", area_keyword_1)
#print("area_keyword_1_and:", area_keyword_1_and)
print("area_keyword_2:", area_keyword_2)
#print("area_keyword_2_and:", area_keyword_2_and)
print("ticket_number:", ticket_number)
is_need_refresh = False
if not is_price_assign_by_bot:
is_need_refresh, is_price_assign_by_bot = kham_area_auto_select(driver, area_auto_select_mode, area_keyword_1, area_keyword_1_and, ticket_number)
if not is_need_refresh:
if not is_price_assign_by_bot:
# try keyword_2
if len(area_keyword_2) > 0:
is_need_refresh, is_price_assign_by_bot = kham_area_auto_select(driver, area_auto_select_mode, area_keyword_2, area_keyword_2_and, ticket_number)
if not is_need_refresh:
if not is_price_assign_by_bot:
if len(area_keyword_3) > 0:
is_need_refresh, is_price_assign_by_bot = kham_area_auto_select(driver, area_auto_select_mode, area_keyword_3, "", ticket_number)
if not is_need_refresh:
if not is_price_assign_by_bot:
if len(area_keyword_4) > 0:
is_need_refresh, is_price_assign_by_bot = kham_area_auto_select(driver, area_auto_select_mode, area_keyword_4, "", ticket_number)
if is_need_refresh:
if show_debug_message:
print("is_need_refresh:", is_need_refresh)
try:
driver.refresh()
except Exception as exc:
pass
# special case for UTK0202 model.
is_ticket_number_assigned = kham_performance_ticket_number(driver, ticket_number)
if is_ticket_number_assigned:
is_captcha_sent = kham_captcha(driver, config_dict, ocr, Captcha_Browser, model_name)
if is_captcha_sent:
el_btn = None
try:
my_css_selector = 'input[onclick="return chkCart();"]'
el_btn = driver.find_element(By.CSS_SELECTOR, my_css_selector)
if not el_btn is None:
el_btn.click()
except Exception as exc:
print("find chkCart button fail")
pass
return is_price_assign_by_bot
def kham_performance_confirm_dialog_popup(driver):
ret = False
el_div = None
try:
el_div = driver.find_element(By.CSS_SELECTOR, 'div.ui-dialog-buttonset > button.ui-button')
except Exception as exc:
#print("find modal-dialog fail")
#print(exc)
pass
if el_div is not None:
#print("bingo, found ui-dialog-buttonset confirm-btn")
is_visible = False
try:
if el_div.is_enabled():
if el_div.is_displayed():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
el_div.click()
ret = True
except Exception as exc:
# use plan B
'''
try:
print("force to click by js.")
driver.execute_script("arguments[0].click();", el_div)
ret = True
except Exception as exc:
pass
'''
pass
return ret
def kham_keyin_captcha_code(driver, answer = "", auto_submit = False):
is_verifyCode_editing = False
is_form_sumbited = False
# manually keyin verify code.
# start to input verify code.
form_verifyCode = None
try:
#my_css_selector = 'table#blockLogin > tbody > tr > td > input[type="text"]'
my_css_selector = 'input[value="驗證碼"]'
form_verifyCode = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
print("find blockLogin input fail")
try:
my_css_selector = 'input[placeholder="驗證碼"]'
form_verifyCode = driver.find_element(By.CSS_SELECTOR, my_css_selector)
except Exception as exc:
pass
if form_verifyCode is not None:
inputed_value = None
try:
inputed_value = form_verifyCode.get_attribute('value')
except Exception as exc:
print("find verify code fail")
pass
if inputed_value is None:
inputed_value = ""
if inputed_value == "驗證碼":
try:
form_verifyCode.clear()
except Exception as exc:
print("clear verify code fail")
pass
else:
if len(inputed_value) > 0:
print("captcha text inputed.")
form_verifyCode = None
is_verifyCode_editing = True
if form_verifyCode is not None:
is_visible = False
try:
if form_verifyCode.is_enabled():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
form_verifyCode.click()
is_verifyCode_editing = True
except Exception as exc:
pass
#print("start to fill answer.")
try:
if len(answer) > 0:
answer=answer.upper()
form_verifyCode.clear()
form_verifyCode.send_keys(answer)
if auto_submit:
form_verifyCode.send_keys(Keys.ENTER)
is_verifyCode_editing = False
is_form_sumbited = True
else:
print("select all captcha text")
driver.execute_script("arguments[0].select();", form_verifyCode)
if len(answer) > 0:
#tixcraft_toast(driver, "※ 按 Enter 如果答案是: " + answer)
pass
except Exception as exc:
print("send_keys ocr answer fail.")
return is_verifyCode_editing, is_form_sumbited
def kham_auto_ocr(driver, ocr, away_from_keyboard_enable, previous_answer, Captcha_Browser, ocr_captcha_image_source, model_name):
show_debug_message = True # debug.
show_debug_message = False # online
print("start to ddddocr")
CONST_OCR_CAPTCH_IMAGE_SOURCE_NON_BROWSER = "NonBrowser"
CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS = "canvas"
is_need_redo_ocr = False
is_form_sumbited = False
orc_answer = None
if not ocr is None:
if show_debug_message:
print("away_from_keyboard_enable:", away_from_keyboard_enable)
print("previous_answer:", previous_answer)
print("ocr_captcha_image_source:", ocr_captcha_image_source)
ocr_start_time = time.time()
img_base64 = None
if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_NON_BROWSER:
if not Captcha_Browser is None:
img_base64 = base64.b64decode(Captcha_Browser.Request_Captcha())
if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS:
image_id = 'chk_pic'
try:
form_verifyCode_base64 = driver.execute_async_script("""
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var img = document.getElementById('%s');
canvas.height = img.naturalHeight;
canvas.width = img.naturalWidth;
context.drawImage(img, 0, 0);
callback = arguments[arguments.length - 1];
callback(canvas.toDataURL());
""" % (image_id))
img_base64 = base64.b64decode(form_verifyCode_base64.split(',')[1])
except Exception as exc:
if show_debug_message:
print("canvas exception:", str(exc))
pass
if not img_base64 is None:
try:
orc_answer = ocr.classification(img_base64)
except Exception as exc:
pass
ocr_done_time = time.time()
ocr_elapsed_time = ocr_done_time - ocr_start_time
print("ocr elapsed time:", "{:.3f}".format(ocr_elapsed_time))
else:
print("ddddocr is None")
if not orc_answer is None:
orc_answer = orc_answer.strip()
print("orc_answer:", orc_answer)
if len(orc_answer)==4:
who_care_var, is_form_sumbited = kham_keyin_captcha_code(driver, answer = orc_answer, auto_submit = away_from_keyboard_enable)
else:
if not away_from_keyboard_enable:
kham_keyin_captcha_code(driver)
#tixcraft_toast(driver, "※ OCR辨識失敗Q_Q驗證碼請手動輸入...")
else:
is_need_redo_ocr = True
if previous_answer != orc_answer:
previous_answer = orc_answer
print("click captcha again")
if True:
# selenium solution.
jquery_string = '$("#chk_pic").attr("src", "/pic.aspx?TYPE=%s&ts=" + new Date().getTime());' % (model_name)
driver.execute_script(jquery_string)
if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS:
time.sleep(0.3)
else:
# Non_Browser solution.
if not Captcha_Browser is None:
new_captcha_url = Captcha_Browser.Request_Refresh_Captcha() #取得新的CAPTCHA
if new_captcha_url != "":
#PS:[TODO]
#tixcraft_change_captcha(driver, new_captcha_url) #更改CAPTCHA圖
pass
else:
print("orc_answer is None")
print("previous_answer:", previous_answer)
if previous_answer is None:
kham_keyin_captcha_code(driver)
else:
# page is not ready, retry again.
# PS: usually occur in async script get captcha image.
is_need_redo_ocr = True
return is_need_redo_ocr, previous_answer, is_form_sumbited
def kham_captcha(driver, config_dict, ocr, Captcha_Browser, model_name):
ocr_captcha_enable = config_dict["ocr_captcha"]["enable"]
away_from_keyboard_enable = config_dict["ocr_captcha"]["force_submit"]
if not ocr_captcha_enable:
away_from_keyboard_enable = False
ocr_captcha_image_source = config_dict["ocr_captcha"]["image_source"]
#PS: need a 'auto assign site' feature to enable away_from_keyboard feature.
away_from_keyboard_enable = False
is_cpatcha_sent = False
previous_answer = None
is_verifyCode_editing = True
for redo_ocr in range(999):
is_need_redo_ocr, previous_answer, is_form_sumbited = kham_auto_ocr(driver, ocr, away_from_keyboard_enable, previous_answer, Captcha_Browser, ocr_captcha_image_source, model_name)
# TODO: must ensure the answer is corrent...
is_cpatcha_sent = True
if is_form_sumbited:
break
if not away_from_keyboard_enable:
break
if not is_need_redo_ocr:
break
return is_cpatcha_sent
def kham_home_close_window(driver):
show_debug_message = True # debug.
show_debug_message = False # online
close_all_alert_btns = None
try:
close_all_alert_btns = driver.find_elements(By.ID, 'Close')
except Exception as exc:
print("find close_all_alert_btns fail")
if close_all_alert_btns is not None:
if show_debug_message:
print('all alert count:', len(close_all_alert_btns))
for alert_btn in close_all_alert_btns:
is_visible = False
try:
if alert_btn.is_enabled() and alert_btn.is_displayed():
is_visible = True
except Exception as exc:
pass
if is_visible:
try:
alert_btn.click()
except Exception as exc:
print("try to click alert_btn fail, force click by js.")
try:
driver.execute_script("arguments[0].click();", alert_btn)
except Exception as exc:
pass
def kham_main(driver, url, config_dict, ocr, Captcha_Browser):
home_url_list = ['https://kham.com.tw/'
,'https://kham.com.tw/application/utk01/utk0101_.aspx'
,'https://kham.com.tw/application/utk01/utk0101_03.aspx']
for each_url in home_url_list:
if each_url == url.lower():
kham_home_close_window(driver)
if config_dict["ocr_captcha"]["enable"]:
domain_name = url.split('/')[2]
if not Captcha_Browser is None:
Captcha_Browser.Set_cookies(driver.get_cookies())
Captcha_Browser.Set_Domain(domain_name)
break
# https://kham.com.tw/application/UTK13/UTK1306_.aspx
if 'utk1306' in url.lower() and '.aspx' in url:
if config_dict["ocr_captcha"]["enable"]:
domain_name = url.split('/')[2]
model_name = url.split('/')[5]
if len(model_name) > 7:
model_name=model_name[:7]
captcha_url = '/pic.aspx?TYPE=%s' % (model_name)
#PS: need set cookies once, if user change domain.
if not Captcha_Browser is None:
Captcha_Browser.Set_Domain(domain_name, captcha_url=captcha_url)
kham_captcha(driver, config_dict, ocr, Captcha_Browser, model_name)
#https://kham.com.tw/application/UTK02/UTK0201_.aspx?PRODUCT_ID=XXX
if 'utk0201_.aspx?product_id=' in url.lower():
is_event_page = False
if len(url.split('/'))==6:
is_event_page = True
if is_event_page:
khan_go_buy_redirect(driver)
# https://kham.com.tw/application/UTK02/UTK0201_00.aspx?PRODUCT_ID=N28TFATD
if 'utk0201_00.aspx?product_id=' in url.lower():
is_event_page = False
if len(url.split('/'))==6:
is_event_page = True
if is_event_page:
date_auto_select_enable = config_dict["tixcraft"]["date_auto_select"]["enable"]
if date_auto_select_enable:
kham_product(driver, config_dict)
# https://kham.com.tw/application/UTK02/UTK0204_.aspx?PERFORMANCE_ID=N28UQPA1&PRODUCT_ID=N28TFATD
if '.aspx?performance_id=' in url.lower() and 'product_id=' in url.lower():
area_auto_select_enable = config_dict["tixcraft"]["area_auto_select"]["enable"]
if area_auto_select_enable:
domain_name = url.split('/')[2]
model_name = url.split('/')[5]
if len(model_name) > 7:
model_name=model_name[:7]
captcha_url = '/pic.aspx?TYPE=%s' % (model_name)
#PS: need set cookies once, if user change domain.
if not Captcha_Browser is None:
Captcha_Browser.Set_Domain(domain_name, captcha_url=captcha_url)
is_confirm_dialog_popup = kham_performance_confirm_dialog_popup(driver)
if is_confirm_dialog_popup:
print("is_confirm_dialog_popup! auto press confirm...")
kham_performance(driver, config_dict, ocr, Captcha_Browser, model_name)
#https://kham.com.tw/application/UTK02/UTK0205_.aspx?PERFORMANCE_ID=XXX&GROUP_ID=30&PERFORMANCE_PRICE_AREA_ID=XXX
if '.aspx?performance_id=' in url.lower() and 'performance_price_area_id=' in url.lower():
is_confirm_dialog_popup = kham_performance_confirm_dialog_popup(driver)
if is_confirm_dialog_popup:
print("is_confirm_dialog_popup! auto press confirm...")
if config_dict["ocr_captcha"]["enable"]:
domain_name = url.split('/')[2]
model_name = url.split('/')[5]
if len(model_name) > 7:
model_name=model_name[:7]
captcha_url = '/pic.aspx?TYPE=%s' % (model_name)
#PS: need set cookies once, if user change domain.
if not Captcha_Browser is None:
Captcha_Browser.Set_Domain(domain_name, captcha_url=captcha_url)
kham_captcha(driver, config_dict, ocr, Captcha_Browser, model_name)
if '/application/utk13/utk1306_.aspx' in url.lower():
if config_dict["ocr_captcha"]["enable"]:
domain_name = url.split('/')[2]
model_name = url.split('/')[5]
if len(model_name) > 7:
model_name=model_name[:7]
captcha_url = '/pic.aspx?TYPE=%s' % (model_name)
#PS: need set cookies once, if user change domain.
if not Captcha_Browser is None:
Captcha_Browser.Set_Domain(domain_name, captcha_url=captcha_url)
kham_captcha(driver, config_dict, ocr, Captcha_Browser, model_name)
account = config_dict["advanced"]["kham_account"].strip()
if len(account) > 4:
kham_login(driver, account, decryptMe(config_dict["advanced"]["kham_password"]))
def main():
config_dict = get_config_dict()
driver = None
if not config_dict is None:
driver = get_driver_by_config(config_dict)
else:
print("Load config error!")
# internal variable. 說明:這是一個內部變數,請略過。
url = ""
last_url = ""
# for tixcraft
tixcraft_dict = {}
tixcraft_dict["answer_index"]=-1
tixcraft_dict["is_verifyCode_editing"] = False
tixcraft_dict["is_popup_checkout"] = False
# for kktix
kktix_dict = {}
kktix_dict["answer_index"]=-1
kktix_dict["kktix_register_status_last"] = None
kktix_dict["is_popup_checkout"] = False
ibon_dict = {}
ibon_dict["answer_index"]=-1
DISCONNECTED_MSG = ': target window already closed'
ocr = None
Captcha_Browser = None
try:
if config_dict["ocr_captcha"]["enable"]:
ocr = ddddocr.DdddOcr(show_ad=False, beta=True)
Captcha_Browser = NonBrowser()
except Exception as exc:
pass
while True:
time.sleep(0.1)
is_alert_popup = False
# pass if driver not loaded.
if driver is None:
print("web driver not accessible!")
break
#is_alert_popup = check_pop_alert(driver)
#MUST "do nothing: if alert popup.
#print("is_alert_popup:", is_alert_popup)
if is_alert_popup:
continue
url = ""
try:
url = driver.current_url
except NoSuchWindowException:
print('NoSuchWindowException at this url:', url )
#print("last_url:", last_url)
#print("get_log:", driver.get_log('driver'))
window_handles_count = 0
try:
window_handles_count = len(driver.window_handles)
#print("window_handles_count:", window_handles_count)
if window_handles_count >= 1:
driver.switch_to.window(driver.window_handles[0])
driver.switch_to.default_content()
time.sleep(0.2)
except Exception as excSwithFail:
#print("excSwithFail:", excSwithFail)
pass
if window_handles_count==0:
try:
driver_log = driver.get_log('driver')[-1]['message']
print("get_log:", driver_log)
if DISCONNECTED_MSG in driver_log:
print('quit bot by NoSuchWindowException')
driver.quit()
sys.exit()
break
except Exception as excGetDriverMessageFail:
#print("excGetDriverMessageFail:", excGetDriverMessageFail)
except_string = str(excGetDriverMessageFail)
if 'HTTP method not allowed' in except_string:
print('quit bot by close browser')
driver.quit()
sys.exit()
break
except UnexpectedAlertPresentException as exc1:
# PS: DON'T remove this line.
is_verifyCode_editing = False
print('UnexpectedAlertPresentException at this url:', url )
#time.sleep(3.5)
# PS: do nothing...
# PS: current chrome-driver + chrome call current_url cause alert/prompt dialog disappear!
# raise exception at selenium/webdriver/remote/errorhandler.py
# after dialog disappear new excpetion: unhandled inspector error: Not attached to an active page
is_pass_alert = False
is_pass_alert = True
if is_pass_alert:
try:
driver.switch_to.alert.accept()
except Exception as exc:
pass
except Exception as exc:
is_verifyCode_editing = False
logger.error('Maxbot URL Exception')
logger.error(exc, exc_info=True)
#UnicodeEncodeError: 'ascii' codec can't encode characters in position 63-72: ordinal not in range(128)
str_exc = ""
try:
str_exc = str(exc)
except Exception as exc2:
pass
if len(str_exc)==0:
str_exc = repr(exc)
exit_bot_error_strings = [u'Max retries exceeded'
, u'chrome not reachable'
, u'unable to connect to renderer'
, u'failed to check if window was closed'
, u'Failed to establish a new connection'
, u'Connection refused'
, u'disconnected'
, u'without establishing a connection'
, u'web view not found'
]
for each_error_string in exit_bot_error_strings:
# for python2
# say goodbye to python2
'''
try:
basestring
if isinstance(each_error_string, unicode):
each_error_string = str(each_error_string)
except NameError: # Python 3.x
basestring = str
'''
if isinstance(str_exc, str):
if each_error_string in str_exc:
print('quit bot by error:', each_error_string)
driver.quit()
sys.exit()
break
# not is above case, print exception.
print("Exception:", str_exc)
pass
if url is None:
continue
else:
if len(url) == 0:
continue
# 說明:輸出目前網址,覺得吵的話,請註解掉這行。
#print("url:", url)
if len(url) > 0 :
if url != last_url:
print(url)
last_url = url
tixcraft_family = False
if 'tixcraft.com' in url:
tixcraft_family = True
if 'indievox.com' in url:
tixcraft_family = True
if tixcraft_family:
tixcraft_dict = tixcraft_main(driver, url, config_dict, tixcraft_dict, ocr, Captcha_Browser)
# for kktix.cc and kktix.com
if 'kktix.c' in url:
kktix_dict = kktix_main(driver, url, config_dict, kktix_dict)
if 'famiticket.com' in url:
famiticket_main(driver, url, config_dict)
if 'ibon.com' in url:
ibon_dict = ibon_main(driver, url, config_dict, ibon_dict)
if 'kham.com' in url:
kham_main(driver, url, config_dict, ocr, Captcha_Browser)
if 'urbtix.hk' in url:
urbtix_main(driver, url, config_dict)
if 'cityline.com' in url:
cityline_main(driver, url, config_dict)
if 'hkticketing.com' in url:
hkticketing_main(driver, url, config_dict)
if 'galaxymacau.com' in url:
hkticketing_main(driver, url, config_dict)
# for facebook
facebook_login_url = 'https://www.facebook.com/login.php?'
if url[:len(facebook_login_url)]==facebook_login_url:
facebook_account = config_dict["advanced"]["facebook_account"].strip()
if len(facebook_account) > 4:
facebook_login(driver, facebook_account, decryptMe(config_dict["advanced"]["facebook_password"]))
if __name__ == "__main__":
CONST_MODE_GUI = 0
CONST_MODE_CLI = 1
mode = CONST_MODE_GUI
#mode = CONST_MODE_CLI
if mode == CONST_MODE_GUI:
main()
else:
#for test kktix infer answer.
captcha_text_div_text = u"請回答下列問題,請在下方空格輸入DELIGHT請以半形輸入法作答大小寫需要一模一樣"
#captcha_text_div_text = u"請在下方空白處輸入引號內文字「abc」"
#captcha_text_div_text = u"請在下方空白處輸入引號內文字「0118eveconcert」請以半形小寫作答。"
#captcha_text_div_text = "在《DEEP AWAKENING見過深淵的人》專輯中哪一首為合唱曲目 【V6】深淵 、【Z5】浮木、【J8】無聲、【C1】以上皆非 (請以半形輸入法作答,大小寫/阿拉伯數字需要一模一樣範例A2"
#captcha_text_div_text = "Super Junior 的隊長是以下哪位? 【v】神童 【w】藝聲 【x】利特 【y】始源 若你覺得答案為 a請輸入 a (英文為半形小寫)"
#captcha_text_div_text = "請問XXX, 請以英文為半形小寫(例如a) a. 1月5日 b. 2月5日 c. 3月5日 d. 4月5日"
#captcha_text_div_text = "以下為選擇題:請問 「OHM NANON 1st Fan Meeting in Hong Kong」 舉行日期是?請以半形細楷英文於下方輸入答案 (例如a) a. 1月5日 b. 2月5日 c. 3月5日 d. 4月5日"
#captcha_text_div_text = "以下哪個「不是」正確的林俊傑與其他藝人合唱的歌曲組合?(選項為歌名/合作藝人 ,請以半形輸入法作答選項,大小寫需要一模一樣,範例:jju 選項: (jja)小酒窩/A-Sa蔡卓妍 (jjb)被風吹過的夏天/金莎 (jjc)友人說/張懷秋 (jjd)全面開戰/五月天阿信 (jje)小說/阿杜"
#captcha_text_div_text = "請問《龍的傳人2060》演唱會是以下哪位藝人的演出請以半形輸入法作答大小寫需要一模一樣範例B2A1.周杰倫 B2.林俊傑 C3.張學友 D4.王力宏"
#captcha_text_div_text = "王力宏何時發行第一張專輯?(請以半形輸入法作答,大小寫需要一模一樣,範例:B2 A1.1985 B2.2005 C3.2015 D4.1995"
#captcha_text_div_text = "朴寶劍三月以歌手出道的日期和單曲名為? Answer the singles name & the debut date. *以半形輸入,大小寫/符號須都相同。例:(E1) Please use the same format given in the options.ex:(E1) (A1)20/Bloomin'(B1)2/Blossom(C1)2/Bloomin'(D1)20/Blossom"
#captcha_text_div_text = "以下哪位不是LOVELYZ成員? (請以半形輸入選項內的英文及數字,大小寫須符合),範例:E5e。 (A1a)智愛 (B2b)美珠 (C3c)JON (D4d)叡仁"
#captcha_text_div_text = "題請問此次 RAVI的SOLO專輯名稱為?(請以半形輸入法作答,大小寫需要一模一樣,範例:Tt Aa [ BOOK] 、 Bb [OOK BOOK.R] 、 Cc [R.OOK BOOK] 、 Dd [OOK R. BOOK]"
#captcha_text_div_text = "請問下列哪個選項皆為河成雲的創作歌曲? Aa) Dont Forget、Candle Bb) Dont Forget、Forever+1 Cc) Dont Forget、Flowerbomb Dd) Dont Forget、One Love 請以半形輸入,大小寫含括號需一模一樣 【範例:答案為B需填入Bb)】"
captcha_text_div_text = "魏如萱得過什麼獎?(1) 金馬獎 最佳女主角(2) 金鐘獎 戲劇節目女主角(3) 金曲獎 最佳華語女歌手(4) 走鐘獎 好好聽音樂獎 (請輸入半形數字)"
inferred_answer_string, answer_list = get_answer_list_from_question_string(None, captcha_text_div_text)
print("inferred_answer_string:", inferred_answer_string)
print("answer_list:", answer_list)
ocr = ddddocr.DdddOcr(show_ad=False, beta=True)
image_file = 'captcha-xxxx.png'
if os.path.exists(image_file):
with open(image_file, 'rb') as f:
image_bytes = f.read()
res = ocr.classification(image_bytes)
print(res)