はじめに
クリップボード操作をするPythonライブラリはpyperclip
が有名だが、このライブラリは文字ベースでしか扱えず、リンク付きのHTML形式で扱うことができない。この記事ではwin32clipboard
を使ってHTML形式のクリップボードを扱う方法をまとめる。シチュエーションはSharepoint等のURLコピーしたクリップボードデータを、リンク付きのHTMLデータとして加工することを想定する。Windows限定であることは注意。
目次
クリップボードのHTML形式ってどういうフォーマット?
URLコピーしたデータを、Excel、PowerPointやTeams等に貼り付けると文字リンク付きのデータになる。この文字リンク付きのクリップボードデータがどういうものか?は、クリップ見え窓を使うと確認できる。
https://qiita.com/timeline
をHTML形式にすると下記のようになっている。本体は<a href= ~ </a>
の部分で、<!--StartFragment-->
と<!--EndFragment-->
で囲まれている。先頭の4行の10桁の数字は、それぞれのオフセット位置を10進数で表記したものである。このフォーマットの詳細はMicrosoftのサイトにまとまっている。
https://learn.microsoft.com/ja-jp/windows/win32/dataxchg/html-clipboard-format
Version:0.9
StartHTML:0000000105
EndHTML:0000000244
StartFragment:0000000141
EndFragment:0000000208
<html>
<body>
<!--StartFragment--><a href="https://qiita.com/timeline">タイムライン - Qiita</a><!--EndFragment-->
</body>
</html>
win32clipboardを使う。
では、本題のwin32clipboard
について。pip install pywin32
でモジュールをインストール。名称が違うので注意。
クリップボード取得
win32clipboard.GetClipboardData()
でクリップボード取得する。前後にOpen/Closeの処理が必要。この操作で、テキストベースのクリップデータを取得できる。
import win32clipboard
win32clipboard.OpenClipboard()
clipdata = win32clipboard.GetClipboardData()
win32clipboard.CloseClipboard()
#クリップデータ確認
print(clipdata)
クリップボード設定
win32clipboard.SetClipboardData()
で設定する。クリップボード取得と同じく前後にOpen/Closeの処理が必要。また設定前の情報をクリアするためEmptyも実施する。Emptyは必須でないが、実施しておいた方が無難。パラーメータを設定することで、クリップボードに設定するフォーマットを選択できる。win32clipboard.CF_UNICODETEXT
とすることで日本語のマルチバイトをTEXT形式で設定ができる。
import win32clipboard
#clipdataにクリップボードに設定したい文字列を入れる。
clipdata = 'テスト'
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, clipdata.encode('UTF-8'))
win32clipboard.CloseClipboard()
HTML形式でクリップボードに設定する場合はCF_HTML
というパラメータがないので、代わりに
win32clipboard.RegisterClipboardFormat('HTML Format')
を設定する。設定するHTMLデータは クリップボードのHTML形式ってどういうフォーマット?のフォーマットで記述が必要。「 https://qiita.com/ 」のリンク文字を 「Qiitaのリンク」という文字にする例は下記の通り。clipboard_to_html_format()
は各種ヘッダやオフセットの計算をする自作関数。
import win32clipboard
#------------------------------
# HTML形式に変換する
#------------------------------
def clipboard_to_html_format(in_html_data):
#HTML形式用の前後データ
header = 'Version:0.9\nStartHTML:0000000000\nEndHTML:0000000000\nStartFragment:0000000000\nEndFragment:0000000000\n'
html_start = '<html><body><!--StartFragment-->'
html_end = '<!--EndFragment--></body></html>'
#オフセット計算
offset_s_html = '{:010d}'.format(len(header)) # StartHTML
offset_e_html = '{:010d}'.format(len(header + html_start + in_html_data + html_end)) # EndHTML
offset_s_frag = '{:010d}'.format(len(header + html_start)) # StartFragment
offset_e_frag = '{:010d}'.format(len(header + html_start + in_html_data)) # EndFragment
#オフセットデータ書き換え
header = 'Version:0.9\nStartHTML:'+offset_s_html+'\nEndHTML:'+offset_e_html+'\nStartFragment:'+offset_s_frag+'\nEndFragment:'+offset_e_frag+'\n'
#結合
return header + html_start + in_html_data + html_end
#------------------------------
# main
#------------------------------
#「https://qiita.com/」のリンク文字を「Qiitaのリンク」とする
clipdata = '<a href="https://qiita.com/">Qiitaのリンク</a>'
#html形式に変更
clipdata = clipboard_to_html_format(clipdata)
# html形式で設定
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardData(win32clipboard.RegisterClipboardFormat('HTML Format'), clipdata.encode('UTF-8'))
win32clipboard.CloseClipboard()
TEXT形式とHTML形式両方設定したい場合はwin32clipboard.SetClipboardData()
を2行並列して記述すればよい。
戻る
コピーしたURLリンクを加工する例。
コピーしたURLを下記のように 「リンク」と「URL」併記したクリップボードに加工する例。
👆のPythonコードはこちら。
import win32clipboard #クリップボード処理 pip install pywin32
import urllib.parse #URLのデコード処理
#------------------------------
#URLの日本語デコード
#------------------------------
def url_decode(in_url):
return urllib.parse.unquote(in_url)
#------------------------------
# HTML形式に変換する
#------------------------------
def clipboard_to_html_format(in_html_data):
#HTML形式用の前後データ
header = 'Version:0.9\nStartHTML:0000000000\nEndHTML:0000000000\nStartFragment:0000000000\nEndFragment:0000000000\n'
html_start = '<html><body><!--StartFragment-->'
html_end = '<!--EndFragment--></body></html>'
#オフセット計算
offset_s_html = '{:010d}'.format(len(header)) # StartHTML
offset_e_html = '{:010d}'.format(len(header + html_start + in_html_data + html_end)) # EndHTML
offset_s_frag = '{:010d}'.format(len(header + html_start)) # StartFragment
offset_e_frag = '{:010d}'.format(len(header + html_start + in_html_data)) # EndFragment
#オフセットデータ書き換え
header = 'Version:0.9\nStartHTML:'+offset_s_html+'\nEndHTML:'+offset_e_html+'\nStartFragment:'+offset_s_frag+'\nEndFragment:'+offset_e_frag+'\n'
#結合
return header + html_start + in_html_data + html_end
#------------------------------
# クリップボードに設定
# cliptype :'HTML'(HTML形式とTEXT形式)/'TEXT'(TEXT形式のみ)
# clipdata_text:TEXT形式データ
# clipdata_html:HTML形式データ
#------------------------------
def clipboard_set(clipdata_text, clipdata_html='', cliptype='TEXT'):
win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
if cliptype == 'HTML':
win32clipboard.SetClipboardData(win32clipboard.RegisterClipboardFormat('HTML Format'), clipdata_html.encode('UTF-8'))
win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, clipdata_text.encode('UTF-8'))
elif cliptype == 'TEXT':
win32clipboard.SetClipboardData(win32clipboard.CF_UNICODETEXT, clipdata_text.encode('UTF-8'))
else:
print('The format is not defined.')
win32clipboard.CloseClipboard()
#------------------------------
# クリップボードから取得
# cliptype :'HTML'(HTML形式)/'TEXT'(TEXT形式のみ)
#------------------------------
def clipboard_get(cliptype='TEXT'):
win32clipboard.OpenClipboard()
if cliptype == 'HTML':
clipdata = win32clipboard.GetClipboardData(win32clipboard.RegisterClipboardFormat('HTML Format'))
elif cliptype == 'TEXT':
clipdata = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
else:
clipdata = 'The format is not defined.'
win32clipboard.CloseClipboard()
return clipdata
#------------------------------
# main
#------------------------------
#クリップボードから取得し日本語デコード
url_data = url_decode(clipboard_get())
#下記のようになるようHTML記述
#---------------
#リンク
#http://xxxxxxxx
#---------------
htmldata = '<a href="'+url_data+'">リンク<br>'+url_data+'</a><br>'
#クリップボード設定
clipboard_set(url_data, clipboard_to_html_format(htmldata), 'HTML')