|
@@ -1,4 +1,3 @@
|
|
|
-import requests
|
|
|
import time
|
|
|
import tkinter as tk
|
|
|
from tkinter import ttk, filedialog, messagebox
|
|
@@ -21,6 +20,7 @@ from multiprocessing import Process
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
+
|
|
|
|
|
|
class TextHandler(logging.Handler):
|
|
|
def __init__(self, text_widget, adjust_height_callback):
|
|
@@ -34,6 +34,7 @@ class TextHandler(logging.Handler):
|
|
|
self.text_widget.see(tk.END)
|
|
|
self.adjust_height_callback()
|
|
|
|
|
|
+
|
|
|
|
|
|
class AdsDataGUI:
|
|
|
def __init__(self, root):
|
|
@@ -50,13 +51,13 @@ class AdsDataGUI:
|
|
|
|
|
|
|
|
|
self.params = {
|
|
|
- "WINDOW_ID": tk.StringVar(value=self.config.get("WINDOW_ID", "947c8036facb4e8a935296e57f36652b")),
|
|
|
+ "WINDOW_ID": tk.StringVar(value=self.config.get("WINDOW_ID", "5c2216ed3b3e4bf0bc144b5ad0c87a5b")),
|
|
|
"BASE_URL": tk.StringVar(value=self.config.get("BASE_URL", "http://127.0.0.1:54345")),
|
|
|
"API_KEY": tk.StringVar(value=self.config.get("API_KEY", "704daf420f7244d08be51f61c987a232")),
|
|
|
"FILE_PATH": tk.StringVar(value=self.config.get("FILE_PATH", "generated_data.txt")),
|
|
|
"AMOUNT": tk.StringVar(value=self.config.get("AMOUNT", "$501-$1,000")),
|
|
|
"SLEEP_TIME_1": tk.DoubleVar(value=self.config.get("SLEEP_TIME_1", 10.0)),
|
|
|
- "SLEEP_TIME_2": tk.DoubleVar(value=self.config.get("SLEEP_TIME_2", 3.0)),
|
|
|
+ "SLEEP_TIME_2": tk.DoubleVar(value=self.config.get("SLEEP_TIME_2", 3.0)),
|
|
|
"SLEEP_TIME_3": tk.DoubleVar(value=self.config.get("SLEEP_TIME_3", 10.0)),
|
|
|
"NO_SANDBOX": tk.BooleanVar(value=self.config.get("NO_SANDBOX", True)),
|
|
|
"DISABLE_DEV_SHM": tk.BooleanVar(value=self.config.get("DISABLE_DEV_SHM", True)),
|
|
@@ -85,7 +86,8 @@ class AdsDataGUI:
|
|
|
|
|
|
|
|
|
row = 0
|
|
|
- tk.Label(self.scrollable_frame, text="自动化注册 - BitBrowser", font=("Arial", 16)).grid(row=row, column=0, columnspan=3, pady=10)
|
|
|
+ tk.Label(self.scrollable_frame, text="自动化注册 - BitBrowser", font=("Arial", 16)).grid(row=row, column=0,
|
|
|
+ columnspan=3, pady=10)
|
|
|
row += 1
|
|
|
|
|
|
|
|
@@ -103,19 +105,26 @@ class AdsDataGUI:
|
|
|
for label_text, var in labels:
|
|
|
tk.Label(self.scrollable_frame, text=label_text).grid(row=row, column=0, sticky="e", padx=5, pady=5)
|
|
|
if label_text == "金额范围:":
|
|
|
- amount_options = ["$0-$500", "$501-$1,000", "$1,001-$5,000", "超过 $5,000"]
|
|
|
- ttk.Combobox(self.scrollable_frame, textvariable=var, values=amount_options, state="readonly").grid(row=row, column=1, padx=5, pady=5, sticky="ew")
|
|
|
+ amount_options = ["$1-$500", "$501-$1,000", "$1,001-$5,000", "超过 $5,000"]
|
|
|
+ ttk.Combobox(self.scrollable_frame, textvariable=var, values=amount_options, state="readonly").grid(
|
|
|
+ row=row, column=1, padx=5, pady=5, sticky="ew")
|
|
|
else:
|
|
|
tk.Entry(self.scrollable_frame, textvariable=var).grid(row=row, column=1, padx=5, pady=5, sticky="ew")
|
|
|
if label_text == "文件路径:":
|
|
|
- tk.Button(self.scrollable_frame, text="浏览", command=self.browse_file).grid(row=row, column=2, padx=5, pady=5)
|
|
|
+ tk.Button(self.scrollable_frame, text="浏览", command=self.browse_file).grid(row=row, column=2, padx=5,
|
|
|
+ pady=5)
|
|
|
row += 1
|
|
|
|
|
|
- tk.Checkbutton(self.scrollable_frame, text="无沙盒模式", variable=self.params["NO_SANDBOX"]).grid(row=row, column=0, columnspan=3, pady=5)
|
|
|
+ tk.Checkbutton(self.scrollable_frame, text="无沙盒模式", variable=self.params["NO_SANDBOX"]).grid(row=row,
|
|
|
+ column=0,
|
|
|
+ columnspan=3,
|
|
|
+ pady=5)
|
|
|
row += 1
|
|
|
- tk.Checkbutton(self.scrollable_frame, text="禁用 Dev SHM", variable=self.params["DISABLE_DEV_SHM"]).grid(row=row, column=0, columnspan=3, pady=5)
|
|
|
+ tk.Checkbutton(self.scrollable_frame, text="禁用 Dev SHM", variable=self.params["DISABLE_DEV_SHM"]).grid(
|
|
|
+ row=row, column=0, columnspan=3, pady=5)
|
|
|
row += 1
|
|
|
- tk.Checkbutton(self.scrollable_frame, text="启动时最大化", variable=self.params["START_MAXIMIZED"]).grid(row=row, column=0, columnspan=3, pady=5)
|
|
|
+ tk.Checkbutton(self.scrollable_frame, text="启动时最大化", variable=self.params["START_MAXIMIZED"]).grid(
|
|
|
+ row=row, column=0, columnspan=3, pady=5)
|
|
|
row += 1
|
|
|
|
|
|
self.status_label = tk.Label(self.scrollable_frame, text="状态: 就绪", fg="blue")
|
|
@@ -262,7 +271,7 @@ class AdsDataGUI:
|
|
|
logger.info("用户停止了脚本")
|
|
|
break
|
|
|
try:
|
|
|
- start_Ads_data(
|
|
|
+ result = start_Ads_data(
|
|
|
self,
|
|
|
data,
|
|
|
window_id=self.params["WINDOW_ID"].get(),
|
|
@@ -278,7 +287,14 @@ class AdsDataGUI:
|
|
|
},
|
|
|
amount=self.params["AMOUNT"].get()
|
|
|
)
|
|
|
- break
|
|
|
+ if result:
|
|
|
+ logger.info("操作成功!")
|
|
|
+ break
|
|
|
+ else:
|
|
|
+
|
|
|
+ logger.warning(f"尝试 {attempt + 1} 失败(业务逻辑错误),等待 10 秒后重试...")
|
|
|
+ time.sleep(10)
|
|
|
+
|
|
|
except Exception as e:
|
|
|
if not self.running:
|
|
|
logger.info("用户停止了脚本")
|
|
@@ -298,52 +314,54 @@ class AdsDataGUI:
|
|
|
self.running = False
|
|
|
self.current_web = None
|
|
|
|
|
|
+
|
|
|
def start_Ads_data(gui, data, window_id, sleep_times, chrome_options, amount):
|
|
|
+
|
|
|
|
|
|
res = openBrowser(window_id)
|
|
|
-
|
|
|
+
|
|
|
|
|
|
logger.info(f"openBrowser Response: {res}")
|
|
|
-
|
|
|
+
|
|
|
|
|
|
if 'data' not in res:
|
|
|
logger.error("BitBrowser API 返回中没有 'data' 键")
|
|
|
raise Exception("BitBrowser API 返回中没有 'data' 键")
|
|
|
-
|
|
|
+
|
|
|
driverPath = res['data']['driver']
|
|
|
debuggerAddress = res['data']['http']
|
|
|
-
|
|
|
+
|
|
|
if res["success"] is True:
|
|
|
logger.info("启动成功,返回信息")
|
|
|
else:
|
|
|
logger.error("启动失败")
|
|
|
raise Exception("启动失败")
|
|
|
-
|
|
|
+
|
|
|
chrome_opts = webdriver.ChromeOptions()
|
|
|
chrome_opts.add_experimental_option("debuggerAddress", debuggerAddress)
|
|
|
-
|
|
|
+
|
|
|
if chrome_options["no_sandbox"]:
|
|
|
chrome_opts.add_argument('--no-sandbox')
|
|
|
if chrome_options["disable_dev_shm"]:
|
|
|
chrome_opts.add_argument('--disable-dev-shm-usage')
|
|
|
if chrome_options["start_maximized"]:
|
|
|
chrome_opts.add_argument('--start-maximized')
|
|
|
-
|
|
|
+
|
|
|
chrome_service = Service(driverPath)
|
|
|
web = webdriver.Chrome(service=chrome_service, options=chrome_opts)
|
|
|
web.implicitly_wait(30)
|
|
|
-
|
|
|
+
|
|
|
|
|
|
gui.current_web = web
|
|
|
-
|
|
|
+
|
|
|
web.get("https://claimform.savingsclubsettlement.com/consumerb-claimants")
|
|
|
-
|
|
|
+
|
|
|
original_window = web.current_window_handle
|
|
|
logger.info(f"当前页面标题: {web.title}")
|
|
|
-
|
|
|
+
|
|
|
time.sleep(sleep_times["sleep1"])
|
|
|
logger.info("等待验证码识别")
|
|
|
-
|
|
|
+
|
|
|
try:
|
|
|
iframe = WebDriverWait(web, 10).until(
|
|
|
EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe[src*='google.com/recaptcha']"))
|
|
@@ -351,7 +369,7 @@ def start_Ads_data(gui, data, window_id, sleep_times, chrome_options, amount):
|
|
|
except TimeoutException:
|
|
|
logger.error("未找到reCAPTCHA iframe")
|
|
|
raise Exception("未找到reCAPTCHA iframe")
|
|
|
-
|
|
|
+
|
|
|
while True:
|
|
|
try:
|
|
|
WebDriverWait(web, 10).until(
|
|
@@ -363,37 +381,64 @@ def start_Ads_data(gui, data, window_id, sleep_times, chrome_options, amount):
|
|
|
logger.warning("验证未完成或失败")
|
|
|
finally:
|
|
|
web.switch_to.default_content()
|
|
|
-
|
|
|
+
|
|
|
web.switch_to.default_content()
|
|
|
web.find_element(By.XPATH, "//input[@type='text']").send_keys(data[1])
|
|
|
web.find_element(By.ID, "street1").send_keys(data[2])
|
|
|
web.find_element(By.ID, "city").send_keys(data[3])
|
|
|
time.sleep(1)
|
|
|
- Select(web.find_element(By.XPATH, "(.//*[normalize-space(text()) and normalize-space(.)='*'])[5]/preceding::select[1]")).select_by_index(abbreviation_to_index[data[4]])
|
|
|
+ Select(web.find_element(By.XPATH,
|
|
|
+ "(.//*[normalize-space(text()) and normalize-space(.)='*'])[5]/preceding::select[1]")).select_by_index(
|
|
|
+ abbreviation_to_index[data[4]])
|
|
|
web.find_element(By.ID, "zip").send_keys(data[5])
|
|
|
time.sleep(1)
|
|
|
web.find_element(By.ID, "email").send_keys(data[0])
|
|
|
web.find_element(By.XPATH, "//input[@type='checkbox']").click()
|
|
|
+
|
|
|
web.find_element(By.XPATH, f"//input[@value='{amount}']").click()
|
|
|
web.find_element(By.ID, "signature").send_keys(data[1])
|
|
|
-
|
|
|
+
|
|
|
submit_button = WebDriverWait(web, 10).until(EC.element_to_be_clickable((By.XPATH, "//button[@type='submit']")))
|
|
|
submit_button.click()
|
|
|
+
|
|
|
+ result = check_submission_success(data, web)
|
|
|
+
|
|
|
time.sleep(sleep_times["sleep2"])
|
|
|
web.delete_all_cookies()
|
|
|
web.execute_script("window.localStorage.clear();")
|
|
|
web.execute_script("window.sessionStorage.clear();")
|
|
|
web.quit()
|
|
|
time.sleep(sleep_times["sleep3"])
|
|
|
-
|
|
|
+
|
|
|
|
|
|
closeBrowser(window_id)
|
|
|
-
|
|
|
+
|
|
|
|
|
|
logger.info("等待窗口完全关闭...")
|
|
|
time.sleep(sleep_times["sleep3"])
|
|
|
-
|
|
|
- logger.info("完成一次")
|
|
|
+
|
|
|
+ logger.info("完成一次填表循环")
|
|
|
+
|
|
|
+ return result
|
|
|
+
|
|
|
+
|
|
|
+def check_submission_success(data, web):
|
|
|
+ try:
|
|
|
+
|
|
|
+ WebDriverWait(web, 15).until(
|
|
|
+ EC.visibility_of_element_located((By.XPATH, "//h2[contains(., 'THANK YOU FOR SUBMITTING')]"))
|
|
|
+ )
|
|
|
+
|
|
|
+ ref_number = web.find_element(By.XPATH, "//p[contains(., 'Your Reference Number is')]/b").text
|
|
|
+ submission_date = web.find_element(By.XPATH, "//p[contains(., 'submitted on')]/b").text
|
|
|
+
|
|
|
+ logger.info(", ".join(data) + "提交成功" + ref_number)
|
|
|
+ return True
|
|
|
+
|
|
|
+ except Exception as e:
|
|
|
+ print(", ".join(data)+"")
|
|
|
+ return False
|
|
|
+
|
|
|
|
|
|
def read_txt_file(file_path):
|
|
|
data = []
|
|
@@ -416,7 +461,8 @@ def read_txt_file(file_path):
|
|
|
return None
|
|
|
return data
|
|
|
|
|
|
+
|
|
|
if __name__ == '__main__':
|
|
|
root = tk.Tk()
|
|
|
app = AdsDataGUI(root)
|
|
|
- root.mainloop()
|
|
|
+ root.mainloop()
|