基于Python实现剪切板实时监控方法解析
作者:辰冢 发布时间:2023-05-31 16:01:59
前言
上网浏览网页的时候,看见好的内容免不了要使用复制粘贴,但是我们看到的内容、心里想要的内容和实际粘贴后的内容往往不一致。数据的获取始于复制,终于粘贴,那么问题来了,在这中间系统做了哪些操作,我们怎么能控制它呢?
人生苦短,我用python,查阅相关资料之后发现有很多不一样的实现方式,如利用内置ctypes模块、tk模块,第三方模块如跨平台的pyperclip模块、clipboard模块、pywin.win32clipboard模块等等,大部分都封装好了简洁易用的高级接口,方便我们直接使用。
基于强迫症的心理,本文分析比较了几种主流的方式,对他们逐一进行源码分析、读写性能实测,最后选择了读写速度最快的一种做出一个实时剪切板监控小案例,以供大家参考。
小案例实现的功能如下:
**实时监测ctrl+c剪切板写入事件,去除剪切板中指定字符或文本,如某些文字的后缀 (¬_¬)瞄。**
使用正则对某些文本进行智能替换,如将python2格式的代码转换为python3格式。
方式一:调用第三方pyperclip模块
In [1]: import pyperclip
In [2]: data = pyperclip.paste()
In [3]: data
Out[3]: "print 'Hello World'\r\n————————————————\r\n版权声明:本文为CSDN博主「...」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。\r\n原文链接:https://blog.csdn.net/.../article/details/..."
In [4]: data = data[7:12]
In [5]: pyperclip.copy(data)
In [6]: pyperclip.paste()
Out[6]: 'Hello'
源码调用: 内置ctypes模块中的ctypes.windll.user32接口编写,和pandas包的代码一致,代码位置:pandas.io.clipboard.windows,代码引用如下
import ctypes
windll = ctypes.windll
safeGetClipboardData = CheckedCall(windll.user32.GetClipboardData)
safeGetClipboardData.argtypes = [UINT]
safeGetClipboardData.restype = HANDLE
safeSetClipboardData = CheckedCall(windll.user32.SetClipboardData)
safeSetClipboardData.argtypes = [UINT, HANDLE]
safeSetClipboardData.restype = HANDLE
优点: 跨平台,接口调用方便简洁
缺点: 剪切板的数据格式只支持utf-8文本,频繁读写速度较慢
方式二:调用第三方win32clipboard模块
In [1]: import win32clipboard
...:
...: def clipboard_get():
...: """获取剪贴板数据"""
...: win32clipboard.OpenClipboard()
...: data = win32clipboard.GetClipboardData()
...: win32clipboard.CloseClipboard()
...: return data
...:
...: def clipboard_set(data):
...: """设置剪贴板数据"""
...: win32clipboard.OpenClipboard()
...: win32clipboard.SetClipboardData(13, data)
...: win32clipboard.CloseClipboard()
...: return True
...:
In [2]: data = clipboard_get()
In [3]: data
Out[3]: "print 'Hello World'\r\n————————————————\r\n版权声明:本文为CSDN博主「...」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上 原文出处链接及本声明。\r\n原文链接:https://blog.csdn.net/.../article/details/..."
In [4]: clipboard_set(data[7:12])
Out[4]: True
In [5]: clipboard_get()
Out[5]: 'Hello'
源码调用: C源码封装,python接口调用如下
def GetClipboardData(*args, **kwargs): # real signature unknown
pass
def SetClipboardData(*args, **kwargs): # real signature unknown
pass
优点: 原生C封装读写速度最快,支持多种剪切板数据格式
缺点: 只适用于windows平台,高频率读写会报错需要小心处理,utf-8格式之外的数据格式需要熟悉winuser.h库自行设计编写
方法三:调用内置tkinter模块
In [1]: from tkinter import *
...:
...: r = Tk()
In [2]: data = r.clipboard_get()
In [3]: data
Out[3]: "print 'Hello World'\n————————————————\n版权声明:本文为CSDN博主「...」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文 出处链接及本声明。\n原文链接:https://blog.csdn.net/.../article/details/..."
In [4]: r.clipboard_append(data[7:12])
In [5]: r.clipboard_get()
Out[6]: 'Hello'
注意: 在win10系统测试后发现,使用tkinter模块只能获取剪切板数据,不能将数据写入剪切板,外部调用clipboard_board方法时,系统剪切板进程会被tk接管锁死,此时在其他的应用按ctrl+v,粘贴的应用会直接处于卡死的状态,或者粘贴后内容为空。
如果还是通过Tk()对象将数据写入剪切板,只能采取下面的方法,设置延迟销毁Tk对象,系统剪切板数据才会被更新,否则内容还是为空(实测如果设置0.2秒以内的频率读取,剪切板还是为空,这就很鸡肋了):
from tkinter import *
import time
r = Tk()
r.withdraw()
r.clipboard_clear()
r.clipboard_append('some string')
r.update()
time.sleep(.2)
r.update()
r.destroy()
源码调用: C源码封装,python接口调用如下
# 读取剪切板数据:
_tkinter.tkapp('clipboard', 'get')
# 写入剪切板数据:
_tkinter.tkapp('clipboard', 'append')
剪切板读写速度测试结果
实时监控小案例:
import win32clipboard
import re
import time
def clipboard_get():
"""获取剪贴板数据"""
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
return data
def clipboard_set(data):
"""设置剪贴板数据"""
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, data)
win32clipboard.CloseClipboard()
# 初始化替换字符列表,相比于正则使用replace函数进行单字符替换更快
char_list = [('(', '('),
(')', ')'),
('“', '"'),
('”', '"'),
('‘', '\''),
(''', '\''),
('print ', 'print '),
('版权声明:本文为CSDN', '版权声明:本文为CSDN'),
]
# 预编译正则替换匹配表达式
# 匹配python2格式的 print函数文本
sub_print = re.compile(r'\bprint\s+(.+)')
# 匹配csdn复制自带的版权声明后缀文本
sub_csdn = re.compile(r'—+\s+版权声明:本文为CSDN.*\s+原文链接.*')
# 指定场景 sub替换函数:python2格式的 print函数 替换为python3格式
def sub_fn(s):
return 'print(' + s.group(1).strip() + ')\r\n'
# 判断如果没有要替换的字符则返回None,有则执行替换操作,先进行字符列表replace,再执行reg.sub(sub_fn, txt)
def char_replace_reg_sub(txt):
new_txt = txt
# 对字符列表中字符 逐一判断,如果字符在文本中 则replace替换,如果都不在 则return None,不用再进行替换操作
i = 0
for old_char, new_char in char_list:
if old_char in new_txt:
i += 1
new_txt = new_txt.replace(old_char, new_char)
if i == 0:
return None
print('-' * 150, '\n【After char replace】:', new_txt)
# 对指定场景替换 使用正则re.sub
new_txt = sub_print.sub(sub_fn, new_txt)
new_txt = sub_csdn.sub('', new_txt)
print('【After sub replace:】', new_txt)
return new_txt
def main():
"""后台脚本:每隔0.2秒,读取剪切板文本,检查有无指定字符或字符串,如果有则执行替换"""
# recent_txt 存放最近一次剪切板文本,初始化值只多执行一次paste函数读取和替换
recent_txt = clipboard_get()
replaced_txt = char_replace_reg_sub(recent_txt)
clipboard_set(recent_txt if replaced_txt is None else replaced_txt)
while True:
# txt 存放当前剪切板文本
txt = clipboard_get()
# 剪切板内容和上一次对比如有变动,再进行内容判断,判断后如果发现有指定字符在其中的话,再执行替换
if txt != recent_txt:
# print(f'txt:{txt}')
new_txt = char_replace_reg_sub(txt) # 没查到要替换的子串,返回None
if new_txt is not None:
clipboard_set(new_txt)
# 更新 recent_txt 为替换之后的文本,便于下次与 txt 剪切板文本对比,判断内容有无更新
recent_txt = new_txt
# 检测间隔(延迟0.2秒)
time.sleep(0.2)
if __name__ == '__main__':
main()
运行效果:
-----------------------------------------------------------------------------------------
【Copy text】:
print 'Hello World' \r\n————————————————\r\n版权声明:本文为CSDN博主「...」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上 原文出处链接及本声明。\r\n原文链接:https://blog.csdn.net/.../article/details/...)
-----------------------------------------------------------------------------------------
【After replace:】:
print('Hello World')
-----------------------------------------------------------------------------------------
参考链接:
微软开发文档:https://docs.microsoft.com/zh-cn/windows/win32/dataxchg/using-the-clipboard?redirectedfrom=MSDN#_win32_Copying_Information_to_the_Clipboard
Stack Overflow:https://stackoverflow.com/questions/579687/how-do-i-copy-a-string-to-the-clipboard-on-windows-using-python
来源:https://www.cnblogs.com/chenzhong1/p/11503532.html
猜你喜欢
- 在腾讯的微信公众平台开发者文档,网页授权获取用户基本信息这一节中写道”在微信公众号请求用户网页授权之前,开发者需要先到公众平台网站的我的服务
- 测试配置文件test.conf内容如下:[first]w = 2v: 3c =11-3[second]sw=4test: hello测试配置
- 本文实例讲述了php基于curl实现随机ip地址抓取内容的方法。分享给大家供大家参考,具体如下:使用php curl 我们可以模仿用户行为,
- 功能点显示日期时间显示树莓派当前局域网IP显示当前UP主粉丝数显示B站未读消息显示B站视频总计播放数显示视频总计获赞数显示总计获得充电次数显
- 本文实例为大家分享了python实现微信自动回复的具体代码,供大家参考,具体内容如下新年到了,不想让一早上给你发送祝福的人心里一阵寒风,可以
- 一、异常处理在程序开发中如果遇到一些 不可预知的错误 或 你懒得做一些判断 时,可以选择用异常处理来做。import requestswhi
- 不知道大家有没有见过在python数组中使用...符号,因为前段时间读别人代码的时候遇到了这个符号立刻就云里雾里,于是这里特此记录一下。先来
- 本文实例为大家分享了python+opencv实现堆叠图片的具体代码,供大家参考,具体内容如下# import cv2# import nu
- 在日常生活中,经常会遇到需要提交身份证正反面证明资料的情况,而且这些网站大部分只接受pdf格式,这时候我们就需要把身份证正反面两张图片合成为
- 主要用到的js代码function getSelectedText(){ &nbs
- 编写tasks.pyfrom celery import Celeryfrom tornado.httpclient import HTTP
- 本文实例讲述了python二分查找算法的递归实现方法。分享给大家供大家参考,具体如下:这里先提供一段二分查找的代码:def binarySe
- 问题一:TypeError: a bytes-like object is required, not 'str'解决:该问
- 本文实例讲述了Python实现简单拆分PDF文件的方法。分享给大家供大家参考。具体如下:依赖pyPdf处理PDF文件切分pdf文件使用方法:
- 以下的文章主要是介绍SQL Server数据库与其实际应用元数据,我前两天在相关网站看见SQL Server数据库与其实际应用元数据的资料,
- 本文实例为大家分享了PyQt5实现简单计算器的具体代码,供大家参考,具体内容如下下面我们将介绍使用python的PyQt5图形界面来编写一个
- 本文实例讲述了django框架中间件原理与用法。分享给大家供大家参考,具体如下:中间件:轻量级,介于 request和response之间的
- 代码:import sysfrom PyQt5.QtWidgets import (QWidget, QHBoxLayout, QLabel
- 先来看看js中的Null类型表示什么?null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象,一般一个未定义的变量在初次使用
- 删除重复记录,将TABLE_NAME中的不重复记录保存到#TABLE_NAME中select distinct&nbs