This article teaches you how to use Python to realize the most effective real-time monitoring of shear board.

Posted by ravnen on Tue, 10 Sep 2019 14:17:02 +0200

Preface

When browsing the web pages on the Internet, it is unavoidable to use copy and paste to see good content, but the content we see, the content we want and the content we actually paste are often inconsistent. Data acquisition begins with replication and ends with pasting. Then the question arises, what is the operation of the system in the middle, and how can we control it?

Life is short, I use python. After consulting the relevant information, I find that there are many different ways of implementation, such as using built-in ctypes module, tk module, third-party module such as cross-platform pyperclip module, clipboard module, pywin. Win32 clipboard module, etc. Most of them have encapsulated concise and easy-to-use high-level interface, which is convenient. We use it directly.

Based on the psychology of obsessive-compulsive disorder, this paper analyses and compares several mainstream methods, carries out source code analysis and read-write performance test one by one, and finally chooses the fastest one to make a real-time clipping board monitoring small case for your reference.

The functions of the small case are as follows:

  1. Real-time monitoring of ctrl+c clipboard writing events removes specified characters or text from the clipboard, such as suffix () targeting of some text.
  2. Intelligent text substitution using regularization, such as converting code in Python 2 format to Python 3 format.

Way 1: Call a third-party pyperclip module

In [1]: import pyperclip

In [2]: data = pyperclip.paste()

In [3]: data
Out[3]: "print 'Hello World'\r\n--------\r\n Copyright Statement: CSDN Blogger「...」Original articles, follow CC 4.0 BY-SA Copyright Agreement, reproduced please attach a link to the original source and this statement.\r\n Links to the original text: https://blog.csdn.net/.../article/details/..."

In [4]: data = data[7:12]

In [5]: pyperclip.copy(data)

In [6]: pyperclip.paste()
Out[6]: 'Hello'

The underlying principle: Call the ctypes.windll.user32 interface in the built-in ctypes module to write, and the code of the pandas package is the same, code location: pandas.io.clipboard.windows, code reference as follows

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

Advantages: Cross-platform, convenient and concise interface calls

Disadvantage: The data format of the clipboard only supports utf-8 text, and the speed of frequent reading and writing is slow.

Mode 2: Call the third party Win32 clipboard module

In [1]: import win32clipboard
 ...:
 ...: def clipboard_get():
 ...:  """Getting Clipboard Data"""
 ...:  win32clipboard.OpenClipboard()
 ...:  data = win32clipboard.GetClipboardData()
 ...:  win32clipboard.CloseClipboard()
 ...:  return data
 ...:
 ...: def clipboard_set(data):
 ...:  """Setting Clipboard 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 Copyright Statement: CSDN Blogger「...」Original articles, follow CC 4.0 BY-SA Copyright Agreement, reproduced please attach a link to the original source and this statement.\r\n Links to the original text: https://blog.csdn.net/.../article/details/..."

In [4]: clipboard_set(data[7:12])
Out[4]: True

In [5]: clipboard_get()
Out[5]: 'Hello'

The underlying principle: C source encapsulation, python interface calls as follows

def GetClipboardData(*args, **kwargs): # real signature unknown  
  pass

def SetClipboardData(*args, **kwargs): # real signature unknown
  pass

Advantages: Native C package has the fastest speed of reading and writing, and supports multiple data formats of clipboard.

Disadvantage: Only for windows platform, high-frequency reading and writing errors need to be handled carefully, data formats other than utf-8 format need to be familiar with winuser.h library design and write by itself.

Method 3: Call the built-in tkinter module

In [1]: from tkinter import *
 ...:
 ...: r = Tk()

In [2]: data = r.clipboard_get()

In [3]: data
Out[3]: "print 'Hello World'\n--------\n Copyright Statement: CSDN Blogger「...」Original articles, follow CC 4.0 BY-SA Copyright Agreement, reproduced please attach a link to the original source and this statement.\n Links to the original text: https://blog.csdn.net/.../article/details/..."

In [4]: r.clipboard_append(data[7:12])

In [5]: r.clipboard_get()
Out[6]: 'Hello'

Note: After win10 system test, it is found that only the data of clipboard can be obtained by using tkinter module, but not written to clipboard. When clipboard_board method is called externally, the process of system clipboard will be locked by tk takeover. At this time, when other applications press ctrl+v, the pasted application will be directly stuck, or The content is empty after pasting.

If the data is written to the clipboard through the Tk() object, the system clipboard data will be updated only by setting the delay destruction Tk object. Otherwise, the content will still be empty (the clipboard will still be empty if the frequency of reading within 0.2 seconds is set, which is very chicken rib):

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()

The underlying principle: C source encapsulation, python interface calls as follows

# Read clipboard data:
_tkinter.tkapp('clipboard', 'get')

# Write the clipboard data:
_tkinter.tkapp('clipboard', 'append')

Test results of reading and writing speed of shear board

Small real-time monitoring cases:

import win32clipboard
import re
import time


def clipboard_get():
    """Getting Clipboard Data"""
    win32clipboard.OpenClipboard()
    data = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
    win32clipboard.CloseClipboard()
    return data


def clipboard_set(data):
    """Setting Clipboard Data"""
    win32clipboard.OpenClipboard()
    win32clipboard.EmptyClipboard()
    win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, data)
    win32clipboard.CloseClipboard()


# Initialization of substitution character lists is faster than regular single character substitution using the replace function
char_list = [('(', '('),
             (')', ')'),
             ('"', '"'),
             ('"', '"'),
             (''', '\''),
             (''', '\''),
             ('print ', 'print '),
             ('Copyright Statement: CSDN', 'Copyright Statement: CSDN'),
             ]

# Precompiled regular replacement matching expression
# Matching text of print function in Python 2 format
sub_print = re.compile(r'\bprint\s+(.+)')
# Match the copyright declaration suffix text of csdn replication
sub_csdn = re.compile(r'—+\s+Copyright Statement: CSDN.*\s+Original link.*')


# Specify scenario sub substitution function: print function in Python 2 format is replaced by Python 3 format
def sub_fn(s):
    return 'print(' + s.group(1).strip() + ')\r\n'


# If there are no characters to be replaced, then return None. If there are any characters to be replaced, then perform the replacement operation. First replace the character list, then execute reg.sub(sub_fn, txt).
def char_replace_reg_sub(txt):
    new_txt = txt

    # Judge the characters in the character list one by one, replace them if they are in the text, return None if they are not in, and no replacement operation is needed.
    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)
    # Use regular re.sub for scenario substitution
    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():
    """Background scripts: every 0.2 In seconds, read the clipboard text, check whether there are specified characters or strings, and if so, perform substitutions"""
    # The latest_txt stores the last clipboard text, and the initialization value only reads and replaces the paste function once more.
    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 stores the current clipboard text
        txt = clipboard_get()

        # If there is any change in the content of the clipboard compared with the previous one, the content judgment will be made. If the specified character is found in the clipboard, the replacement will be performed.
        if txt != recent_txt:
            # print(f'txt:{txt}')
            new_txt = char_replace_reg_sub(txt)  # No substrings to be replaced were found, returning None

            if new_txt is not None:
                clipboard_set(new_txt)
                # Update recent_txt to replace the text so that it can be compared with the txt clipboard text next time to determine whether the content is updated or not.
                recent_txt = new_txt

        # Detection interval (0.2 seconds delay)
        time.sleep(0.2)


if __name__ == '__main__':
    main()

Operation effect:

-----------------------------------------------------------------------------------------
[Copy text]:

print 'Hello World' \r\n--------\r\n Copyright Statement: CSDN Blogger「...」Original articles, follow CC 4.0 BY-SA Copyright Agreement, reproduced please attach a link to the original source and this statement.\r\n Links to the original text: https://blog.csdn.net/.../article/details/...)
-----------------------------------------------------------------------------------------
[After replace:]:

print('Hello World')
-----------------------------------------------------------------------------------------

Reference link:

Microsoft Development Document: https://docs.microsoft.com/zh-cn/windows/win32/dataxchg/using-the-clipboard?

Stack Overflow: https://stackoverflow.com/questions/579687/how-do-i-copy-a-string-to-the-clipboard-on-windows-using-python

Topics: Python Windows