powershell では python の標準出力を受け取ることができるので(過去記事) pywin32 で処理します。
コード
powershell
とりあえず今回は現在開いている Word 文書のテキスト情報を取得します。
activeWord.ps1
function Get-ActiveWordDocumentTextContent {
<#
.SYNOPSIS
pywin32 を利用して現在開いている Word 文書からテキストを抽出する
#>
if ((Get-Process | Where-Object ProcessName -EQ "winword").Count -lt 1) {
# Word が開かれていた場合にのみ起動する
return
}
$pyCodePath = "{0}\activeword2text.py" -f $PSScriptRoot
$command = 'python -B "{0}"' -f $pyCodePath
$result = (Invoke-Expression -Command $command)
return $result
}
python
pip で pywin32 を取り込んでおきます。
pip install pywin32
メイン処理としては呼び出し側の .ps1
スクリプトと同じディレクトリに下記スクリプトを配置します。
activeword2text.py
"""
pywin32を使用して現在開いている Microsoft Word 文書からテキスト情報を抽出する
"""
import win32com.client
import codecs
def main():
wdApp = win32com.client.Dispatch("Word.Application")
if wdApp.Documents.Count < 1:
if not wdApp.Visible:
# 不可視のゾンビプロセスを捕まえてしまった場合は終了させる
wdApp.Quit()
return 0
lines_list = []
content = str(wdApp.ActiveDocument.Content.Text).replace(chr(12),"\r") # 改ページ/改セクションの処理
content_without_BEL = content.replace(chr(7), "") # 表のセル区切りがBEL文字になるので削除
for para in content_without_BEL.split("\r"):
line = str(para).replace(chr(11), "") # 改行(≠改段落)処理
lines_list.append(line)
lines = "\n".join(lines_list)
# コンソール出力時に windows の文字コード(cp932)に変換できない文字を無視しておく
byte = lines.encode("cp932", "ignore")
decoded = byte.decode("cp932")
return decoded
if __name__ == '__main__':
print(main(), end="")
実行
powershell 側から呼び出します。
PS > Get-ActiveWordDocumentTextContent
寿限無寿限無
五劫の擦り切れ
海砂利水魚の
水行末雲来末風来末
……
PS > Get-ActiveWordDocumentTextContent | sv t
PS > $t | where {$_ -match "[ぁ-ん]"}
五劫の擦り切れ
海砂利水魚の
powershell 6 では基盤の .Net Core に [System.Runtime.InteropServices.Marshal]::GetActiveObject()
のメソッドが含まれていないようで困っていました。今回の内容で対処できて一安心です。
(WindowsPowerShell では上記のメソッドで現在開いている Office ソフトを捕まえて処理することができていました→過去記事)
以下、今回の学び:
- pywin32 で Word インスタンスを作成するとき、その時点ですでに文書が開いている場合はその文書がインスタンスとして割り当てられる。
- なので、
ActiveDocument
で捕まえて VBA 文法でアレコレ操作できる。 - スクリプト経由で一通り操作してから手動で Word のウィンドウを閉じるだけでプロセスは解放される。
-
New-Object
で COM オブジェクトを操作する場合とは対照的。この場合は、インスタンス作成のたびに各インスタンスに対して新たにActiveDocument
が生まれるので「現在開いている文書」の処理は困難。
- なので、
- powershell から外部コマンドを
Invoke-Expression
で呼び出すと、powershell はそのプロセスが終了するのを待ってから次の処理を行う。- いわゆる同期処理というシロモノ?
- powershell は外部プロセスからの標準出力を改行区切りの文字列配列として受け取る。
- python 側で
return None
としてもNone
という文字列が出力されたと powershell は解釈する。
- python 側で
Excel に関してはプロセスの解放などが少し異なるようで使いこなせていません。今後の課題です。