1 背景
Make your clipboard data no longer easy to lose
2 环境
Python 3.7.3 64-bit
pywin32 224
3 win32clipboard
优点:速度快
缺点:不跨平台
- 获取文本
import win32clipboard as clip
clip.OpenClipboard() # 打开剪贴板
clip.SetClipboardText("这是复制的内容", clip.CF_UNICODETEXT) # 复制
text = clip.GetClipboardData(clip.CF_UNICODETEXT) # 粘贴
clip.CloseClipboard() # 关闭剪贴板
print(text)
- 获取复制文件的绝对路径
import win32clipboard as clip
clip.OpenClipboard() # 打开剪贴板
if clip.IsClipboardFormatAvailable(clip.CF_HDROP): # 判断剪贴板中是否包含指定格式的数据
file_path = clip.GetClipboardData(clip.CF_HDROP)
for item in file_path:
print("文件路径 -> %s" % item)
else:
print("请先复制文件!")
clip.CloseClipboard() # 关闭剪贴板
- 获取图片
import ctypes
from ctypes.wintypes import WORD, DWORD, LONG
import win32clipboard as clip
class BMPFileHeader(ctypes.Structure): # BMP文件头结构体
_pack_ = 1
_fields_ = [
('bfType', WORD),
('bfSize', DWORD),
('bfReserved1', WORD),
('bfReserved2', WORD),
('bfOffBits', DWORD)
]
BMPFileHeaderSize = ctypes.sizeof(BMPFileHeader)
class BMPApinfogHeader(ctypes.Structure): # 位图信息头结构体
_pack_ = 1
_fields_ = [
('biSize', DWORD),
('biWidth', LONG),
('biHeight', LONG),
('biPLanes', WORD),
('biBitCount', WORD),
('biCompression', DWORD),
('biSizeImage', DWORD),
('biXpelsPerMeter', LONG),
('biYpelsPerMeter', LONG),
('biClrUsed', DWORD),
('biClrImportant', DWORD)
]
BMPApinfogHeaderSize = ctypes.sizeof(BMPApinfogHeader)
ColorTableSize = 0
if __name__ == "__main__":
clip.OpenClipboard() # 打开剪贴板
if clip.IsClipboardFormatAvailable(clip.CF_DIB): # 判断剪贴板中是否包含指定格式的数据
data = clip.GetClipboardData(clip.CF_DIB) # 返回的是一个内存对象,包含BIT格式图片的信息
clip.CloseClipboard() # 关闭剪贴板
bmp_file_header = BMPFileHeader()
ctypes.memset(ctypes.pointer(bmp_file_header), 0, BMPFileHeaderSize)
bmp_file_header.bfType = ord('B') | (ord('M') << 8)
bmp_file_header.bfSize = BMPFileHeaderSize + len(data)
bmp_file_header.bfOffBits = BMPFileHeaderSize + BMPApinfogHeaderSize + ColorTableSize
with open("test.png", 'wb') as bmp_file:
bmp_file.write(bmp_file_header)
bmp_file.write(data)
else:
print("请先截图或者复制图片内容!")
- 获取剪贴板序列号
import win32clipboard as clip
print(clip.GetClipboardSequenceNumber())
当剪贴板内容发生变化或被清空时,该序列号会递增。所以可以通过该序列号来监听剪贴板。
4 主要代码
- 监听
def listen(self):
while self.allow_listen: # 是否允许监听,可通过 allow_listen 控制是否开启监听
if not self.pause_listen: # 是否暂停监听,可通过 pause_listen 控制是否暂停监听
clip_sn = clip.GetClipboardSequenceNumber() # 获取剪贴板序列号
if clip_sn != self.last_clip_sn: # 如果序列号和上次不一样,则代表剪贴板内容发生了变化
try:
data = self.get_data() # 获取剪贴板内容
if data[1] and len(data[1]) > self.max: # 如果剪贴板内容太长,则直接跳过
pass
else:
self.print(data) # 输出剪贴板内容
self.data.append(data) # 将剪贴板内容存入列表
if len(self.data) > self.num: # 如果列表中储存的内容超过限定个数,则删除最早的
del self.data[0]
self.last_clip_sn = clip_sn # 记录剪贴板序列号
except Exception as e: # 如果发生异常,则打印异常信息
print_exc()
self.print(e)
time.sleep(self.listen_invl) # 休眠指定时间,一般设为0.5秒就可以了
- 获取剪贴板内容
def get_data(self):
data_type = data_content = None
self.open() # 打开剪贴板
if clip.IsClipboardFormatAvailable(clip.CF_HDROP): # 如果是文件格式
data_content = [file for file in clip.GetClipboardData(clip.CF_HDROP)]
self.close()
data_type = self.DATA_TYPE_FILE
elif clip.IsClipboardFormatAvailable(clip.CF_DIB): # 如果是图片格式
if self.dir_img: # 如果设置了图片目录,则将剪贴板的图片内容保存到该目录
data = clip.GetClipboardData(clip.CF_DIB)
self.close()
self.last_img_path = data_content = self.save_img(data) # 保存图片
else:
self.close()
data_type = self.DATA_TYPE_IMG
elif clip.IsClipboardFormatAvailable(clip.CF_UNICODETEXT): # 如果是文本格式
data_content = clip.GetClipboardData(clip.CF_UNICODETEXT).split("\r\n")
self.close()
data_type = self.DATA_TYPE_TEXT
else:
self.close()
data_type = self.DATA_TYPE_OTHR
return (data_type, data_content)
这里优先判断是否满足文件格式,因为有些剪贴板内容既可以是文件格式也可以是图片格式,比如你在网页上复制了某些图片。防止图片重复存储至本地,因为图片可能已经存在于你的浏览器的临时目录里了。
- 保存图片
def save_img(self, data):
cur_time = time.strftime('%Y%m%d_%H%M%S', time.localtime(time.time())) # 当前时间
img_dir = os.path.join(self.dir_img,cur_time.split("_")[0]) # 分日期存储图片
if not os.path.exists(img_dir): os.mkdir(img_dir)
imt_name = "{}{}{}".format(self.IMG_NAME_PRFX, cur_time, self.IMG_NAME_SFX) # 图片名字
imt_path = os.path.join(img_dir, imt_name) # 图片具体路径
bmp_file_header = BMPFileHeader() # 创建文件头
ctypes.memset(ctypes.pointer(bmp_file_header), 0, BMPFileHeaderSize)
bmp_file_header.bfType = ord('B') | (ord('M') << 8)
bmp_file_header.bfSize = BMPFileHeaderSize + len(data)
bmp_file_header.bfOffBits = BMPFileHeaderSize + BMPApinfogHeaderSize + ColorTableSize
with open(imt_path, 'wb') as bmp_file: # 写入图片内容
bmp_file.write(bmp_file_header)
bmp_file.write(data)
return imt_path