From f6b33c603db0d09d01911d03f44c86c04c1a7018 Mon Sep 17 00:00:00 2001 From: Yong-Jer Chuang Date: Wed, 24 Apr 2024 09:57:01 +0800 Subject: [PATCH 1/6] Refactor code to follow pep8 --- NonBrowser.py | 65 ++++++++++++++++++++------------------------ chrome_tixcraft.py | 36 ++++++++++++------------ nodriver_tixcraft.py | 6 ++-- 3 files changed, 51 insertions(+), 56 deletions(-) diff --git a/NonBrowser.py b/NonBrowser.py index 6149e8f..5ddf811 100644 --- a/NonBrowser.py +++ b/NonBrowser.py @@ -1,49 +1,44 @@ import base64 -import json -from io import BytesIO - import requests +from io import BytesIO from PIL import Image +from typing import Optional +from requests.exceptions import RequestException +class NonBrowser: + def __init__(self, domain_name: str = "tixcraft.com") -> None: + self.session = requests.Session() + self.set_domain(domain_name) -class NonBrowser(): - def __init__(self, domain_name = "tixcraft.com") -> None: - self.Session = requests.session() - self.Set_Domain(domain_name) + def set_cookies(self, cookies: Optional[dict]) -> bool: + if cookies is not None: + [self.session.cookies.set(cookie["name"], cookie["value"]) for cookie in cookies] + return True + return False - def Set_cookies(self, cookies:dict): - ret = False - if not cookies is None: - for cookie in cookies: - self.Session.cookies.set(cookie["name"],cookie["value"]) - ret = True - return ret + def get_cookies(self) -> dict: + return self.session.cookies.get_dict() - def Get_cookies(self): - return self.Session.cookies.get_dict() + def set_headers(self, header: str) -> None: + self.session.headers = header - def set_headers(self, header:str): - self.Session.headers = header + def set_domain(self, domain_name: str, captcha_url: str = "ticket/captcha", refresh_url: str = "ticket/captcha?refresh=1") -> None: + self.url = f"https://{domain_name}/{captcha_url}" + self.refresh_url = f"https://{domain_name}/{refresh_url}" - def Set_Domain(self, domain_name, captcha_url="ticket/captcha", refresh_url="ticket/captcha?refresh=1"): - self.url = "https://%s/%s" % (domain_name, captcha_url) - self.refresh_url = "https://%s/%s" % (domain_name, refresh_url) - - def Request_Captcha(self): - img = Image.open(BytesIO(self.Session.get(self.url, stream = True).content)) + def request_captcha(self) -> bytes: + response = self.session.get(self.url, stream=True) + img = Image.open(BytesIO(response.content)) output_buffer = BytesIO() img.save(output_buffer, format='JPEG') binary_data = output_buffer.getvalue() - base64_data = base64.b64encode(binary_data) - return base64_data + return base64.b64encode(binary_data) - def Request_Refresh_Captcha(self) -> str: + def request_refresh_captcha(self) -> str: try: - result = self.Session.get(self.refresh_url, stream = True) - if result.status_code == 200: - json_data = json.loads(result.text) - return json_data.get("url","") - else: - return "" - except Exception as e: - return "" \ No newline at end of file + response = self.session.get(self.refresh_url, stream=True) + if response.status_code == 200: + return response.json().get("url", "") + except RequestException: + pass + return "" \ No newline at end of file diff --git a/chrome_tixcraft.py b/chrome_tixcraft.py index 65d204d..f81e85a 100644 --- a/chrome_tixcraft.py +++ b/chrome_tixcraft.py @@ -2039,7 +2039,7 @@ def tixcraft_get_ocr_answer(driver, ocr, ocr_captcha_image_source, Captcha_Brows 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()) + img_base64 = base64.b64decode(Captcha_Browser.request_captcha()) if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS: image_id = 'TicketForm_verifyCode-image' @@ -2073,7 +2073,7 @@ def tixcraft_get_ocr_answer(driver, ocr, ocr_captcha_image_source, Captcha_Brows if img_base64 is None: if not Captcha_Browser is None: print("canvas get image fail, use plan_b: NonBrowser") - img_base64 = base64.b64decode(Captcha_Browser.Request_Captcha()) + img_base64 = base64.b64decode(Captcha_Browser.request_captcha()) except Exception as exc: if show_debug_message: print("canvas exception:", str(exc)) @@ -2152,7 +2152,7 @@ def tixcraft_auto_ocr(driver, ocr, away_from_keyboard_enable, previous_answer, C else: # Non_Browser solution. if not Captcha_Browser is None: - new_captcha_url = Captcha_Browser.Request_Refresh_Captcha() #取得新的CAPTCHA + new_captcha_url = Captcha_Browser.request_refresh_captcha() #取得新的CAPTCHA if new_captcha_url != "": tixcraft_change_captcha(driver, new_captcha_url) #更改CAPTCHA圖 else: @@ -5730,10 +5730,10 @@ def set_non_browser_cookies(driver, url, Captcha_Browser): #PS: need set cookies once, if user change domain. if not Captcha_Browser is None: try: - Captcha_Browser.Set_cookies(driver.get_cookies()) + Captcha_Browser.set_cookies(driver.get_cookies()) except Exception as e: pass - Captcha_Browser.Set_Domain(domain_name) + Captcha_Browser.set_domain(domain_name) def ticketmaster_parse_zone_info(driver, config_dict): show_debug_message = True # debug. @@ -7007,7 +7007,7 @@ def ibon_auto_ocr(driver, config_dict, ocr, away_from_keyboard_enable, previous_ 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()) + img_base64 = base64.b64decode(Captcha_Browser.request_captcha()) if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS: image_id = 'chk_pic' image_element = None @@ -7072,7 +7072,7 @@ def ibon_auto_ocr(driver, config_dict, ocr, away_from_keyboard_enable, previous_ else: # Non_Browser solution. if not Captcha_Browser is None: - new_captcha_url = Captcha_Browser.Request_Refresh_Captcha() #取得新的CAPTCHA + new_captcha_url = Captcha_Browser.request_refresh_captcha() #取得新的CAPTCHA if new_captcha_url != "": #PS:[TODO] #tixcraft_change_captcha(driver, new_captcha_url) #更改CAPTCHA圖 @@ -7245,7 +7245,7 @@ def ibon_main(driver, url, config_dict, ocr, Captcha_Browser): 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) + Captcha_Browser.set_domain(domain_name, captcha_url=captcha_url) is_captcha_sent = ibon_captcha(driver, config_dict, ocr, Captcha_Browser, model_name) @@ -8984,7 +8984,7 @@ def kham_auto_ocr(driver, config_dict, ocr, away_from_keyboard_enable, previous_ 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()) + img_base64 = base64.b64decode(Captcha_Browser.request_captcha()) if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS: image_id = 'chk_pic' image_element = None @@ -9049,7 +9049,7 @@ def kham_auto_ocr(driver, config_dict, ocr, away_from_keyboard_enable, previous_ else: # Non_Browser solution. if not Captcha_Browser is None: - new_captcha_url = Captcha_Browser.Request_Refresh_Captcha() #取得新的CAPTCHA + new_captcha_url = Captcha_Browser.request_refresh_captcha() #取得新的CAPTCHA if new_captcha_url != "": #PS:[TODO] #tixcraft_change_captcha(driver, new_captcha_url) #更改CAPTCHA圖 @@ -9169,8 +9169,8 @@ def kham_main(driver, url, config_dict, ocr, Captcha_Browser): if config_dict["ocr_captcha"]["enable"]: if not Captcha_Browser is None: - Captcha_Browser.Set_cookies(driver.get_cookies()) - Captcha_Browser.Set_Domain(domain_name) + Captcha_Browser.set_cookies(driver.get_cookies()) + Captcha_Browser.set_domain(domain_name) break #https://kham.com.tw/application/UTK02/UTK0201_.aspx?PRODUCT_ID=XXX @@ -9264,7 +9264,7 @@ def kham_main(driver, url, config_dict, ocr, Captcha_Browser): 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) + Captcha_Browser.set_domain(domain_name, captcha_url=captcha_url) is_captcha_sent = False @@ -9332,7 +9332,7 @@ def kham_main(driver, url, config_dict, ocr, Captcha_Browser): 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) + Captcha_Browser.set_domain(domain_name, captcha_url=captcha_url) is_captcha_sent = False if config_dict["ocr_captcha"]["enable"]: @@ -9382,7 +9382,7 @@ def kham_main(driver, url, config_dict, ocr, Captcha_Browser): 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) + Captcha_Browser.set_domain(domain_name, captcha_url=captcha_url) kham_captcha(driver, config_dict, ocr, Captcha_Browser, model_name) @@ -10197,7 +10197,7 @@ def ticketplus_auto_ocr(driver, config_dict, ocr, previous_answer, Captcha_Brows 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()) + img_base64 = base64.b64decode(Captcha_Browser.request_captcha()) if ocr_captcha_image_source == CONST_OCR_CAPTCH_IMAGE_SOURCE_CANVAS: image_id = 'span.captcha-img' image_element = None @@ -10660,8 +10660,8 @@ def ticketplus_main(driver, url, config_dict, ocr, Captcha_Browser): 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) + Captcha_Browser.set_cookies(driver.get_cookies()) + Captcha_Browser.set_domain(domain_name) is_user_signin = ticketplus_account_auto_fill(driver, config_dict) if is_user_signin: diff --git a/nodriver_tixcraft.py b/nodriver_tixcraft.py index 6fb9d30..18e6991 100644 --- a/nodriver_tixcraft.py +++ b/nodriver_tixcraft.py @@ -1376,8 +1376,8 @@ async def nodriver_ticketplus_main(tab, url, config_dict, ocr, Captcha_Browser): domain_name = url.split('/')[2] if not Captcha_Browser is None: # TODO: - #Captcha_Browser.Set_cookies(driver.get_cookies()) - Captcha_Browser.Set_Domain(domain_name) + #Captcha_Browser.set_cookies(driver.get_cookies()) + Captcha_Browser.set_domain(domain_name) is_user_signin = await nodriver_ticketplus_account_auto_fill(tab, config_dict) @@ -1603,7 +1603,7 @@ async def nodriver_ibon_main(tab, url, config_dict, ocr, Captcha_Browser): 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) + Captcha_Browser.set_domain(domain_name, captcha_url=captcha_url) # TODO: #is_captcha_sent = ibon_captcha(driver, config_dict, ocr, Captcha_Browser, model_name) From 4adad6951b5fc9f6dd46bef6a363e2eb3990eaf8 Mon Sep 17 00:00:00 2001 From: Yong-Jer Chuang Date: Wed, 24 Apr 2024 10:58:03 +0800 Subject: [PATCH 2/6] Update pip-req.txt to requirement.txt in README.md --- README.md | 2 +- pip-req.txt => requirement.txt | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename pip-req.txt => requirement.txt (100%) diff --git a/README.md b/README.md index 9fd473b..1f92bad 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ https://max-everyday.com/2023/11/buy-ticket-by-vm/ ### Step 3: 安裝第三方套件: -python3 -m pip install -r pip-req.txt +python3 -m pip install -r requirement.txt ### Step 4: 執行設定介面主桯式: diff --git a/pip-req.txt b/requirement.txt similarity index 100% rename from pip-req.txt rename to requirement.txt From da4dfde82d8e2a1b4e4cd48e64e3930360f89bcb Mon Sep 17 00:00:00 2001 From: Yong-Jer Chuang Date: Wed, 24 Apr 2024 11:02:47 +0800 Subject: [PATCH 3/6] add dockerfile --- Dockerfile | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..b91865f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,4 @@ +From python:3.10 +RUN python3 -m pip install --upgrade pip +RUN pip install -r requirements.txt +CMD ["python3", "setting.py"] \ No newline at end of file From f19fa64645e20793e777e27c2a22e8c45b4fb2aa Mon Sep 17 00:00:00 2001 From: Yong-Jer Chuang Date: Wed, 24 Apr 2024 11:06:09 +0800 Subject: [PATCH 4/6] Update Dockerfile to use Python 3.10-slim-buster and install Node.js --- Dockerfile | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b91865f..bdbb8c4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,33 @@ -From python:3.10 +# 使用具有 Node.js 的官方 Python 基礎映像 +FROM python:3.10-slim-buster + +# 安裝 Node.js +RUN apt-get update && apt-get install -y nodejs npm + +# 升級 pip RUN python3 -m pip install --upgrade pip + +# 安裝 Python 和 Node.js 套件 +COPY requirements.txt ./ +COPY package.json ./ RUN pip install -r requirements.txt +RUN npm install + +# 安裝 Chrome 瀏覽器和 ChromeDriver 以供 Selenium 使用 +RUN apt-get update && apt-get install -y wget gnupg2 unzip +RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb +RUN dpkg -i google-chrome-stable_current_amd64.deb; apt-get -fy install +RUN wget https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.zip +RUN unzip chromedriver_linux64.zip +RUN mv chromedriver /usr/bin/chromedriver +RUN chown root:root /usr/bin/chromedriver +RUN chmod +x /usr/bin/chromedriver + +# 設定工作目錄 +WORKDIR /app + +# 複製應用程式程式碼到 Docker 容器 +COPY . . + +# 預設命令 CMD ["python3", "setting.py"] \ No newline at end of file From 9de59ae498ee8d6ad30c873ecb83230e463b0806 Mon Sep 17 00:00:00 2001 From: Yong-Jer Chuang Date: Wed, 24 Apr 2024 11:18:23 +0800 Subject: [PATCH 5/6] Refactor Dockerfile to use Python 3.10-slim-buster and install Node.js --- Dockerfile | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index bdbb8c4..0000000 --- a/Dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -# 使用具有 Node.js 的官方 Python 基礎映像 -FROM python:3.10-slim-buster - -# 安裝 Node.js -RUN apt-get update && apt-get install -y nodejs npm - -# 升級 pip -RUN python3 -m pip install --upgrade pip - -# 安裝 Python 和 Node.js 套件 -COPY requirements.txt ./ -COPY package.json ./ -RUN pip install -r requirements.txt -RUN npm install - -# 安裝 Chrome 瀏覽器和 ChromeDriver 以供 Selenium 使用 -RUN apt-get update && apt-get install -y wget gnupg2 unzip -RUN wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -RUN dpkg -i google-chrome-stable_current_amd64.deb; apt-get -fy install -RUN wget https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.zip -RUN unzip chromedriver_linux64.zip -RUN mv chromedriver /usr/bin/chromedriver -RUN chown root:root /usr/bin/chromedriver -RUN chmod +x /usr/bin/chromedriver - -# 設定工作目錄 -WORKDIR /app - -# 複製應用程式程式碼到 Docker 容器 -COPY . . - -# 預設命令 -CMD ["python3", "setting.py"] \ No newline at end of file From f078895d3de3a51b9c49db2c18263ee8cc21df68 Mon Sep 17 00:00:00 2001 From: Yong-Jer Chuang Date: Wed, 24 Apr 2024 13:14:07 +0800 Subject: [PATCH 6/6] Refactor get_config_dict function to simplify argument handling in nodriver_tixcraft.py --- nodriver_tixcraft.py | 74 +++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 46 deletions(-) diff --git a/nodriver_tixcraft.py b/nodriver_tixcraft.py index 18e6991..8824474 100644 --- a/nodriver_tixcraft.py +++ b/nodriver_tixcraft.py @@ -111,9 +111,8 @@ def get_config_dict(args): config_filepath = os.path.join(app_root, CONST_MAXBOT_CONFIG_FILE) # allow assign config by command line. - if not args.input is None: - if len(args.input) > 0: - config_filepath = args.input + if args.input and len(args.input) > 0: + config_filepath = args.input config_dict = None if os.path.isfile(config_filepath): @@ -121,48 +120,33 @@ def get_config_dict(args): with open(config_filepath) as json_data: config_dict = json.load(json_data) - if not args.headless is None: - config_dict["advanced"]["headless"] = util.t_or_f(args.headless) + # Define a dictionary to map argument names to their paths in the config_dict + arg_to_path = { + "headless": ["advanced", "headless"], + "homepage": ["homepage"], + "ticket_number": ["ticket_number"], + "browser": ["browser"], + "tixcraft_sid": ["advanced", "tixcraft_sid"], + "ibonqware": ["advanced", "ibonqware"], + "kktix_account": ["advanced", "kktix_account"], + "kktix_password": ["advanced", "kktix_password_plaintext"], + "proxy_server": ["advanced", "proxy_server_port"], + "window_size": ["advanced", "window_size"] + } - if not args.homepage is None: - if len(args.homepage) > 0: - config_dict["homepage"] = args.homepage - - if not args.ticket_number is None: - if args.ticket_number > 0: - config_dict["ticket_number"] = args.ticket_number - - if not args.browser is None: - if len(args.browser) > 0: - config_dict["browser"] = args.browser - - if not args.tixcraft_sid is None: - if len(args.tixcraft_sid) > 0: - config_dict["advanced"]["tixcraft_sid"] = args.tixcraft_sid - if not args.ibonqware is None: - if len(args.ibonqware) > 0: - config_dict["advanced"]["ibonqware"] = args.ibonqware - - if not args.kktix_account is None: - if len(args.kktix_account) > 0: - config_dict["advanced"]["kktix_account"] = args.kktix_account - if not args.kktix_password is None: - if len(args.kktix_password) > 0: - config_dict["advanced"]["kktix_password_plaintext"] = args.kktix_password - - if not args.proxy_server is None: - if len(args.proxy_server) > 2: - config_dict["advanced"]["proxy_server_port"] = args.proxy_server - - if not args.window_size is None: - if len(args.window_size) > 2: - config_dict["advanced"]["window_size"] = args.window_size + # Update the config_dict based on the arguments + for arg, path in arg_to_path.items(): + value = getattr(args, arg) + if value and len(str(value)) > 0: + d = config_dict + for key in path[:-1]: + d = d[key] + d[path[-1]] = value # special case for headless to enable away from keyboard mode. is_headless_enable_ocr = False if config_dict["advanced"]["headless"]: # for tixcraft headless. - #print("If you are runnig headless mode on tixcraft, you need input your cookie SID.") if len(config_dict["advanced"]["tixcraft_sid"]) > 1: is_headless_enable_ocr = True @@ -207,20 +191,18 @@ async def nodriver_press_button(tab, select_query): print(e) pass -async def nodriver_check_checkbox(tab, select_query, value='true'): - is_checkbox_checked = False +from typing import Optional + +async def nodriver_check_checkbox(tab: Optional[object], select_query: str, value: str = 'true') -> bool: if tab: try: element = await tab.query_selector(select_query) if element: - #await element.apply('function (element) { element.checked='+ value +'; } ') await element.click() - is_checkbox_checked = True + return True except Exception as exc: - #print("check checkbox fail for selector:", select_query) print(exc) - pass - return is_checkbox_checked + return False async def nodriver_facebook_login(tab, facebook_account, facebook_password): if tab: