基于Python實(shí)現(xiàn)剪切板實(shí)時(shí)監(jiān)控方法解析
前言
上網(wǎng)瀏覽網(wǎng)頁的時(shí)候,看見好的內(nèi)容免不了要使用復(fù)制粘貼,但是我們看到的內(nèi)容、心里想要的內(nèi)容和實(shí)際粘貼后的內(nèi)容往往不一致。數(shù)據(jù)的獲取始于復(fù)制,終于粘貼,那么問題來了,在這中間系統(tǒng)做了哪些操作,我們?cè)趺茨芸刂扑兀?/p>
人生苦短,我用python,查閱相關(guān)資料之后發(fā)現(xiàn)有很多不一樣的實(shí)現(xiàn)方式,如利用內(nèi)置ctypes模塊、tk模塊,第三方模塊如跨平臺(tái)的pyperclip模塊、clipboard模塊、pywin.win32clipboard模塊等等,大部分都封裝好了簡(jiǎn)潔易用的高級(jí)接口,方便我們直接使用。
基于強(qiáng)迫癥的心理,本文分析比較了幾種主流的方式,對(duì)他們逐一進(jìn)行源碼分析、讀寫性能實(shí)測(cè),最后選擇了讀寫速度最快的一種做出一個(gè)實(shí)時(shí)剪切板監(jiān)控小案例,以供大家參考。
小案例實(shí)現(xiàn)的功能如下:
**實(shí)時(shí)監(jiān)測(cè)ctrl+c剪切板寫入事件,去除剪切板中指定字符或文本,如某些文字的后綴 (¬_¬)瞄。**
使用正則對(duì)某些文本進(jìn)行智能替換,如將python2格式的代碼轉(zhuǎn)換為python3格式。
方式一:調(diào)用第三方pyperclip模塊
In [1]: import pyperclip In [2]: data = pyperclip.paste() In [3]: data Out[3]: "print 'Hello World'\r\n————————————————\r\n版權(quán)聲明:本文為CSDN博主「...」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。\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'
源碼調(diào)用: 內(nèi)置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
優(yōu)點(diǎn): 跨平臺(tái),接口調(diào)用方便簡(jiǎn)潔
缺點(diǎn): 剪切板的數(shù)據(jù)格式只支持utf-8文本,頻繁讀寫速度較慢
方式二:調(diào)用第三方win32clipboard模塊
In [1]: import win32clipboard ...: ...: def clipboard_get(): ...: """獲取剪貼板數(shù)據(jù)""" ...: win32clipboard.OpenClipboard() ...: data = win32clipboard.GetClipboardData() ...: win32clipboard.CloseClipboard() ...: return data ...: ...: def clipboard_set(data): ...: """設(shè)置剪貼板數(shù)據(jù)""" ...: 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版權(quán)聲明:本文為CSDN博主「...」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上 原文出處鏈接及本聲明。\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'
源碼調(diào)用: C源碼封裝,python接口調(diào)用如下
def GetClipboardData(*args, **kwargs): # real signature unknown pass def SetClipboardData(*args, **kwargs): # real signature unknown pass
優(yōu)點(diǎn): 原生C封裝讀寫速度最快,支持多種剪切板數(shù)據(jù)格式
缺點(diǎn): 只適用于windows平臺(tái),高頻率讀寫會(huì)報(bào)錯(cuò)需要小心處理,utf-8格式之外的數(shù)據(jù)格式需要熟悉winuser.h庫自行設(shè)計(jì)編寫
方法三:調(diào)用內(nèi)置tkinter模塊
In [1]: from tkinter import * ...: ...: r = Tk() In [2]: data = r.clipboard_get() In [3]: data Out[3]: "print 'Hello World'\n————————————————\n版權(quán)聲明:本文為CSDN博主「...」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文 出處鏈接及本聲明。\n原文鏈接:https://blog.csdn.net/.../article/details/..." In [4]: r.clipboard_append(data[7:12]) In [5]: r.clipboard_get() Out[6]: 'Hello'
注意: 在win10系統(tǒng)測(cè)試后發(fā)現(xiàn),使用tkinter模塊只能獲取剪切板數(shù)據(jù),不能將數(shù)據(jù)寫入剪切板,外部調(diào)用clipboard_board方法時(shí),系統(tǒng)剪切板進(jìn)程會(huì)被tk接管鎖死,此時(shí)在其他的應(yīng)用按ctrl+v,粘貼的應(yīng)用會(huì)直接處于卡死的狀態(tài),或者粘貼后內(nèi)容為空。
如果還是通過Tk()對(duì)象將數(shù)據(jù)寫入剪切板,只能采取下面的方法,設(shè)置延遲銷毀Tk對(duì)象,系統(tǒng)剪切板數(shù)據(jù)才會(huì)被更新,否則內(nèi)容還是為空(實(shí)測(cè)如果設(shè)置0.2秒以內(nèi)的頻率讀取,剪切板還是為空,這就很雞肋了):
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()
源碼調(diào)用: C源碼封裝,python接口調(diào)用如下
# 讀取剪切板數(shù)據(jù):
_tkinter.tkapp('clipboard', 'get')
# 寫入剪切板數(shù)據(jù):
_tkinter.tkapp('clipboard', 'append')
剪切板讀寫速度測(cè)試結(jié)果

實(shí)時(shí)監(jiān)控小案例:
import win32clipboard
import re
import time
def clipboard_get():
"""獲取剪貼板數(shù)據(jù)"""
win32clipboard.OpenClipboard()
data = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
win32clipboard.CloseClipboard()
return data
def clipboard_set(data):
"""設(shè)置剪貼板數(shù)據(jù)"""
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, data)
win32clipboard.CloseClipboard()
# 初始化替換字符列表,相比于正則使用replace函數(shù)進(jìn)行單字符替換更快
char_list = [('(', '('),
(')', ')'),
('“', '"'),
('”', '"'),
('‘', '\''),
(''', '\''),
('print ', 'print '),
('版權(quán)聲明:本文為CSDN', '版權(quán)聲明:本文為CSDN'),
]
# 預(yù)編譯正則替換匹配表達(dá)式
# 匹配python2格式的 print函數(shù)文本
sub_print = re.compile(r'\bprint\s+(.+)')
# 匹配csdn復(fù)制自帶的版權(quán)聲明后綴文本
sub_csdn = re.compile(r'—+\s+版權(quán)聲明:本文為CSDN.*\s+原文鏈接.*')
# 指定場(chǎng)景 sub替換函數(shù):python2格式的 print函數(shù) 替換為python3格式
def sub_fn(s):
return 'print(' + s.group(1).strip() + ')\r\n'
# 判斷如果沒有要替換的字符則返回None,有則執(zhí)行替換操作,先進(jìn)行字符列表replace,再執(zhí)行reg.sub(sub_fn, txt)
def char_replace_reg_sub(txt):
new_txt = txt
# 對(duì)字符列表中字符 逐一判斷,如果字符在文本中 則replace替換,如果都不在 則return None,不用再進(jìn)行替換操作
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)
# 對(duì)指定場(chǎng)景替換 使用正則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():
"""后臺(tái)腳本:每隔0.2秒,讀取剪切板文本,檢查有無指定字符或字符串,如果有則執(zhí)行替換"""
# recent_txt 存放最近一次剪切板文本,初始化值只多執(zhí)行一次paste函數(shù)讀取和替換
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 存放當(dāng)前剪切板文本
txt = clipboard_get()
# 剪切板內(nèi)容和上一次對(duì)比如有變動(dòng),再進(jìn)行內(nèi)容判斷,判斷后如果發(fā)現(xiàn)有指定字符在其中的話,再執(zhí)行替換
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 剪切板文本對(duì)比,判斷內(nèi)容有無更新
recent_txt = new_txt
# 檢測(cè)間隔(延遲0.2秒)
time.sleep(0.2)
if __name__ == '__main__':
main()
運(yùn)行效果:
-----------------------------------------------------------------------------------------
【Copy text】:
print 'Hello World' \r\n————————————————\r\n版權(quán)聲明:本文為CSDN博主「...」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上 原文出處鏈接及本聲明。\r\n原文鏈接:https://blog.csdn.net/.../article/details/...)
-----------------------------------------------------------------------------------------
【After replace:】:
print('Hello World')
-----------------------------------------------------------------------------------------
參考鏈接:
Stack Overflow:https://stackoverflow.com/questions/579687/how-do-i-copy-a-string-to-the-clipboard-on-windows-using-python
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python內(nèi)置堆的具體實(shí)現(xiàn)
本文主要介紹了python內(nèi)置堆的具體實(shí)現(xiàn),堆的表示方法,從上到下,從左到右存儲(chǔ),與列表十分相似,本文就來介紹一下,感興趣的可以了解一下2023-03-03
Python實(shí)現(xiàn)模擬登錄網(wǎng)易郵箱的方法示例
這篇文章主要介紹了Python實(shí)現(xiàn)模擬登錄網(wǎng)易郵箱的方法,結(jié)合實(shí)例形式分析了Python基于urllib2及cookielib模塊的http請(qǐng)求、數(shù)據(jù)傳輸及交互相關(guān)操作技巧,需要的朋友可以參考下2018-07-07
一個(gè)Python優(yōu)雅的數(shù)據(jù)分塊方法詳解
在做需求過程中有一個(gè)對(duì)大量數(shù)據(jù)分塊處理的場(chǎng)景,具體來說就是幾十萬量級(jí)的數(shù)據(jù),分批處理,每次處理100個(gè)。這時(shí)就需要一個(gè)分塊功能的代碼。本文為大家分享了一個(gè)Python中優(yōu)雅的數(shù)據(jù)分塊方法,需要的可以參考一下2022-05-05
Python使用Chrome插件實(shí)現(xiàn)爬蟲過程圖解
這篇文章主要介紹了Python使用Chrome插件實(shí)現(xiàn)爬蟲,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
解決出現(xiàn)Incorrect integer value: '''' for column ''id'' at row 1
這篇文章主要介紹了解決出現(xiàn)Incorrect integer value: '' for column 'id' at row 1的問題的相關(guān)資料,希望通過本文能幫助到大家,讓大家遇到這樣的問題及時(shí)的解決,需要的朋友可以參考下2017-10-10
利用Python實(shí)現(xiàn)快速批量轉(zhuǎn)換HEIC文件
HEIC 是蘋果采用的新的默認(rèn)圖片格式,它能在不損失圖片畫質(zhì)的情況下,減少圖片大小。本篇文章將使用 Python 批量實(shí)現(xiàn) HEIC 圖片文件的格式轉(zhuǎn)換,需要的可以參考一下2022-07-07

