侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

基于Python实现剪切板实时监控方法解析

Python  /  管理员 发布于 7年前   190

前言

上网浏览网页的时候,看见好的内容免不了要使用复制粘贴,但是我们看到的内容、心里想要的内容和实际粘贴后的内容往往不一致。数据的获取始于复制,终于粘贴,那么问题来了,在这中间系统做了哪些操作,我们怎么能控制它呢?

人生苦短,我用python,查阅相关资料之后发现有很多不一样的实现方式,如利用内置ctypes模块、tk模块,第三方模块如跨平台的pyperclip模块、clipboard模块、pywin.win32clipboard模块等等,大部分都封装好了简洁易用的高级接口,方便我们直接使用。

基于强迫症的心理,本文分析比较了几种主流的方式,对他们逐一进行源码分析、读写性能实测,最后选择了读写速度最快的一种做出一个实时剪切板监控小案例,以供大家参考。

小案例实现的功能如下:

**实时监测ctrl+c剪切板写入事件,去除剪切板中指定字符或文本,如某些文字的后缀 (V_V)瞄。**

使用正则对某些文本进行智能替换,如将python2格式的代码转换为python3格式。

方式一:调用第三方pyperclip模块

In [1]: import pyperclipIn [2]: data = pyperclip.paste()In [3]: dataOut[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 ctypeswindll = ctypes.windllsafeGetClipboardData = CheckedCall(windll.user32.GetClipboardData)safeGetClipboardData.argtypes = [UINT]safeGetClipboardData.restype = HANDLEsafeSetClipboardData = 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]: dataOut[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]: TrueIn [5]: clipboard_get()Out[5]: 'Hello'

源码调用: C源码封装,python接口调用如下

def GetClipboardData(*args, **kwargs): # real signature unknown  passdef 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]: dataOut[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 timer = 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 win32clipboardimport reimport timedef clipboard_get():  """获取剪贴板数据"""  win32clipboard.OpenClipboard()  data = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)  win32clipboard.CloseClipboard()  return datadef 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_txtdef 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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


  • 上一条:
    Python使用APScheduler实现定时任务过程解析
    下一条:
    python连接、操作mongodb数据库的方法实例详解
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 在python语言中Flask框架的学习及简单功能示例(0个评论)
    • 在Python语言中实现GUI全屏倒计时代码示例(0个评论)
    • Python + zipfile库实现zip文件解压自动化脚本示例(0个评论)
    • python爬虫BeautifulSoup快速抓取网站图片(1个评论)
    • vscode 配置 python3开发环境的方法(0个评论)
    • 近期文章
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 在go语言中实现IP/CIDR的ip和netmask互转及IP段形式互转及ip是否存在IP/CIDR(0个评论)
    • PHP 8.4 Alpha 1现已发布!(0个评论)
    • Laravel 11.15版本发布 - Eloquent Builder中添加的泛型(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2018-04
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2022-01
    • 2023-07
    • 2023-10
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客