|
@@ -65,14 +65,12 @@ class TlsRegistrator:
|
|
|
|
|
|
|
|
# 3. 反爬及稳定性配置
|
|
# 3. 反爬及稳定性配置
|
|
|
co.headless(False)
|
|
co.headless(False)
|
|
|
- co.set_argument('--lang=en-US')
|
|
|
|
|
co.set_argument('--no-sandbox')
|
|
co.set_argument('--no-sandbox')
|
|
|
co.set_argument('--disable-gpu')
|
|
co.set_argument('--disable-gpu')
|
|
|
co.set_argument('--disable-dev-shm-usage')
|
|
co.set_argument('--disable-dev-shm-usage')
|
|
|
co.set_argument('--window-size=1920,1080')
|
|
co.set_argument('--window-size=1920,1080')
|
|
|
co.set_argument('--disable-blink-features=AutomationControlled')
|
|
co.set_argument('--disable-blink-features=AutomationControlled')
|
|
|
self.page = ChromiumPage(co)
|
|
self.page = ChromiumPage(co)
|
|
|
- self.page.run_cdp('Emulation.setLocaleOverride', locale='en-US')
|
|
|
|
|
self.page.get(self.tls_url)
|
|
self.page.get(self.tls_url)
|
|
|
cf_bypasser = CloudflareBypasser(self.page, log=True)
|
|
cf_bypasser = CloudflareBypasser(self.page, log=True)
|
|
|
cf_bypasser.bypass()
|
|
cf_bypasser.bypass()
|
|
@@ -143,43 +141,40 @@ class TlsRegistrator:
|
|
|
btn_selector = '#submit'
|
|
btn_selector = '#submit'
|
|
|
if not self.page.wait.ele_displayed(btn_selector, timeout=3):
|
|
if not self.page.wait.ele_displayed(btn_selector, timeout=3):
|
|
|
register_btn = self.page.ele("tag:a@@href:registration")
|
|
register_btn = self.page.ele("tag:a@@href:registration")
|
|
|
- self.mouse.move_to(register_btn)
|
|
|
|
|
- self.mouse.click(register_btn.rect.midpoint[0], register_btn.rect.midpoint[1], humanize=True)
|
|
|
|
|
|
|
+ self.mouse.human_click_ele(register_btn)
|
|
|
time.sleep(3)
|
|
time.sleep(3)
|
|
|
if not self.page.wait.ele_displayed(btn_selector, timeout=10):
|
|
if not self.page.wait.ele_displayed(btn_selector, timeout=10):
|
|
|
raise BizLogicError(message=f"Can't find selector={btn_selector}")
|
|
raise BizLogicError(message=f"Can't find selector={btn_selector}")
|
|
|
time.sleep(random.uniform(0.5, 1))
|
|
time.sleep(random.uniform(0.5, 1))
|
|
|
self._log("正在填写邮箱和密码...")
|
|
self._log("正在填写邮箱和密码...")
|
|
|
email_input_e = self.page.ele('#email')
|
|
email_input_e = self.page.ele('#email')
|
|
|
- self.mouse.click(int(email_input_e.rect.midpoint[0]), int(email_input_e.rect.midpoint[1]), humanize=True)
|
|
|
|
|
|
|
+ self.mouse.human_click_ele(email_input_e)
|
|
|
self.keyboard.type_text(email, humanize=True)
|
|
self.keyboard.type_text(email, humanize=True)
|
|
|
time.sleep(random.uniform(0.2, 0.5))
|
|
time.sleep(random.uniform(0.2, 0.5))
|
|
|
|
|
|
|
|
password_e = self.page.ele('#password')
|
|
password_e = self.page.ele('#password')
|
|
|
- self.mouse.click(int(password_e.rect.midpoint[0]), int(password_e.rect.midpoint[1]), humanize=True)
|
|
|
|
|
|
|
+ self.mouse.human_click_ele(password_e)
|
|
|
self.keyboard.type_text(password, humanize=True)
|
|
self.keyboard.type_text(password, humanize=True)
|
|
|
time.sleep(random.uniform(0.2, 0.5))
|
|
time.sleep(random.uniform(0.2, 0.5))
|
|
|
|
|
|
|
|
confirm_password_e = self.page.ele('#confirm-password')
|
|
confirm_password_e = self.page.ele('#confirm-password')
|
|
|
- self.mouse.click(int(confirm_password_e.rect.midpoint[0]), int(confirm_password_e.rect.midpoint[1]), humanize=True)
|
|
|
|
|
|
|
+ self.mouse.human_click_ele(confirm_password_e)
|
|
|
self.keyboard.type_text(password, humanize=True)
|
|
self.keyboard.type_text(password, humanize=True)
|
|
|
time.sleep(random.uniform(0.2, 0.5))
|
|
time.sleep(random.uniform(0.2, 0.5))
|
|
|
|
|
|
|
|
self._log("正在勾选必选条款...")
|
|
self._log("正在勾选必选条款...")
|
|
|
for checkbox_id in ['#terms-and-conditions', '#biometric-data', '#privacy-notice']:
|
|
for checkbox_id in ['#terms-and-conditions', '#biometric-data', '#privacy-notice']:
|
|
|
check_box_e = self.page.ele(checkbox_id).next()
|
|
check_box_e = self.page.ele(checkbox_id).next()
|
|
|
- mx, my = int(check_box_e.rect.midpoint[0]), int(check_box_e.rect.midpoint[1])
|
|
|
|
|
- self.mouse.click(mx, my, humanize=True)
|
|
|
|
|
|
|
+ self.mouse.human_click_ele(check_box_e)
|
|
|
time.sleep(random.uniform(0.3, 0.6))
|
|
time.sleep(random.uniform(0.3, 0.6))
|
|
|
|
|
|
|
|
self._log("提交注册...")
|
|
self._log("提交注册...")
|
|
|
btn_e = self.page.ele(btn_selector)
|
|
btn_e = self.page.ele(btn_selector)
|
|
|
-
|
|
|
|
|
btn_e.scroll.to_see(center=True)
|
|
btn_e.scroll.to_see(center=True)
|
|
|
- time.sleep(1)
|
|
|
|
|
-
|
|
|
|
|
|
|
+ time.sleep(random.uniform(0.3, 0.6))
|
|
|
|
|
+
|
|
|
btn_mx, btn_my = int(btn_e.rect.midpoint[0]), int(btn_e.rect.midpoint[1])
|
|
btn_mx, btn_my = int(btn_e.rect.midpoint[0]), int(btn_e.rect.midpoint[1])
|
|
|
- self.mouse.click(btn_mx, btn_my, humanize=True)
|
|
|
|
|
|
|
+ self.mouse.move(btn_mx, btn_my, humanize=True)
|
|
|
|
|
|
|
|
time.sleep(0.5)
|
|
time.sleep(0.5)
|
|
|
btn_e.click(by_js=True)
|
|
btn_e.click(by_js=True)
|
|
@@ -232,7 +227,7 @@ class TlsRegistrator:
|
|
|
if not date_str:
|
|
if not date_str:
|
|
|
return
|
|
return
|
|
|
ele = page.ele(selector)
|
|
ele = page.ele(selector)
|
|
|
- ele.scroll.to_see(center=True) # 滚动到屏幕中间
|
|
|
|
|
|
|
+ ele.scroll.to_see(center=True)
|
|
|
ele.click()
|
|
ele.click()
|
|
|
time.sleep(0.2)
|
|
time.sleep(0.2)
|
|
|
year, month, day = date_str.split('-')
|
|
year, month, day = date_str.split('-')
|
|
@@ -249,33 +244,40 @@ class TlsRegistrator:
|
|
|
btn_selector = '#btn-login'
|
|
btn_selector = '#btn-login'
|
|
|
if not self.page.wait.ele_displayed(btn_selector, timeout=3):
|
|
if not self.page.wait.ele_displayed(btn_selector, timeout=3):
|
|
|
login_btn = self.page.ele("tag:a@@href:login")
|
|
login_btn = self.page.ele("tag:a@@href:login")
|
|
|
- self.mouse.move_to(login_btn)
|
|
|
|
|
- self.mouse.click(login_btn.rect.midpoint[0], login_btn.rect.midpoint[1], humanize=True)
|
|
|
|
|
|
|
+ self.mouse.human_click_ele(login_btn)
|
|
|
time.sleep(3)
|
|
time.sleep(3)
|
|
|
if not self.page.wait.ele_displayed(btn_selector, timeout=10):
|
|
if not self.page.wait.ele_displayed(btn_selector, timeout=10):
|
|
|
raise BizLogicError(message=f"Can't find selector={btn_selector}")
|
|
raise BizLogicError(message=f"Can't find selector={btn_selector}")
|
|
|
- g_token = ""
|
|
|
|
|
|
|
+ recpatchav2_token = ""
|
|
|
if self.page.ele('.g-recaptcha') or self.page.ele('xpath://iframe[contains(@src, "recaptcha")]'):
|
|
if self.page.ele('.g-recaptcha') or self.page.ele('xpath://iframe[contains(@src, "recaptcha")]'):
|
|
|
self._log("Solving ReCaptcha...")
|
|
self._log("Solving ReCaptcha...")
|
|
|
- g_token = self.solve_captcha(self.page.url, "ReCaptchaV2TaskProxyLess", "6LcDpXcfAAAAAM7wOEsF_38DNsL20tTvPTKxpyn0")
|
|
|
|
|
|
|
+ recpatchav2_token = self.solve_captcha(self.page.url, "ReCaptchaV2TaskProxyLess", "6LcDpXcfAAAAAM7wOEsF_38DNsL20tTvPTKxpyn0")
|
|
|
|
|
|
|
|
- js_login = f"""
|
|
|
|
|
- var u = document.getElementById('email-input-field');
|
|
|
|
|
- if(u) {{ u.value = "{email}"; u.dispatchEvent(new Event('input', {{bubbles:true}})); }}
|
|
|
|
|
-
|
|
|
|
|
- var p = document.getElementById('password-input-field');
|
|
|
|
|
- if(p) {{ p.value = "{password}"; p.dispatchEvent(new Event('input', {{bubbles:true}})); }}
|
|
|
|
|
|
|
+ input_ele = self.page.ele('#email-input-field')
|
|
|
|
|
+ self.mouse.human_click_ele(input_ele)
|
|
|
|
|
+ time.sleep(random.uniform(0.2, 0.6))
|
|
|
|
|
+ self.keyboard.type_text(email, humanize=True)
|
|
|
|
|
|
|
|
- var g = document.getElementById('g-recaptcha-response');
|
|
|
|
|
- if(g) {{ g.value = "{g_token}"; }}
|
|
|
|
|
|
|
+ time.sleep(random.uniform(0.5, 1.2))
|
|
|
|
|
+
|
|
|
|
|
+ pwd_ele = self.page.ele('#password-input-field')
|
|
|
|
|
+ self.mouse.human_click_ele(pwd_ele)
|
|
|
|
|
+ time.sleep(random.uniform(0.2, 0.6))
|
|
|
|
|
+ self.keyboard.type_text(password, humanize=True)
|
|
|
|
|
|
|
|
- var btn = document.getElementById('btn-login');
|
|
|
|
|
- if(btn) {{ btn.click(); return true; }} else {{ return false; }}
|
|
|
|
|
- """
|
|
|
|
|
|
|
+ if recpatchav2_token:
|
|
|
|
|
+ inject_recpatchav2_token_js = f"""
|
|
|
|
|
+ var g = document.getElementById('g-recaptcha-response');
|
|
|
|
|
+ if(g) {{ g.value = "{recpatchav2_token}"; }}
|
|
|
|
|
+ """
|
|
|
|
|
+ self._log("Inject ReCaptchaV2 Token via JS...")
|
|
|
|
|
+ self.page.run_js(inject_recpatchav2_token_js)
|
|
|
|
|
+ time.sleep(random.uniform(0.5, 1.0))
|
|
|
|
|
|
|
|
- self._log("Submitting Login via JS...")
|
|
|
|
|
- if not self.page.run_js(js_login):
|
|
|
|
|
- raise BizLogicError(message="Login button missing")
|
|
|
|
|
|
|
+ self._log("Submitting Login...")
|
|
|
|
|
+ time.sleep(random.uniform(0.3, 0.8))
|
|
|
|
|
+ login_btn = self.page.ele('#btn-login')
|
|
|
|
|
+ self.mouse.human_click_ele(login_btn)
|
|
|
|
|
|
|
|
self._log("Waiting for dashboard redirect...")
|
|
self._log("Waiting for dashboard redirect...")
|
|
|
self.page.wait.url_change('login-actions', exclude=True, timeout=45)
|
|
self.page.wait.url_change('login-actions', exclude=True, timeout=45)
|
|
@@ -311,8 +313,8 @@ class TlsRegistrator:
|
|
|
formgroup_id = travel_group.get('formGroupId')
|
|
formgroup_id = travel_group.get('formGroupId')
|
|
|
self._log(f"Waiting for group button to render: {formgroup_id}")
|
|
self._log(f"Waiting for group button to render: {formgroup_id}")
|
|
|
btn_selector = f'tag:a@@data-testid=btn-select-group'
|
|
btn_selector = f'tag:a@@data-testid=btn-select-group'
|
|
|
- self._log(f"Select group_id={formgroup_id} via JS...")
|
|
|
|
|
- self.page.ele(btn_selector).click(by_js=True)
|
|
|
|
|
|
|
+ self._log(f"Select group_id={formgroup_id}...")
|
|
|
|
|
+ self.mouse.human_click_ele(self.page.ele(btn_selector))
|
|
|
|
|
|
|
|
self._log("Waiting for url redirect...")
|
|
self._log("Waiting for url redirect...")
|
|
|
self.page.wait.url_change('travel-groups', exclude=True, timeout=45)
|
|
self.page.wait.url_change('travel-groups', exclude=True, timeout=45)
|
|
@@ -326,7 +328,7 @@ class TlsRegistrator:
|
|
|
btn_selector = 'tag:button@@data-testid=btn-max-number-of-applicants'
|
|
btn_selector = 'tag:button@@data-testid=btn-max-number-of-applicants'
|
|
|
if not self.page.ele(btn_selector):
|
|
if not self.page.ele(btn_selector):
|
|
|
raise BizLogicError(message=f"Can't find selector={btn_selector}")
|
|
raise BizLogicError(message=f"Can't find selector={btn_selector}")
|
|
|
- self.page.ele(btn_selector).click()
|
|
|
|
|
|
|
+ self.mouse.human_click_ele(self.page.ele(btn_selector))
|
|
|
time.sleep(6)
|
|
time.sleep(6)
|
|
|
|
|
|
|
|
visa_type = self.account_detail.get("visa_type")
|
|
visa_type = self.account_detail.get("visa_type")
|
|
@@ -458,24 +460,24 @@ if __name__ == "__main__":
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
CAPSOLVER_KEY = "CAP-5441DD341DD3CC2FAEF0BE6FE493EE9A"
|
|
CAPSOLVER_KEY = "CAP-5441DD341DD3CC2FAEF0BE6FE493EE9A"
|
|
|
- TLS_URL = "https://visas-fr.tlscontact.com/visa/cn/cnCNG2fr/home"
|
|
|
|
|
|
|
+ TLS_URL = "https://visas-fr.tlscontact.com/en-us/country/cn/vac/cnCNG2fr"
|
|
|
ACCOUNT_DETAIL = {
|
|
ACCOUNT_DETAIL = {
|
|
|
- "email": "lisi103@gmail-app.com",
|
|
|
|
|
|
|
+ "email": "lisi105@gmail-app.com",
|
|
|
"pwd": "Visafly@111",
|
|
"pwd": "Visafly@111",
|
|
|
"location": "Chengdu",
|
|
"location": "Chengdu",
|
|
|
"visa_type": "Short stay (<90 days) - Tourism",
|
|
"visa_type": "Short stay (<90 days) - Tourism",
|
|
|
"travel_purpose": "Tourism / Private visit",
|
|
"travel_purpose": "Tourism / Private visit",
|
|
|
- "application_form_id": "FRA1CA20260420996",
|
|
|
|
|
|
|
+ "application_form_id": "FRA1CA20260421997",
|
|
|
"last_name": "Song",
|
|
"last_name": "Song",
|
|
|
- "first_name": "Xiao",
|
|
|
|
|
|
|
+ "first_name": "Xiaohui",
|
|
|
"gender": "Male",
|
|
"gender": "Male",
|
|
|
- "birthday": "1998-12-18",
|
|
|
|
|
|
|
+ "birthday": "1998-12-20",
|
|
|
"nationality": "China",
|
|
"nationality": "China",
|
|
|
"province_residence": "Sichuan",
|
|
"province_residence": "Sichuan",
|
|
|
"passport_type": "Ordinary passport",
|
|
"passport_type": "Ordinary passport",
|
|
|
- "passport_no": "EJ8628293",
|
|
|
|
|
|
|
+ "passport_no": "EJ8628394",
|
|
|
"phone_country_code": "86",
|
|
"phone_country_code": "86",
|
|
|
- "phone_number": "17386068917",
|
|
|
|
|
|
|
+ "phone_number": "17386068828",
|
|
|
"departure_origin_date": "2026-05-26",
|
|
"departure_origin_date": "2026-05-26",
|
|
|
"arrival_schengen_area_date": "2026-05-26",
|
|
"arrival_schengen_area_date": "2026-05-26",
|
|
|
"departure_schengen_area_date": "2026-05-28"
|
|
"departure_schengen_area_date": "2026-05-28"
|
|
@@ -484,10 +486,10 @@ if __name__ == "__main__":
|
|
|
try:
|
|
try:
|
|
|
bot = TlsRegistrator(TLS_URL, proxy_config=PROXY_CONFIG, capsolver_key=CAPSOLVER_KEY, account_detail=ACCOUNT_DETAIL)
|
|
bot = TlsRegistrator(TLS_URL, proxy_config=PROXY_CONFIG, capsolver_key=CAPSOLVER_KEY, account_detail=ACCOUNT_DETAIL)
|
|
|
bot.init_browser()
|
|
bot.init_browser()
|
|
|
- now_utc = datetime.utcnow()
|
|
|
|
|
- sent_at = now_utc.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
- bot.register()
|
|
|
|
|
- bot.activate(sent_at=sent_at)
|
|
|
|
|
|
|
+ # now_utc = datetime.utcnow()
|
|
|
|
|
+ # sent_at = now_utc.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
+ # bot.register()
|
|
|
|
|
+ # bot.activate(sent_at=sent_at)
|
|
|
bot.make_account_useful()
|
|
bot.make_account_useful()
|
|
|
except Exception as e:
|
|
except Exception as e:
|
|
|
print(f'Exception Info={e}')
|
|
print(f'Exception Info={e}')
|