添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Python: 截屏

最近项目中想实现截屏功能,使用的笔记本是高清屏,实际屏幕设置成了150%,所以在截屏的时候遇到个各种问题。

最开始使用PIL ImageGrab来截取屏幕,如果本来是100%的设置没有问题,能截取到全屏,但是150%或者其他设置的就会有问题,只能截取到屏幕的左上部分,无法截取到全屏。

from PIL import ImageGrab
pic = ImageGrab.grab()
# print(pic.size)
pic.save(r'C:\Users\test\Desktop\Automation\python\pic.jpg')

但是这个问题很奇怪,也有的机器150%设置,但是执行后没有问题。

遇到这个问题后看到网上有个解决方法:在注册表中Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers添加python.exe和pythonw.exe路径信息进去,再次执行程序就能截取到全屏,用python代码添加注册表的话,要重新再次运行程序才能截取到全屏:

from PIL import ImageGrab
import winreg
reg = winreg.ConnectRegistry(None, winreg.HKEY_CURRENT_USER)
key = winreg.OpenKey(reg, r'Control Panel\Desktop\WindowMetrics')
# print(winreg.QueryValueEx(key, 'AppliedDPI'))
if winreg.QueryValueEx(key, 'AppliedDPI')[0] != 96:
    key.Close()
    key = winreg.OpenKey(reg, r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers', 0, winreg.KEY_ALL_ACCESS)
    winreg.SetValueEx(key, r'C:\Users\test\AppData\Local\Continuum\anaconda3\pythonw.exe', 0, winreg.REG_SZ, 'HIGHDPIAWARE')
    winreg.SetValueEx(key, r'C:\Users\test\AppData\Local\Continuum\anaconda3\python.exe', 0, winreg.REG_SZ, 'HIGHDPIAWARE')
key.Close()
reg.Close()
pic = ImageGrab.grab()
# print(pic.size)
pic.save(r'C:\Users\test\Desktop\Automation\python\pic.jpg')

考虑到以后会用到其他机器上,每次都需要执行2次才能截取到全屏,就弃用了此方法。

后来使用pyautogui来截取全屏,一般没有安装pyautogui,需要先安装:
pip install pyautogui

import pyautogui
img = pyautogui.screenshot()
img.save(r'C:\Users\test\Desktop\Automation\python\pic_pyautogui.jpg')

但是如果笔记本还有连接外接显示器,是截取不到外显上内容的,只能截取笔记本显示器上的内容。如果要截取到外显上内容,想到使用win32方法来实现按键盘上的截屏功能,从而来实现抓取全屏带外显内容:

import win32api
import win32con
from PIL import ImageGrab
win32api.keybd_event(win32con.VK_SNAPSHOT, 0)
im = ImageGrab.grabclipboard()
im.save(r'C:\Users\test\Desktop\Automation\python\pic_screenshot.jpg')


运用Windows API来截屏,速度更快

def screenshot2():
    # 获取桌面
    hdesktop = win32gui.GetDesktopWindow()
    # 分辨率适应
    hDC = win32gui.GetDC(0)
    # 横向分辨率
    width = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)
    # 纵向分辨率
    height = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES)
    # 创建设备描述表
    desktop_dc = win32gui.GetWindowDC(hdesktop)
    img_dc = win32ui.CreateDCFromHandle(desktop_dc)
    # 创建一个内存设备描述表
    mem_dc = img_dc.CreateCompatibleDC()
    # 创建位图对象
    screenshot = win32ui.CreateBitmap()
    screenshot.CreateCompatibleBitmap(img_dc, width, height)
    mem_dc.SelectObject(screenshot)
    # 截图至内存设备描述表
    mem_dc.BitBlt((0, 0), (width, height), img_dc, (0, 0), win32con.SRCCOPY)
    # 将截图保存到文件中
    nowtime = time.strftime('%Y_%m_%d_%H_%M_%S',time.localtime(time.time()))
    screenshot.SaveBitmapFile(mem_dc, f'D:/Screenshots/{nowtime}.jpg')
    # 内存释放
    mem_dc.DeleteDC()
    win32gui.DeleteObject(screenshot.GetHandle())
def screenshot3():
    hwnd = 0  # 窗口的编号,0号表示当前活跃窗口
    # 根据窗口句柄获取窗口的设备上下文DC(Divice Context)
    hwndDC = win32gui.GetWindowDC(hwnd)
    # 根据窗口的DC获取mfcDC
    mfcDC = win32ui.CreateDCFromHandle(hwndDC)
    # mfcDC创建可兼容的DC
    saveDC = mfcDC.CreateCompatibleDC()
    # 创建bigmap准备保存图片
    saveBitMap = win32ui.CreateBitmap()
    # 获取真实的分辨率
    hDC = win32gui.GetDC(0)
    # 横向分辨率
    width = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)
    # 纵向分辨率
    height = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES)
    # 为bitmap开辟空间
    saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)
    # 高度saveDC,将截图保存到saveBitmap中
    saveDC.SelectObject(saveBitMap)
    # 截取从左上角(0,0)长宽为(w,h)的图片
    saveDC.BitBlt((0, 0), (width, height), mfcDC, (0, 0), win32con.SRCCOPY)
    # 将截图保存到文件中
    nowtime = time.strftime('%Y_%m_%d_%H_%M_%S', time.localtime(time.time()))