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


Posted in Python onSeptember 11, 2019

前言

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

人生苦短,我用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')

剪切板读写速度测试结果

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

实时监控小案例:

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

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

Python 相关文章推荐
破解安装Pycharm的方法
Oct 19 Python
python url 参数修改方法
Dec 26 Python
使用TensorFlow实现二分类的方法示例
Feb 05 Python
Python基于滑动平均思想实现缺失数据填充的方法
Feb 21 Python
python通过http下载文件的方法详解
Jul 26 Python
Python中list的交、并、差集获取方法示例
Aug 01 Python
基于python的BP神经网络及异或实现过程解析
Sep 30 Python
python二元表达式用法
Dec 04 Python
Python threading.local代码实例及原理解析
Mar 16 Python
Python类和实例的属性机制原理详解
Mar 21 Python
基于jupyter代码无法在pycharm中运行的解决方法
Apr 21 Python
Python多线程 Queue 模块常见用法
Jul 04 Python
python连接、操作mongodb数据库的方法实例详解
Sep 11 #Python
面向对象学习之pygame坦克大战
Sep 11 #Python
Python整数与Numpy数据溢出问题解决
Sep 11 #Python
python中通过selenium简单操作及元素定位知识点总结
Sep 10 #Python
用Python画一个LinkinPark的logo代码实例
Sep 10 #Python
Pytorch修改ResNet模型全连接层进行直接训练实例
Sep 10 #Python
django drf框架自带的路由及最简化的视图
Sep 10 #Python
You might like
php排序算法(冒泡排序,快速排序)
2012/10/09 PHP
ThinkPHP3.1新特性之动态设置自动完成和自动验证示例
2014/06/19 PHP
四个常见html网页乱码问题及解决办法
2015/09/08 PHP
php使用Jpgraph创建折线图效果示例
2017/02/15 PHP
php正则表达式基本知识与应用详解【经典教程】
2017/04/17 PHP
Jquery中dialog属性小记
2010/09/03 Javascript
jQuery使用数组编写图片无缝向左滚动
2012/12/11 Javascript
jquery控制左右箭头滚动图片列表的实例
2013/05/20 Javascript
用jquery统计子菜单的条数示例代码
2013/10/18 Javascript
IE6浏览器中window.location.href无效的解决方法
2014/11/20 Javascript
jQuery实现的网页左侧在线客服效果代码
2015/10/23 Javascript
浅析jquery数组删除指定元素的方法:grep()
2016/05/19 Javascript
AngularJS 获取ng-repeat动态生成的ng-model值实例详解
2016/11/29 Javascript
js实现九宫格拼图小游戏
2017/02/13 Javascript
vue-cli+webpack在生成的项目中使用bootstrap实例代码
2017/05/26 Javascript
关于Webpack dev server热加载失败的解决方法
2018/02/22 Javascript
微信小程序上传图片实例
2018/05/28 Javascript
实用的Vue开发技巧
2019/05/30 Javascript
最简单的vue消息提示全局组件的方法
2019/06/16 Javascript
微信小程序 WXML节点信息查询详解
2019/07/29 Javascript
Vue状态模式实现窗口停靠功能(灵动、自由, 管理后台Admin界面)
2020/03/06 Javascript
[30:55]完美世界DOTA2联赛PWL S2 Magma vs LBZS 第二场 11.18
2020/11/18 DOTA
python中requests模块的使用方法
2015/04/08 Python
对于Python的Django框架部署的一些建议
2015/04/09 Python
Python元组操作实例分析【创建、赋值、更新、删除等】
2017/07/24 Python
Python打印“菱形”星号代码方法
2018/02/05 Python
分享一个pycharm专业版安装的永久使用方法
2019/09/24 Python
Python计算IV值的示例讲解
2020/02/28 Python
Django ForeignKey与数据库的FOREIGN KEY约束详解
2020/05/20 Python
HUGO BOSS美国官方网上商店:世界知名奢侈品牌
2017/08/04 全球购物
KIKO MILANO英国官网:意大利知名化妆品和护肤品品牌
2017/09/25 全球购物
爱尔兰最大的体育零售商:Life Style Sports
2019/06/12 全球购物
在weblogic中发布ejb需涉及到哪些配置文件
2012/01/17 面试题
推广普通话共筑中国梦演讲稿
2014/09/21 职场文书
2014年反腐倡廉工作总结
2014/12/05 职场文书
违纪检讨书
2015/01/27 职场文书