如何让Python脚本模拟浏览器通过WiFi Captive Portal认证?
解决Captive Portal拒绝Python脚本请求的问题
我尝试用Python脚本通过POST方法连接带浏览器门户(Captive Portal)的WiFi,但门户因识别出请求并非来自浏览器而拒绝。以下是我的代码:
import requests url = 'https://xxx/portal_api.php' # Add appropriate credentials here payload = { "action": "authenticate", "login": "xxx@xxx.com", "password": "xxxx", "policy_accept": "false", "from_ajax": "true" } # Send a POST request with the credentials response = requests.post(url, data=payload) payload2 = { "action": "switch_language", "isAppleCNA_fakeclick": "false", "lang": "fr" } # Check if the connection was successful if response.status_code == 200: print("Connection successful 1") response2 = requests.post(url, data=payload2) if response2.status_code == 200: print("Connection successful 2") else: print("Connection failed")
我期望能成功连接并收到两个成功提示,但实际并未连接。用Postman测试请求时,收到如下响应:
<html> <head> <title>Forbidden access</title> </head> <body style="text-align:center"> <div style="width:80%; border:1px solid #64696C; color:#64696C; font-weight:bold; text-align:center; padding:20px; margin:auto; margin-top:20px"> <p id="small_p" style="font-size:small;">Forbidden access</p> <p id="large_p" style="font-size:large;">Your current web browser cannot access this page.</p> </div> </body> </html>
解决方法
要让门户认为脚本是合法浏览器,需要模拟浏览器的请求特征,主要做以下几点:
添加浏览器的User-Agent请求头
绝大多数Captive Portal会通过User-Agent字段识别请求来源。你需要在请求中添加主流浏览器的User-Agent值,比如Chrome的标识:headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36' }使用Session保持会话Cookie
浏览器访问门户时会自动保存并携带会话Cookie,脚本需要用requests.Session()来维护同一个会话,否则每次请求都是独立的,门户会判定为非法请求。补充其他必要请求头
部分门户还会检查Referer(请求来源页面)、Accept等字段,你可以通过浏览器开发者工具(F12)查看真实浏览器请求的完整头信息,复制到脚本中。
修改后的完整代码示例
import requests # 创建会话对象,自动维护Cookie session = requests.Session() url = 'https://xxx/portal_api.php' # 模拟Chrome浏览器的请求头 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Referer': 'https://xxx/portal_page.html', # 替换为门户的实际登录页面URL 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' } payload = { "action": "authenticate", "login": "xxx@xxx.com", "password": "xxxx", "policy_accept": "false", "from_ajax": "true" } # 发送认证请求,携带请求头和会话 response = session.post(url, data=payload, headers=headers) payload2 = { "action": "switch_language", "isAppleCNA_fakeclick": "false", "lang": "fr" } if response.status_code == 200: print("Connection successful 1") # 同一个会话发送第二个请求,自动携带Cookie response2 = session.post(url, data=payload2, headers=headers) if response2.status_code == 200: print("Connection successful 2") else: print("Connection failed") # 打印响应内容排查问题 print(response.text)
内容的提问来源于stack exchange,提问作者Othman Bargach
相关产品推荐
相关产品推荐

