Python requests请求页面时网页内WebSocket未运行原因排查
问题描述
- 某网页内置WebSocket通信逻辑,直接通过浏览器访问时所有功能均可正常运行
- 使用Python
requests库发起POST请求访问该页面时,页面不会发起WebSocket连接,相关逻辑完全不执行 - 执行
print(response.text)可以正常输出包含WebSocket逻辑的完整网页HTML代码,但WebSocket相关逻辑始终不会触发
相关代码
前端WebSocket实现代码
<script> $(document).ready(function () { const messages_container = document.getElementById('chat_box'); let room_id = "{{ room.id }}"; var loc = window.location; var wsStart = 'ws://'; if (loc.protocol == 'https:') { var wsStart = 'wss://'; } let chatSocket = new WebSocket( wsStart + window.location.host + '/ws/matchmaker/' + room_id + '/' ); $('#game_results').click(function () { chatSocket.send(JSON.stringify({ 'message': 'results-incoming' })); }); chatSocket.onopen = function (e) { // 无初始化逻辑 }; chatSocket.onmessage = function (e) { let message = JSON.parse(e.data)['message']; if (message['message-type'] == 'get-room-players') { let message_body = JSON.parse(message['message-body']); let players = ""; for (let i = 0; i < message_body.length; i++) { players += `<div class="col-md-6 card"> <div class="card-body"> <h5 lass="card-title">player id ${message_body[i].fields['player_id']}</h5> <h5 lass="card-title">player skill ${message_body[i].fields['skill']}</h5> <h5 lass="card-title">player behaviour ${message_body[i].fields['behaviour']}</h5> <h5 lass="card-title">player skill preference ${message_body[i].fields['skill_preference']}</h5> <h5 lass="card-title">player behaviour preference ${message_body[i].fields['behaviour_preference']}</h5> <h5 lass="card-title">player granularity_preference ${message_body[i].fields['granularity_preference']}</h5> </div> </div>` } $('#players_container').html(players); } else if (message['message-type'] == 'update-players') { chatSocket.send(JSON.stringify({ 'message': 'get-room-players' })); } else if (message['message-type'] == 'update-room-match-status') { $('#match_status').text(message['message-body']); } else if (message['message-type'] == 'results-incoming') { window.location = "http://localhost:8002/game/?room_id=" + room_id; } else if (message['message-type'] == 'update-current-num-players') { $('#current_num_players').text(message['message-body']); // 房间人数达到上限后可进入游戏 if (message['message-body'] == {{ room.game.max_num_players }}) { $('#game_results').show(); } } }; chatSocket.onclose = function (e) { console.error('Chat socket closed unexpectedly'); }; } ); </script>
发起请求的Python代码
搭载上述WebSocket逻辑的页面是如下POST请求的响应结果:
response = client.post(url, headers=headers, params=params, data=data, cookies=cookies)
问题原因
核心原因是Python的requests库本质是纯HTTP静态请求客户端,仅具备发起HTTP请求、接收服务端返回HTTP响应内容的能力,完全没有内置浏览器的DOM解析、资源加载、JavaScript执行环境:
- 浏览器访问页面时,拿到HTML响应后会完成完整的渲染流程:解析DOM树、加载页面依赖的CSS/JS/图片等静态资源、执行页面内的JavaScript代码,写在
$(document).ready回调里的WebSocket初始化逻辑,就是在JS执行阶段被触发运行的。 - 用
requests发起请求时,response.text只是存储了服务端返回的HTML格式纯文本字符串,没有任何引擎会解析这段文本、加载关联资源、运行里面的JS代码,自然不会主动创建WebSocket连接。 - 简单来说,
requests只完成了"把网页源码从服务器下载到本地"这一步,完全不会像浏览器那样把源码加载成可交互的页面、运行页面里的逻辑。
解决方案
根据实际需求二选一即可:
- 如果需要完全模拟浏览器访问页面的行为(自动执行页面JS、触发WebSocket连接、渲染页面内容),不要用
requests,改用带浏览器渲染内核的自动化工具,比如selenium、playwright、pyppeteer,这类工具会驱动真实/无头浏览器加载页面,和手动用浏览器访问的效果完全一致。 - 如果不需要加载页面,只是要和后端的WebSocket服务通信,可以直接使用Python的WebSocket客户端库(比如
websocket-client、websockets),按照前端代码里的拼接规则直接构造WebSocket连接地址,手动完成连接、消息收发逻辑即可,不需要先请求对应的HTML页面。
内容的提问来源于stack exchange,提问作者Lucas Sousa
相关产品推荐
相关产品推荐

