上网浏览网页的时候,看见好的内容免不了要使用复制粘贴,但是我们看到的内容、心里想要的内容和实际粘贴后的内容往往不一致。数据的获取始于复制,终于粘贴,那么问题来了,在这中间系统做了哪些操作,我们怎么能控制它呢?
码农的日常~
人生苦短,我用python,查阅相关资料之后发现有很多不一样的实现方式,如利用内置ctypes模块、tk模块,第三方模块如跨平台的pyperclip模块、clipboard模块、pywin.win32clipboard模块等等,大部分都封装好了简洁易用的高级接口,方便我们直接使用。
用最简单的方式获取你想要的数据
基于强迫症的心理,本文分析比较了几种主流的方式,对他们逐一进行源码分析、读写性能实测,最后选择了读写速度最快的一种做出一个实时剪切板监控小案例,以供大家参考。
小案例实现的功能如下:
- 实时监测ctrl c剪切板写入事件,去除剪切板中指定字符或文本,如CSDN的复制版权后缀 (¬_¬)瞄。
- 使用正则对某些文本进行智能替换,如将python2格式的代码转换为python3格式。
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')
剪切板读写速度测试结果
性能对比
实时监控小案例:
运行效果:
【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_ClipboardStack Overflow:https://stackoverflow.com/questions/579687/how-do-i-copy-a-string-to-the-clipboard-on-windows-using-python
这是一个数据爆炸的时代
,