如何使用Python监控屏幕变化并截图
1、导入所需模块
首先,我们需要导入一些Python模块,包括PIL(Python Imaging Library)、numpy、os和time。这些模块将帮助我们截取屏幕图像,并进行文件和时间相关的操作。
from PIL import ImageGrab # 导入ImageGrab模块,用于截取屏幕图像 import numpy as np # 导入numpy模块,用于处理图像数据 import os # 导入os模块,用于文件和文件夹操作 import time # 导入time模块,用于时间相关操作
2、设置截图保存路径
接下来,我们将设置截图保存的路径。在本例中,我们将截图保存到用户桌面的一个名为“Screenshots”的文件夹中。
desktop_path = os.path.join(os.path.expanduser("~"), "Desktop") # 获取当前用户的桌面路径 screenshot_folder = os.path.join(desktop_path, "Screenshots") # 设置截图保存文件夹路径 os.makedirs(screenshot_folder, exist_ok=True) # 创建截图保存文件夹,如果文件夹已存在则忽略
3、定义监控区域
我们需要定义要监控的屏幕区域的左上角和右下角坐标。在这个示例中,我们选择了一个800x600像素的区域
monitor_region = (0, 0, 800, 600) # 示例:左上角(0, 0),右下角(800, 600)
4、初始化上一次截图
我们将使用一个变量来保存上一次的屏幕截图,以便与当前截图进行比较,以检测屏幕是否发生了变化。
last_screenshot = ImageGrab.grab(bbox=monitor_region) # 截取指定区域的屏幕图像,并赋值给last_screenshot变量
5、 监控屏幕变化并截图
现在,我们将进入一个无限循环,在循环中持续监控屏幕的变化。当检测到屏幕发生变化时,我们将进行截图并保存。
try: while True: # 进入无限循环,持续监控屏幕变化 # 获取当前屏幕截图 current_screenshot = ImageGrab.grab(bbox=monitor_region) # 截取指定区域的屏幕图像,并赋值给current_screenshot变量 # 将图像转换为 NumPy 数组... # 计算监控区域的像素值差异... # 检查像素值差异是否超过阈值... # 保存截图... # 输出截图信息... # 更新上一次截图... # 每隔一定时间进行一次截图... except KeyboardInterrupt: # 捕获键盘中断异常,用于停止监控 print("Monitoring stopped.") # 打印停止监控的提示信息
6、完整代码
from PIL import ImageGrab # 导入ImageGrab模块,用于截取屏幕图像 import numpy as np # 导入numpy模块,用于处理图像数据 import os # 导入os模块,用于文件和文件夹操作 import time # 导入time模块,用于时间相关操作 # 设置截图保存路径 desktop_path = os.path.join(os.path.expanduser("~"), "Desktop") # 获取当前用户的桌面路径 screenshot_folder = os.path.join(desktop_path, "Screenshots") # 设置截图保存文件夹路径 os.makedirs(screenshot_folder, exist_ok=True) # 创建截图保存文件夹,如果文件夹已存在则忽略 # 定义监控区域的左上角和右下角坐标 monitor_region = (0, 0, 800, 600) # 示例:左上角(0, 0),右下角(800, 600) # 初始化上一次截图 last_screenshot = ImageGrab.grab(bbox=monitor_region) # 截取指定区域的屏幕图像,并赋值给last_screenshot变量 try: while True: # 进入无限循环,持续监控屏幕变化 # 获取当前屏幕截图 current_screenshot = ImageGrab.grab(bbox=monitor_region) # 截取指定区域的屏幕图像,并赋值给current_screenshot变量 # 将图像转换为 NumPy 数组 current_screenshot_array = np.array(current_screenshot) # 将当前截图转换为NumPy数组 last_screenshot_array = np.array(last_screenshot) # 将上一次截图转换为NumPy数组 # 计算监控区域的像素值差异 pixel_diff = np.sum(current_screenshot_array != last_screenshot_array) # 计算两张截图像素差异的总和 # 检查像素值差异是否超过阈值(根据具体情况调整阈值) threshold = 1000 # 示例阈值,根据实际情况调整 if pixel_diff > threshold: # 如果像素值差异超过阈值,则表示屏幕发生了变化 # 生成截图文件名 screenshot_filename = f"screenshot_{int(time.time())}.png" # 根据当前时间生成截图文件名 screenshot_path = os.path.join(screenshot_folder, screenshot_filename) # 拼接截图文件路径 # 保存截图 current_screenshot.save(screenshot_path) # 将当前截图保存为图片文件 # 输出截图信息 print(f"Screenshot saved: {screenshot_path}") # 打印截图保存路径 # 更新上一次截图 last_screenshot = current_screenshot # 将当前截图赋值给上一次截图,以便下一次比较 # 每隔一定时间进行一次截图 time.sleep(5) # 5秒钟检查一次屏幕变化,可根据需要调整 except KeyboardInterrupt: # 捕获键盘中断异常,用于停止监控 print("Monitoring stopped.") # 打印停止监控的提示信息
分类: Python , Windows , 自动截屏 标签: python , 开发语言 监控一个界面的内容变化,以确保自己能第一时间留意到,总不能一直看着吧?
于是我写了一个Python脚本去帮我看。原理就是实时获取界面像素,只要像素变化,代表界面有变化。
jiankong.py
[Python] 纯文本查看 复制代码 ?
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
from PIL import ImageGrab
import numpy as np
import time
import requests # Import the requests library
def get_screen_region_screenshot(region):
"""
获取屏幕指定区域的截图
"""
screenshot = ImageGrab.grab(bbox = region)
return np.array(screenshot)
def send_http_request():
"""
发送HTTP请求的函数
"""
# 替换接收通知的Url,我这里使用的是iOS的Bark App
url = "https://xxxxxxxxxxxxxxxx"
payload = { "key" : "value" }
headers = { "Content-Type" : "application/json" }
response = requests.post(url, json = payload, headers = headers)
# 打印结果
print ( "HTTP Response:" , response.text)
def monitor_screen_region_changes(region, polling_interval = 1 ):
"""
监控屏幕指定区域的像素变化
"""
previous_screenshot = get_screen_region_screenshot(region)
while True :
current_screenshot = get_screen_region_screenshot(region)
if not np.array_equal(previous_screenshot, current_screenshot):
print ( "指定区域的像素发生变化" )
# 发送HTTP请求
send_http_request()
# 更新前一次的截图
previous_screenshot = current_screenshot
time.sleep(polling_interval)
if __name__ = = "__main__" :
# 替换为要监控的区域坐标 (left, top, right, bottom)
# left:左上角距离屏幕左侧的距离(像素)
# top:左上角距离屏幕上方的距离(像素)
# right:右下角距离屏幕左侧的距离(像素)
# bottom:右下角距离屏幕上方的距离(像素)
region_to_monitor = ( 0 , 0 , 100 , 100 )
monitor_screen_region_changes(region_to_monitor)
|
如何获得坐标?截图软件一般都有标注像素。
运行
接收通知: Python的GUI应用,用于实时监控屏幕区域的图片变化,并通过图像哈希比较来检测相似度变化,触发警报。它利用Tkinter、PyAutoGUI和PIL库进行图像处理,以及pygame库处理声音。 摘要由CSDN通过智能技术生成
代码拿走就能跑
很乱 才开始学
import sys
import tkinter as tk
#创建图形用户界面(GUI)的标准库
import time
import cv2
#图片处理库
#import numpy as np
import pyautogui
#键鼠库
import pygame
#播放声音用,这个库有点大,但是我测试其他3个库 都不好使,只能用这个
from PIL import Image, ImageTk
#图像处理库
import threading
#线程库
from datetime import datetime
#时间库
start_x, start_y, end_x, end_y = None, None, None, None
#选取的区域坐标
from imagehash import average_hash
pinlv=2 #监控频率 第二版是把图片读取到内存操作 所以可以每秒一次
import io
should_exit = False
im0imagehas=0 #选区的hash值 用全局
isarm=False
i=0
def print_to_text(*args):
global i
global isarm
i=i+1
if 8 < i :
text_widget.delete(1.0, tk.END)#执行8次后清空一下txt,让txt一直滚动 方便进行监控
i=0
for arg in args:
if not isarm:
text_widget.tag_configure('red_text', foreground='blue')#正常字体
if isarm :
text_widget.tag_configure('red_text', foreground='red')#报警为红色
text_widget.insert('end', str(arg), 'red_text' )
text_widget.insert('end','\n')
text_widget.yview_scroll(1, 'units') # 向下滚动一格
# 将print的输出重定向到text_widget
print = print_to_text.__get__(None, print)
# 这将全局print函数绑定到text_widget
#按坐标获取切图
def qie_tu(img01=None):
global start_x, start_y, end_x, end_y
global disktoptu
# 使用pyautogui进行屏幕截图
screenshot = pyautogui.screenshot()
#screenshot.save('temp.png', format='png')
# 使用BytesIO将图像保持到内存中
crop_bytes0 = io.BytesIO()
screenshot.save(crop_bytes0, format='png')
# 读取到内存中的图像数据
crop_bytes0 = crop_bytes0.getvalue()
# 打开图像
img = Image.open(io.BytesIO(crop_bytes0))
# 截取部分图像
disktoptu=img
crop = img.crop((start_x,start_y ,end_x, end_y))
# 使用BytesIO将图像保持到内存中
crop_bytes = io.BytesIO()
crop.save(crop_bytes, format='png')
# 读取到内存中的图像数据
crop_bytes = crop_bytes.getvalue()
# 对内存中的图像进行处理,例如调整大小
# 这里使用的是PIL库的Image类,你可以根据需要进行其他操作
im0 = Image.open(io.BytesIO(crop_bytes))
# 如果需要,你可以在此处进行其他操作,例如旋转、裁剪等。
# 在完成所有操作后,你可以使用下面的代码将图像保存到磁盘。
imimagehash=average_hash(im0)#image hash
img.save('desktop_screenshot.png', format='png') # 将处理后的图像保存到磁盘
if img01 != None:
im0.save(img01, format='png') # 将处理后的图像保存到磁盘
return (str(imimagehash))
#鼠标选区并截取
def select_screen_region():
load_alarm_sound("警报声.mp3")#放到这里防止错误提示终止运行
text_widget.delete(1.0, tk.END)
print('点击选区后,进入选区模式,'+'\n''最下面出现红色按钮才可以开始选区,'+'\n''选区后点击红色按钮退出选区模式')
btn_xq.config(state=tk.DISABLED)#点击开始选区后 不可以重复点击 ,需要暂停后再次启动
btn_start.config(state=tk.DISABLED)#开始按键停用
global start_x, start_y, end_x, end_y
global im0imagehas
def on_press(event):
global start_x, start_y
start_x, start_y = event.x, event.y
def on_move(event):
global end_x, end_y
end_x, end_y = event.x, event.y
canvas.coords(rect, start_x, start_y, end_x, end_y)
def on_release(event):
global end_x, end_y
end_x, end_y = event.x, event.y
canvas.coords(rect, start_x, start_y, end_x, end_y)
root1 = tk.Toplevel(root)
root1.title("选择监控区域")
root1.attributes('-fullscreen', True) #设置全屏模式
screenshot = pyautogui.screenshot() #截屏
screenshot.save('desktop_screenshot.png', format='png')
canvas = tk.Canvas(root1, bg='white') #创建画布
canvas.pack(fill=tk.BOTH, expand=True)#添加画布并填充
desktop_image = ImageTk.PhotoImage(file='desktop_screenshot.png')#创建图片对象
canvas.create_image(0, 0, anchor=tk.NW, image=desktop_image)#在画布上添加图片
rect = canvas.create_rectangle(0, 0, 0, 0, outline='red')#创建矩形对象
canvas.bind("<ButtonPress-1>", on_press)
canvas.bind("<B1-Motion>", on_move)
canvas.bind("<ButtonRelease-1>", on_release)
def close_window(): # 新增的关闭窗口函数
global im0imagehas
if start_x== None:
text_widget.delete(1.0, tk.END)
print("请选定区域后再退出"+'\n'+'\n')
print('点击选区后,进入选区模式,'+'\n''最下面出现红色按钮才可以开始选区,'+'\n''选区后点击红色按钮退出选区模式。')
else:
#im0imagehas = qie_tu('0.png') 在这里切图会再次抓屏 把那条红线抓进来
img = Image.open('desktop_screenshot.png')
crop = img.crop((start_x,start_y ,end_x, end_y))
#crop.save('0.png', format='png')
# 使用BytesIO将图像保持到内存中
crop_bytes = io.BytesIO()
crop.save(crop_bytes, format='png')
im0imagehas=average_hash(crop)
text_widget.delete(1.0, tk.END)
print('成功抓取所选区域 可以开始监控')
btn_start.config(state=tk.NORMAL)#成功抓取区域图片后,才可以开始监控
root1.destroy() # 使用Tkinter的destroy()方法关闭窗口
button_close = tk.Button(root1, text=",选择需要监控的区域后,点击此关闭", fg="red", command=close_window) # 创建关闭按钮
button_close.pack()
root1.mainloop()
# 初始化pygame库
pygame.init()
pygame.mixer.init()
# 全局变量,加载MP3文件
def load_alarm_sound(file_path):
try:
pygame.mixer.music.load(file_path)
except pygame.error:
print(f"无法加载音频文件:{file_path}")
# 封装一个播放MP3警报的函数
def play_alarm():
try:
# 播放MP3文件
pygame.mixer.music.play()
except pygame.error:
print("播放警报音频失败")
def monitor(data_source):
global pinlv
global should_exit
global isarm
global im0imagehas
while not should_exit:
current_time = datetime.now()
time_string = current_time.strftime("%H:%M:%S")
#im1imagehas = qie_tu('1.png')
im1imagehas = qie_tu()
#print('im0imagehas:',str(im0imagehas))
#print('im1imagehas:',str(im1imagehas))
if str(im0imagehas) != str(im1imagehas) :
print(time_string,' 相似度有变化,进行报警!')
play_alarm()
isarm=True
else:
print(time_string,' 相似度没有变化')
isarm=False
time.sleep(pinlv) # 等待5秒后再获取下一帧
if should_exit and suspend :
print('暂停监控')
else :
cv2.destroyAllWindows()
def start_recognition():
btn_start.config(state=tk.DISABLED)
btn_suspend.config(state=tk.NORMAL)
global should_exit
global suspend
suspend = False
should_exit = False
print("开始监控")
th_monitor = threading.Thread(target=monitor, args=("screenshot",))
th_monitor.daemon = True
th_monitor.start()
def suspend_recognition():
btn_xq.config(state=tk.NORMAL)
btn_start.config(state=tk.NORMAL)
btn_suspend.config(state=tk.DISABLED)
global suspend
global should_exit
should_exit = True
suspend=True
def end_program():
global should_exit
should_exit = True
print("结束监控")
sys.exit(1)
# 创建主窗口
root = tk.Tk()
root.title("监控报警")
root.wm_attributes('-topmost', True)
root.protocol("WM_DELETE_WINDOW",end_program)
#计算屏幕中央的位置
x = int((root.winfo_screenwidth() - root.winfo_reqwidth()) / 2)
y = int((root.winfo_screenheight() - root.winfo_reqheight()) / 2)
#将窗口居中显示
root.geometry("+{}+{}".format(x, y))
text_widget = tk.Text(root, width=55, height=10) # 设置文本框的最小宽度为40个字符,最小高度为10行
#text_widget.grid(column=0, row=0, width=10) # 在grid中设置文本框的宽度为10个字符
text_widget.pack()
# 添加按钮
print('点击选区后,进入选区模式,'+'\n''最下面出现红色按钮才可以开始选区,'+'\n''选区后点击红色按钮退出选区模式。')
btn_xq = tk.Button(root, text="开始选区", command=select_screen_region)
btn_start = tk.Button(root, text="开始监控", command=start_recognition)
btn_suspend = tk.Button(root, text="暂停监控", command=suspend_recognition)
btn_end = tk.Button(root, text="结束监控", command=end_program)
#btn_start.config(state=tk.DISABLED)
# 使用pack布局并设置side参数为LEFT实现横向排列
btn_suspend.config(state=tk.DISABLED)#暂停按键停用
btn_start.config(state=tk.DISABLED)#开始按键停用
btn_xq.pack(side=tk.LEFT, padx=10, pady=10)
btn_start.pack(side=tk.LEFT, padx=10, pady=10)
btn_suspend.pack(side=tk.LEFT, padx=10, pady=10)
btn_end.pack(side=tk.LEFT, padx=10, pady=10)
# 创建一个下拉列表变量
root.var = tk.StringVar(root)
# 设置下拉列表的默认值
root.var.set("监控频率默认2秒次")
# 定义下拉列表的选项
options = ["1秒次", "5秒次", "10秒次", "20秒次", "30秒次"]
# 创建下拉列表
dropdown = tk.OptionMenu(root, root.var, *options)
# 将下拉列表放置到主窗口
dropdown.pack()
def option_selected(*args):
global pinlv
text_widget.delete(1.0, tk.END)
print(f"选项 {root.var.get()} 被选择了!")
if root.var.get() == "1秒次" :
pinlv=1
if root.var.get() == "5秒次" :
pinlv=5
if root.var.get() == "10秒次" :
pinlv=10
if root.var.get() == "20秒次" :
pinlv=20
if root.var.get() == "30秒次" :
pinlv=30
root.var.trace("w", option_selected)
# 进入事件循环
root.mainloop()