refactor: enhance auto-login functionality and add MAC address randomization

This commit is contained in:
2026-04-13 12:48:46 -04:00
parent f50b7dab84
commit 955e636d5f
2 changed files with 231 additions and 57 deletions

BIN
README.md

Binary file not shown.

260
main.py
View File

@@ -1,74 +1,248 @@
from selenium import webdriver
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.webdriver.edge.service import Service as EdgeService
from selenium.webdriver.edge.options import Options
# 如果你安装了 webdriver_manager取消下面这行的注释
# from webdriver_manager.microsoft import EdgeChromiumDriverManager
import argparse
import random
import subprocess
import sys
import time
import requests
import winreg
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.edge.options import Options
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
# Captive Portal 触发 URL 列表,按优先级依次尝试
CAPTIVE_PORTAL_URLS = [
"http://captive.apple.com/",
"http://www.msftconnecttest.com/redirect",
"http://detectportal.firefox.com/",
]
MAX_LOGIN_RETRIES = 3
def is_connected():
"""通过 HTTP 204 检测网络是否连通。"""
test_urls = [
("http://clients3.google.com/generate_204", 204),
("http://www.msftconnecttest.com/connecttest.txt", 200),
]
for url, expected_status in test_urls:
try:
# 尝试访问一个极其稳定的网站,设置短超时
requests.get("https://www.google.com", timeout=3)
r = requests.get(url, timeout=3)
if r.status_code == expected_status:
return True
except:
except Exception:
continue
return False
def auto_login_wifi():
# 配置 Edge 选项
edge_options = Options()
edge_options.add_argument("--start-maximized") # 最大化窗口
edge_options.add_argument("--ignore-certificate-errors") # 忽略证书错误公共Wi-Fi常见
edge_options.add_argument("--headless") # 如果不想看到浏览器界面,取消注释这一行
def get_wifi_adapter_name():
"""获取当前活跃的 Wi-Fi 网卡名称。"""
result = subprocess.run(
["netsh", "wlan", "show", "interfaces"],
capture_output=True, text=True, encoding="gbk",
)
for line in result.stdout.splitlines():
line = line.strip()
if line.startswith("名称") or line.startswith("Name"):
return line.split(":", 1)[1].strip()
return None
def generate_random_mac():
"""生成一个随机的本地管理单播 MAC 地址。"""
mac = [random.randint(0x00, 0xFF) for _ in range(6)]
mac[0] = (mac[0] & 0xFC) | 0x02 # 本地管理、单播
return mac
def find_adapter_registry_key(adapter_name):
"""在注册表中找到匹配 adapter_name 的网卡子键路径。"""
base_path = r"SYSTEM\CurrentControlSet\Control\Class\{4d36e972-e325-11ce-bfc1-08002be10318}"
try:
base_key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, base_path)
except OSError:
return None
index = 0
while True:
try:
subkey_name = winreg.EnumKey(base_key, index)
index += 1
except OSError:
break
try:
subkey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, f"{base_path}\\{subkey_name}")
driver_desc, _ = winreg.QueryValueEx(subkey, "DriverDesc")
if adapter_name.lower() in driver_desc.lower():
winreg.CloseKey(subkey)
winreg.CloseKey(base_key)
return f"{base_path}\\{subkey_name}"
winreg.CloseKey(subkey)
except OSError:
continue
winreg.CloseKey(base_key)
return None
def randomize_mac():
"""随机化当前 Wi-Fi 网卡的 MAC 地址(需要管理员权限)。"""
adapter_name = get_wifi_adapter_name()
if not adapter_name:
print("错误:未找到活跃的 Wi-Fi 适配器。")
return False
print(f"找到 Wi-Fi 适配器: {adapter_name}")
reg_path = find_adapter_registry_key(adapter_name)
if not reg_path:
print(f"错误:未在注册表中找到适配器 '{adapter_name}' 的条目。")
return False
mac = generate_random_mac()
mac_str = "".join(f"{b:02X}" for b in mac)
mac_display = ":".join(f"{b:02X}" for b in mac)
try:
# 初始化 Edge 驱动
# 如果安装了 webdriver_manager使用下面这行
# driver = webdriver.Edge(service=EdgeService(EdgeChromiumDriverManager().install()), options=edge_options)
key = winreg.OpenKey(
winreg.HKEY_LOCAL_MACHINE, reg_path, 0, winreg.KEY_SET_VALUE,
)
winreg.SetValueEx(key, "NetworkAddress", 0, winreg.REG_SZ, mac_str)
winreg.CloseKey(key)
except PermissionError:
print("错误:需要管理员权限来修改 MAC 地址。请以管理员身份运行。")
return False
# 如果没有安装 webdriver_manager且驱动已在环境变量中直接使用下面这行
print(f"正在将 MAC 地址更改为: {mac_display}")
# 获取网络适配器的接口名称(用于 netsh
interface_name = get_netsh_interface_name()
if not interface_name:
interface_name = adapter_name
print("正在重启网卡以应用新 MAC 地址...")
subprocess.run(
["netsh", "interface", "set", "interface", interface_name, "disable"],
capture_output=True,
)
time.sleep(2)
subprocess.run(
["netsh", "interface", "set", "interface", interface_name, "enable"],
capture_output=True,
)
time.sleep(3)
print(f"MAC 地址已更改为: {mac_display}")
return True
def get_netsh_interface_name():
"""获取 Wi-Fi 网络接口的名称(用于 netsh interface 命令)。"""
result = subprocess.run(
["netsh", "interface", "show", "interface"],
capture_output=True, text=True, encoding="gbk",
)
for line in result.stdout.splitlines():
if "Wi-Fi" in line or "WLAN" in line or "Wireless" in line:
parts = line.split()
if len(parts) >= 4:
return " ".join(parts[3:])
return None
def auto_login_wifi():
"""自动登录 OSU 公共 Wi-Fi支持重试。"""
edge_options = Options()
edge_options.add_argument("--start-maximized")
edge_options.add_argument("--ignore-certificate-errors")
edge_options.add_argument("--headless")
for attempt in range(1, MAX_LOGIN_RETRIES + 1):
driver = None
try:
driver = webdriver.Edge(options=edge_options)
print(f"{attempt} 次尝试登录...")
print("正在打开浏览器并访问触发页面...")
# 1. 访问触发页面,这会自动重定向到 OSU 的登录页
driver.get("http://captive.apple.com/")
# 依次尝试不同的 Captive Portal 触发 URL
portal_reached = False
for url in CAPTIVE_PORTAL_URLS:
print(f" 访问触发页面: {url}")
driver.get(url)
try:
wait = WebDriverWait(driver, 10)
wait.until(EC.element_to_be_clickable((By.NAME, "visitor_accept_terms")))
portal_reached = True
break
except Exception:
print(f" 未能通过 {url} 跳转到登录页,尝试下一个...")
continue
# 设置显式等待,最长等待 20 秒,确保页面元素加载出来
wait = WebDriverWait(driver, 20)
print("等待跳转至登录页面...")
# 2. 定位并勾选 "I accept the terms of use"
# 使用 name="visitor_accept_terms" 定位,这比包含随机数字的 ID 更稳定
checkbox = wait.until(EC.element_to_be_clickable((By.NAME, "visitor_accept_terms")))
if not portal_reached:
print(f"{attempt} 次尝试未能到达登录页面。")
continue
# 勾选同意协议
checkbox = driver.find_element(By.NAME, "visitor_accept_terms")
if not checkbox.is_selected():
checkbox.click()
print(" 已勾选同意协议。")
# 3. 定位并点击 "Log In" 按钮
# 同样避开动态 ID使用 XPath 查找 value 为 "Log In" 的提交按钮
login_button = driver.find_element(By.XPATH, "//input[@type='submit' and @value='Log In']")
time.sleep(1)
# 点击登录按钮
login_button = driver.find_element(
By.XPATH, "//input[@type='submit' and @value='Log In']",
)
login_button.click()
print(" 已点击登录按钮。")
# 保持窗口打开一小会儿以确认连接成功(根据需要调整)
import time
time.sleep(5)
print("操作完成。")
# 轮询验证是否真正连上网络
for i in range(10):
time.sleep(2)
if is_connected():
print("登录成功!网络已连通。")
return
print(f"{attempt} 次尝试:点击登录后网络仍未连通。")
except Exception as e:
print(f"发生错误: {e}")
print(f"{attempt} 次尝试出错: {e}")
finally:
# 如果你想让浏览器保持打开状态,注释掉下面这行
if driver:
driver.quit()
if __name__ == "__main__":
if attempt < MAX_LOGIN_RETRIES:
print(" 等待 3 秒后重试...")
time.sleep(3)
print("多次尝试后仍未能成功登录。")
def main():
parser = argparse.ArgumentParser(description="OSU 公共 Wi-Fi 自动登录工具")
parser.add_argument(
"--random-mac",
action="store_true",
help="登录前随机化 Wi-Fi 网卡的 MAC 地址(需要管理员权限)",
)
args = parser.parse_args()
if is_connected():
print("网络已连接,无需登录。")
return
if args.random_mac:
print("正在随机化 MAC 地址...")
if not randomize_mac():
print("MAC 地址随机化失败,继续尝试登录...")
else:
# MAC 更改后需要等待 Wi-Fi 重新连接
print("等待 Wi-Fi 重新连接...")
time.sleep(5)
auto_login_wifi()
if __name__ == "__main__":
main()