|
@@ -217,9 +217,7 @@ class TlsRegistrator:
|
|
|
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"Wait ele={btn_selector} timeout")
|
|
raise BizLogicError(message=f"Wait ele={btn_selector} timeout")
|
|
|
self.page.ele(btn_selector).click()
|
|
self.page.ele(btn_selector).click()
|
|
|
- btn_selector = '#btn-login'
|
|
|
|
|
- if not self.page.wait.ele_displayed(btn_selector, timeout=10):
|
|
|
|
|
- raise BizLogicError(message=f"Wait ele={btn_selector} timeout")
|
|
|
|
|
|
|
+ time.sleep(3)
|
|
|
|
|
|
|
|
def make_account_useful(self):
|
|
def make_account_useful(self):
|
|
|
|
|
|
|
@@ -241,42 +239,42 @@ class TlsRegistrator:
|
|
|
email = self.account_detail.get('email')
|
|
email = self.account_detail.get('email')
|
|
|
password = self.account_detail.get('pwd')
|
|
password = self.account_detail.get('pwd')
|
|
|
location = self.account_detail.get('location')
|
|
location = self.account_detail.get('location')
|
|
|
- btn_selector = '#btn-login'
|
|
|
|
|
|
|
+ btn_selector = 'tag:button@@text():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.human_click_ele(login_btn)
|
|
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}")
|
|
|
- recpatchav2_token = ""
|
|
|
|
|
- if self.page.ele('.g-recaptcha') or self.page.ele('xpath://iframe[contains(@src, "recaptcha")]'):
|
|
|
|
|
- self._log("Solving ReCaptcha...")
|
|
|
|
|
- recpatchav2_token = self.solve_captcha(self.page.url, "ReCaptchaV2TaskProxyLess", "6LcDpXcfAAAAAM7wOEsF_38DNsL20tTvPTKxpyn0")
|
|
|
|
|
|
|
+ # recpatchav2_token = ""
|
|
|
|
|
+ # if self.page.ele('.g-recaptcha') or self.page.ele('xpath://iframe[contains(@src, "recaptcha")]'):
|
|
|
|
|
+ # self._log("Solving ReCaptcha...")
|
|
|
|
|
+ # recpatchav2_token = self.solve_captcha(self.page.url, "ReCaptchaV2TaskProxyLess", "6LcDpXcfAAAAAM7wOEsF_38DNsL20tTvPTKxpyn0")
|
|
|
|
|
|
|
|
- input_ele = self.page.ele('#email-input-field')
|
|
|
|
|
|
|
+ input_ele = self.page.ele('tag:label@@text():Email').next()
|
|
|
self.mouse.human_click_ele(input_ele)
|
|
self.mouse.human_click_ele(input_ele)
|
|
|
time.sleep(random.uniform(0.2, 0.6))
|
|
time.sleep(random.uniform(0.2, 0.6))
|
|
|
self.keyboard.type_text(email, humanize=True)
|
|
self.keyboard.type_text(email, humanize=True)
|
|
|
|
|
|
|
|
time.sleep(random.uniform(0.5, 1.2))
|
|
time.sleep(random.uniform(0.5, 1.2))
|
|
|
|
|
|
|
|
- pwd_ele = self.page.ele('#password-input-field')
|
|
|
|
|
- self.mouse.human_click_ele(pwd_ele)
|
|
|
|
|
|
|
+ input_ele = self.page.ele('tag:label@@text():Password').next()
|
|
|
|
|
+ self.mouse.human_click_ele(input_ele)
|
|
|
time.sleep(random.uniform(0.2, 0.6))
|
|
time.sleep(random.uniform(0.2, 0.6))
|
|
|
self.keyboard.type_text(password, humanize=True)
|
|
self.keyboard.type_text(password, humanize=True)
|
|
|
|
|
|
|
|
- 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))
|
|
|
|
|
|
|
+ # 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...")
|
|
self._log("Submitting Login...")
|
|
|
time.sleep(random.uniform(0.3, 0.8))
|
|
time.sleep(random.uniform(0.3, 0.8))
|
|
|
- login_btn = self.page.ele('#btn-login')
|
|
|
|
|
|
|
+ login_btn = self.page.ele('tag:button@@text():Login')
|
|
|
self.mouse.human_click_ele(login_btn)
|
|
self.mouse.human_click_ele(login_btn)
|
|
|
|
|
|
|
|
self._log("Waiting for dashboard redirect...")
|
|
self._log("Waiting for dashboard redirect...")
|
|
@@ -291,44 +289,47 @@ class TlsRegistrator:
|
|
|
time.sleep(5)
|
|
time.sleep(5)
|
|
|
|
|
|
|
|
# 解析 Dashboard 提取 Group ID
|
|
# 解析 Dashboard 提取 Group ID
|
|
|
- self._log("Parsing Dashboard for Travel Group...")
|
|
|
|
|
- html = self.page.html
|
|
|
|
|
- js_pattern = r'\\"travelGroups\\":\s*(\[.*?\]),\\"availableCountriesToCreateGroups'
|
|
|
|
|
- js_match = re.search(js_pattern, html, re.DOTALL)
|
|
|
|
|
|
|
+ # self._log("Parsing Dashboard for Travel Group...")
|
|
|
|
|
+ # html = self.page.html
|
|
|
|
|
+ # js_pattern = r'\\"travelGroups\\":\s*(\[.*?\]),\\"availableCountriesToCreateGroups'
|
|
|
|
|
+ # js_match = re.search(js_pattern, html, re.DOTALL)
|
|
|
|
|
|
|
|
- groups = []
|
|
|
|
|
- if js_match:
|
|
|
|
|
- json_str = js_match.group(1).replace(r'\"', '"')
|
|
|
|
|
- groups = json.loads(json_str)
|
|
|
|
|
|
|
+ # groups = []
|
|
|
|
|
+ # if js_match:
|
|
|
|
|
+ # json_str = js_match.group(1).replace(r'\"', '"')
|
|
|
|
|
+ # groups = json.loads(json_str)
|
|
|
|
|
|
|
|
- travel_group = None
|
|
|
|
|
- for g in groups:
|
|
|
|
|
- if g.get('vacName', '').lower() == location.lower():
|
|
|
|
|
- travel_group = g
|
|
|
|
|
- break
|
|
|
|
|
|
|
+ # travel_group = None
|
|
|
|
|
+ # for g in groups:
|
|
|
|
|
+ # if g.get('vacName', '').lower() == location.lower():
|
|
|
|
|
+ # travel_group = g
|
|
|
|
|
+ # break
|
|
|
|
|
|
|
|
- if not travel_group:
|
|
|
|
|
- raise BizLogicError(message=f"Travel Group not found for {location}")
|
|
|
|
|
|
|
+ # if not travel_group:
|
|
|
|
|
+ # raise BizLogicError(message=f"Travel Group not found for {location}")
|
|
|
|
|
|
|
|
- formgroup_id = travel_group.get('formGroupId')
|
|
|
|
|
- self._log(f"Waiting for group button to render: {formgroup_id}")
|
|
|
|
|
- btn_selector = f'tag:a@@data-testid=btn-select-group'
|
|
|
|
|
- self._log(f"Select group_id={formgroup_id}...")
|
|
|
|
|
- self.mouse.human_click_ele(self.page.ele(btn_selector))
|
|
|
|
|
|
|
+ # formgroup_id = travel_group.get('formGroupId')
|
|
|
|
|
+ # self._log(f"Waiting for group button to render: {formgroup_id}")
|
|
|
|
|
+ # btn_selector = f'tag:a@@data-testid=btn-select-group'
|
|
|
|
|
+ # 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.page.wait.url_change('travel-groups', exclude=True, timeout=45)
|
|
|
|
|
- time.sleep(2)
|
|
|
|
|
|
|
+ # self._log("Waiting for url redirect...")
|
|
|
|
|
+ # self.page.wait.url_change('travel-groups', exclude=True, timeout=45)
|
|
|
|
|
+ # time.sleep(2)
|
|
|
|
|
|
|
|
- if "travel-groups" in self.page.url or "auth" in self.page.url:
|
|
|
|
|
- raise BizLogicError(message="Redirect to service-level Failed!")
|
|
|
|
|
|
|
+ # if "travel-groups" in self.page.url or "auth" in self.page.url:
|
|
|
|
|
+ # raise BizLogicError(message="Redirect to service-level Failed!")
|
|
|
|
|
|
|
|
btn_selector = 'tag:button@@data-testid=btn-add-applicant'
|
|
btn_selector = 'tag:button@@data-testid=btn-add-applicant'
|
|
|
if not self.page.wait.ele_displayed(btn_selector, timeout=10):
|
|
if not self.page.wait.ele_displayed(btn_selector, timeout=10):
|
|
|
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.mouse.human_click_ele(self.page.ele(btn_selector))
|
|
|
|
|
|
|
+ add_btn = self.page.ele(btn_selector)
|
|
|
|
|
+ add_btn.scroll.to_see(center=True)
|
|
|
|
|
+ time.sleep(random.uniform(0.6, 0.8))
|
|
|
|
|
+ add_btn.click()
|
|
|
time.sleep(6)
|
|
time.sleep(6)
|
|
|
|
|
|
|
|
visa_type = self.account_detail.get("visa_type")
|
|
visa_type = self.account_detail.get("visa_type")
|
|
@@ -388,13 +389,16 @@ class TlsRegistrator:
|
|
|
|
|
|
|
|
province_residence = self.account_detail.get('province_residence')
|
|
province_residence = self.account_detail.get('province_residence')
|
|
|
if province_residence:
|
|
if province_residence:
|
|
|
- province_residence = province_residence.title()
|
|
|
|
|
- btn = self.page.ele('tag:label@@for=f_pers_province').next()
|
|
|
|
|
- btn.scroll.to_see(center=True)
|
|
|
|
|
- btn.click()
|
|
|
|
|
- time.sleep(0.5)
|
|
|
|
|
- self.page.ele(f'tag:li@@role=option@@text():{province_residence}').click(by_js=True)
|
|
|
|
|
- time.sleep(0.5)
|
|
|
|
|
|
|
+ try:
|
|
|
|
|
+ province_residence = province_residence.title()
|
|
|
|
|
+ btn = self.page.ele('tag:label@@for=f_pers_province').next()
|
|
|
|
|
+ btn.scroll.to_see(center=True)
|
|
|
|
|
+ btn.click()
|
|
|
|
|
+ time.sleep(0.5)
|
|
|
|
|
+ self.page.ele(f'tag:li@@role=option@@text():{province_residence}').click(by_js=True)
|
|
|
|
|
+ time.sleep(0.5)
|
|
|
|
|
+ except Exception as e:
|
|
|
|
|
+ self._log(e)
|
|
|
|
|
|
|
|
passport_type = self.account_detail.get('passport_type')
|
|
passport_type = self.account_detail.get('passport_type')
|
|
|
if passport_type:
|
|
if passport_type:
|
|
@@ -462,22 +466,22 @@ if __name__ == "__main__":
|
|
|
CAPSOLVER_KEY = "CAP-5441DD341DD3CC2FAEF0BE6FE493EE9A"
|
|
CAPSOLVER_KEY = "CAP-5441DD341DD3CC2FAEF0BE6FE493EE9A"
|
|
|
TLS_URL = "https://visas-fr.tlscontact.com/en-us/country/cn/vac/cnCNG2fr"
|
|
TLS_URL = "https://visas-fr.tlscontact.com/en-us/country/cn/vac/cnCNG2fr"
|
|
|
ACCOUNT_DETAIL = {
|
|
ACCOUNT_DETAIL = {
|
|
|
- "email": "lisi105@gmail-app.com",
|
|
|
|
|
|
|
+ "email": "lisi110@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": "FRA1CA20260421997",
|
|
|
|
|
|
|
+ "application_form_id": "FRA1CA20260419573",
|
|
|
"last_name": "Song",
|
|
"last_name": "Song",
|
|
|
- "first_name": "Xiaohui",
|
|
|
|
|
|
|
+ "first_name": "Xiaoyan",
|
|
|
"gender": "Male",
|
|
"gender": "Male",
|
|
|
"birthday": "1998-12-20",
|
|
"birthday": "1998-12-20",
|
|
|
"nationality": "China",
|
|
"nationality": "China",
|
|
|
"province_residence": "Sichuan",
|
|
"province_residence": "Sichuan",
|
|
|
"passport_type": "Ordinary passport",
|
|
"passport_type": "Ordinary passport",
|
|
|
- "passport_no": "EJ8628394",
|
|
|
|
|
|
|
+ "passport_no": "EJ8623112",
|
|
|
"phone_country_code": "86",
|
|
"phone_country_code": "86",
|
|
|
- "phone_number": "17386068828",
|
|
|
|
|
|
|
+ "phone_number": "18386037738",
|
|
|
"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"
|