UWSC を Python で置換しよう（3）チートシート[1]

# はじめに

「UWSC を Python で置換しよう」第三回です。今回はUWSCのスクリプトを置き換える説明をする予定でしたが、その前に、各モジュールのよく使う機能のチートシートを用意しました。
<font color=red>なにぶん、調べながら書いているため、間違っている点もあるかと思います。
その場合は、ビシバシ編集リクエストをください(汗</font>

前回は
[UWSC を Python で置換しよう（2）関数置き換え](https://qiita.com/hirohiro77/items/1aaa7717a4411fbcfc7b)
次回は
[UWSC を Python で置換しよう（4） チートシート[2]](https://qiita.com/hirohiro77/items/0b7fa5bea1024b39af6b)

# 解説するモジュールと用途一覧

--チートシート[1]で解説するもの
-  PyAutoGUI (画像判定 / マウス・キーボード操作)
-  OpenCV (画像処理)<font color=red>※PyAutoGUI内部から使われる機能のみ解説</font>
-  PyWin32 (Win32Api/Win32COM OLE/COMオブジェクト操作)
-  BeautifulSoup (html/xmlパーサー)
-  PyAudio (オーディオ操作)
-  SpeechRecognition (音声認識)
-  eSpeak (音声合成)

--チートシート[2]で解説するもの
-  Selenium (ブラウザ操作)
-  xlrd , xlwt (Excel 読み書き)
-  OpenPyXL (Excel 読み書き)
-  ReportLab (PDF 読み書き)
-  PyInstaller (EXE 形式単一実行ファイル生成)
-  ConfigParser (cfg/ini 形式の読み込み)

----

# PyAutoGui [[github]](https://github.com/asweigart/pyautogui)

```cheat01.py
#ロードモジュール
# -*- coding: utf-8 -*-
import os,sys,re,time,subprocess
import pyautogui

#カレントマウス座標(tuple型)
CUR_MOUSE_POS = pyautogui.position()
X,Y = CUR_MOUSE_POS
#※変数型がわからなくなったら print(type(変数))で確認

#画面解像度(tuple型)
RESOLUTION = pyautogui.size()
X,Y = RESOLUTION

#画面の色深度(2/4/8/16/24/32bitの識別)
im  = pyautogui.screenshot()
colordepth = im.dtype

#座標の存在確認
if pyautogui.onScreen(x, y):
    print("x,yは画面内にあります")

#デフォルト待ち時間(sec)
pyautogui.PAUSE = 2.5

# Fail-Safeモードの有効化(失敗しても中断しなくなる、FailSafeExceptionをキャッチできる)
pyautogui.FAILSAFE = True

# マウス座標移動(絶対座標と移動時間を指定)
pyautogui.moveTo(x, y, duration=num_seconds)

# マウス座標移動(相対座標と移動時間を指定)
pyautogui.moveRel(xOffset, yOffset, duration=num_seconds)

# Drag&DropのDrag位置指定(絶対座標と移動時間を指定,ボタン指定)
pyautogui.drag(x, y, duration=num_seconds, button='right')  

# Drag&DropのDrop位置指定(絶対座標と移動時間を指定)
pyautogui.dragTo(x, y, duration=num_seconds)

# Drag&DropのDrop位置指定(相対座標と移動時間を指定)
pyautogui.dragRel(xOffset, yOffset, duration=num_seconds)

# マウスクリック(絶対座標とクリック回数、クリック間隔、ボタンを指定)
pyautogui.click(x=moveToX, y=moveToY, clicks=num_of_clicks,interval=secs_between_clicks, button='left')
pyautogui.click(x=moveToX, y=moveToY, clicks=num_of_clicks,interval=secs_between_clicks, button='right')
pyautogui.click(x=moveToX, y=moveToY, clicks=num_of_clicks,interval=secs_between_clicks, button='middle')

# マウスクリック(絶対座標を指定)
pyautogui.rightClick(x=moveToX, y=moveToY)
pyautogui.middleClick(x=moveToX, y=moveToY)
pyautogui.doubleClick(x=moveToX, y=moveToY)
pyautogui.tripleClick(x=moveToX, y=moveToY)

# マウスホイール(ノッチ数と絶対座標を指定[座標は省略可])
#垂直ホイール
pyautogui.scroll(amount_to_scroll,x=moveToX,y=moveToY)
#水平ホイール
pyautogui.hscroll(amount_to_scroll,x=moveToX,y=moveToY) 

# マウスホールド/リリース(絶対座標とボタンを指定)
pyautogui.mouseDown(x=moveToX, y=moveToY, button='left')
pyautogui.mouseUp(x=moveToX, y=moveToY, button='left')

# タイピング(日本語未対応:文字列と入力間隔を指定)
pyautogui.typewrite('Hello world!\n', interval=secs_between_keys)

# タイピング(キー単位で入力、ファンクションキー押下可能、入力間隔も指定)
pyautogui.typewrite(['a', 'b', 'c', 'left', 'backspace', 'enter', 'f1'], interval=secs_between_keys)

# ショートカットキー(特定キーの同時押しを指定)
pyautogui.hotkey('ctrl', 'a')
pyautogui.hotkey('ctrl', 'c')
pyautogui.hotkey('ctrl', 'v')

# キーホールド/リリース(キー名を指定)
pyautogui.keyDown(key_name)
pyautogui.keyUp(key_name)

# キー押下(キー名を指定)
pyautogui.press(key_name)

# キー名一覧
['\t', '\n', '\r', ' ', '!', '"', '#', '$', '%', '&', "'", '(',
')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`',
'a', 'b', 'c', 'd', 'e','f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
'accept', 'add', 'alt', 'altleft', 'altright', 'apps', 'backspace',
'browserback', 'browserfavorites', 'browserforward', 'browserhome',
'browserrefresh', 'browsersearch', 'browserstop', 'capslock', 'clear',
'convert', 'ctrl', 'ctrlleft', 'ctrlright', 'decimal', 'del', 'delete',
'divide', 'down', 'end', 'enter', 'esc', 'escape', 'execute', 'f1', 'f10',
'f11', 'f12', 'f13', 'f14', 'f15', 'f16', 'f17', 'f18', 'f19', 'f2', 'f20',
'f21', 'f22', 'f23', 'f24', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9',
'final', 'fn', 'hanguel', 'hangul', 'hanja', 'help', 'home', 'insert', 'junja',
'kana', 'kanji', 'launchapp1', 'launchapp2', 'launchmail',
'launchmediaselect', 'left', 'modechange', 'multiply', 'nexttrack',
'nonconvert', 'num0', 'num1', 'num2', 'num3', 'num4', 'num5', 'num6',
'num7', 'num8', 'num9', 'numlock', 'pagedown', 'pageup', 'pause', 'pgdn',
'pgup', 'playpause', 'prevtrack', 'print', 'printscreen', 'prntscrn',
'prtsc', 'prtscr', 'return', 'right', 'scrolllock', 'select', 'separator',
'shift', 'shiftleft', 'shiftright', 'sleep', 'space', 'stop', 'subtract', 'tab',
'up', 'volumedown', 'volumemute', 'volumeup', 'win', 'winleft', 'winright', 'yen',
'command', 'option', 'optionleft', 'optionright']


#メッセージボックス(Info)
pyautogui.alert(text='メッセージ',title='タイトル',button='ボタンの文字')

#メッセージボックス(Confirm)
result = pyautogui.confirm(text='メッセージ', 'タイトル', buttons=['選択1', '選択2'])

#メッセージボックス(Prompt[Input])
result = pyautogui.prompt(text='メッセージ', 'タイトル',default='デフォルト値')

#メッセージボックス(Password[Input])
result = pyautogui.password(text='メッセージ', 'タイトル',default='デフォルト値', mask='*')

# スクリーンショット(全体)
pyautogui.screenshot(Filename)

# スクリーンショット(範囲)
pyautogui.screenshot(Filename,region=(x1,y1,x2,y2))

# 画像識別(指定画像の発見位置の左,上,幅,高さ、が取得できる)
pos = pyautogui.locateOnScreen('looksLikeThis.png')

# 認識後Centerで中央座標を取ることができる、locateCenterOnScreenと同等
centerpos = pyautogui.center(pos)

# 画像識別(グレイスケール化検索,色相を気にせず形状で判別する場合高速化できる)
pos = pyautogui.locateOnScreen('looksLikeThis.png',grayscale=True)

# 画像識別(検索範囲指定)
pos = pyautogui.locateOnScreen('looksLikeThis.png',region=(rx1,ry1,rx2,ry2))

# あいまい画像識別(confidenceで閾値が指定できる、95%合致なら0.95)
pos = pyautogui.locateOnScreen('looksLikeThis.png',confidence=0.95)

# あいまい画像識別(検索範囲指定、confidenceは閾値)
pos = pyautogui.locateOnScreen('looksLikeThis.png',region=(rx1,ry1,rx2,ry2),confidence=0.95)

# 画面認識(画面上に複数ある場合全て検出)
# 順次処理の場合
for pos in pyautogui.locateAllOnScreen('looksLikeThis.png')
    print(pos)

# リスト化して指定個数目(num)を処理する場合
poslist = list(pyautogui.locateAllOnScreen('looksLikeThis.png'))
x,y,h,w = poslist[num]

# 画像識別(指定画像の発見位置の中央X,Y、が取得できる)
# グレースケール(grayscale)、検索範囲(region=)や、あいまい画像認識(confidence)は同様に使える
pos = pyautogui.locateCenterOnScreen('looksLikeThis.png')

# 指定座標のRGB値を取得する(tuple型)
rgb = pyautogui.pixel(x,y)
r,g,b = rgb

# 指定座標のRGB値がマッチするか
if pyautogui.pixelMatchesColor(x, y, (r,g,b)):
    print('Color Matched !!')

# 指定座標のRGB値がマッチするか(誤差指定[tolerance(%)])
if pyautogui.pixelMatchesColor(x, y, (r,g,b),tolerance=num):
    print('Color Matched !!')
```

# PyWin32 [[github]](https://github.com/mhammond/pywin32)

pywin32には、以下のモジュールが含まれます。基本的にWindowsのアプリケーションハンドラ、プロセスID、ウインドウ名、を使った操作やレジストリ、設定書き換えなどはこの辺りを利用します

- win32api (Windows API)
- win32gui (Windows GUI)
- win32ui (Windows UI)
- win32con (Windows Console)
- win32com (Windows OLE/COM Object)
- win32prosess (Windows Prosess)
- win32service (Windows Service)
- win32evtlog (Windows Event Log)
- win32file (Windows Files Api)
- win32pdhutil (Windows Performance Data Helpers Utility)
- win32ras (Windows Remote Access Service)
- wincerapi (Windows CE Remote API)

----
- 利用例

```cheat02.py
# -*- coding: utf-8 -*-
import win32api
import win32gui
import win32con
import win32com.client

##ディスク容量の表示
disks = win32api.GetDiskFreeSpaceEx()
for i in disks:
    r = round(i/(1024**3),1)
    print(str(r)+" GB")

##OKウィンドウの表示
a = win32gui.MessageBox(None,'Contents','Title',1)
print(a) # ok -> 1, cancel -> 2

##IE実行
ie = win32com.client.Dispatch("InternetExplorer.Application")
ie.Visible = True
ie.Addressbar = True
ie.Navigate("https://www.google.com")

##WScript.Shell経由でメモ帳起動
wshShell = win32com.client.Dispatch("WScript.Shell")
wshShell.Run("notepad.exe")

##COMオブジェクト経由でExcel操作 (この辺りは)
xlApp = win32com.client.Dispatch("Excel.Application")
#Excelを表示させる
xlApp.Visible = 1
#Excelファイルを開く
wb = xlApp.Workbooks.Open("開くファイル")
#指定したシートを操作可能にする
sheet = wb.Worksheets("開きたいシート名(左から1,2,3..のように数字で選択でも可)")
#指定したシートを選択状態にする。
sheet.Activate() 
#セルにデータを入力する
sheets.Range("A4").Value = "入力データ"
#行の高さ、列の幅を変更する
sheet.Rows("1:1").RowHeight = 25
sheet.Columns("A:A").ColumnWidth = 15
#上書き保存
wb.Save()
#名前をつけて保存
wb.SaveAs("保存するファイルパスと名前")
#Excelファイルを閉じる。
wb.Close()
```

- 起動したアプリの画面サイズ変更

```cheat02-1.py
# -*- coding: utf-8 -*-
import os,sys,re,time,subprocess
import win32api
import win32gui
import win32con
import win32process

#プロセスIDからハンドル取得
def get_hwnds_for_pid (pid):
    def callback (hwnd, hwnds):
        if win32gui.IsWindowVisible (hwnd) and win32gui.IsWindowEnabled (hwnd):
            _, found_pid = win32process.GetWindowThreadProcessId (hwnd)
            if found_pid == pid:
                hwnds.append (hwnd)
    return True
  
    hwnds = []
    win32gui.EnumWindows (callback, hwnds)
    
    return hwnds

## 起動したアプリの画面サイズ変更
child_process = subprocess.Popen(r'c:\windows\system32\notepad.exe')
time.sleep(2)
pid = child_process.pid

for hwnd in get_hwnds_for_pid(pid):
    if hwnd == 0:
        print("Windows Target Application not found!")
    else:
        #サイズ指定(リサイズ)
        win32gui.MoveWindow(hwnd, 100, 100, 500, 500, True)
        #最大化
        win32gui.ShowWindow(hwnd, win32con.SW_MAXIMIZE)
        time.sleep(1)
        #閉じる
        win32gui.SendMessage(hwnd,win32con.WM_CLOSE,0,0)
```

# BeautifulSoup4 [[HP]](https://www.crummy.com/software/BeautifulSoup/)

htmlを処理するのに使うが、昨今Bot対策が行われているため、 `urllib3 + BeautifulSoup`
よりも `selenium + BeautifulSoup` で使われることが多い

```cheat03.py
# -*- coding: utf-8 -*-
import re
import urllib3
from bs4 import BeautifulSoup
import certifi

# アクセスするURL
url = "https://www.yahoo.co.jp/"

#httpsの証明書検証を実行している
http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED',ca_certs=certifi.where())

#httpsの証明書検証を実行しない
#http = urllib3.PoolManager()

r = http.request('GET',url)

# htmlをBeautifulSoupで扱う
soup = BeautifulSoup(r.data, 'html.parser')

title_tag = soup.title
title     = title_tag.string

# タイトル要素を出力
print (title_tag)

# タイトルを文字列を出力
print (title)

# 全てのaタグ
for atag in soup.find_all("a"):
    print ("ALL : ")
    print (atag.string)
    print (atag.get("href"))

# 全てのaタグ(条件あり)
for ataglimit in soup.find_all("a", attrs={"class": "link", "href": "/link"}):
    print ("Limit : ")
    print (ataglimit.string)
    print (ataglimit.get("href"))

# 正規表現で検索 BタグやBODYタグなどbで始まるタグをすべて取得
for btag in soup.find_all(re.compile("^b")):
    print (btag.string)

# ”link”を含むhref属性を持っているタグをすべて取得
for altag in soup.find_all(href=re.compile("link")):
    print (altag.get("href"))

# タグの中の文字列に"hello"を含むAタグをすべて取得
for hatag in soup.find_all("a", text=re.compile("hello")):
    print (hatag.get("href"))

# cssセレクタを使ったタグの取得
for catag in soup.select('a[href^="http://"]'):
    print (catag.get("href"))
```

# PyAudio [[HP]](http://people.csail.mit.edu/hubert/pyaudio/)

音声の録音、再生を行います。音声フォーマットについては、基本PCM/WAVになりますが、Audio Codecも利用できるのでMP3/MP4(m4a)/VP9なども使えます。

```cheat04.py
import pyaudio

#録音
def RecWavFile(FileName,Record_Seconds):
    audiobuff = 1024
    FORMAT = pyaudio.paInt16
    CHANNELS = 1 #モノラル
    RATE = 44100 #サンプルレート（録音の音質）
    p = pyaudio.PyAudio()
    stream = p.open(format = FORMAT,channels = CHANNELS,rate = RATE,input = True,frames_per_buffer = audiobuff)
    print("Now Recording...")
    all = []
    for i in range(0, int(RATE / audiobuff * Record_Seconds)):
        data = stream.read(audiobuff) #音声を読み取って、
        all.append(data) #データを追加
    print("Finished Recording.")
    
    stream.close()
    p.terminate()
    wavFile = wave.open(FileName, 'wb')
    wavFile.setnchannels(CHANNELS)
    wavFile.setsampwidth(p.get_sample_size(FORMAT))
    wavFile.setframerate(RATE)
    wavFile.writeframes(b"".join(all))
    wavFile.close()

#再生
def PlayWavFie(Filename):
    try:
        wf = wave.open(Filename, "r")
    except FileNotFoundError: #ファイルが存在しなかった場合
        print("[Error 404] No such file or directory: " + Filename)
        return 0

    p = pyaudio.PyAudio()
    stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),channels=wf.getnchannels(),rate=wf.getframerate(),output=True)

    audiobuff = 1024
    data = wf.readframes(audiobuff)
    while data != '':
        stream.write(data)
        data = wf.readframes(audiobuff)
    stream.close()
    p.terminate()

if __name__ is "__main__":
    #録音
    RecWavFile("sample.wav",2)
    #再生
    PlayWavFie("sample.wav")
```

# SpeechRecognition [[github]](https://github.com/Uberi/speech_recognition)

Speech Recognition は音声認識を行います。
次の音声エンジンをサポートしています。

- Sphinx
- Google Speech Recognition
- Google Cloud Speech API
- Wit.ai
- Microsoft Bing Voice Recognition
- Microsoft Azure Speech
- Houndify API
- IBM Speech to Text
- Snowboy Hotword Detection （works offline）

```cheat05.py
import speech_recognition

#音声入力デバイス一覧
def MicCheck():
    for index, name in enumerate(speech_recognition.Microphone.list_microphone_names()):
        print("Microphone with name \"{1}\" found for `Microphone(device_index={0})`".format(index, name))

r = speech_recognition.Recognizer()
mic = speech_recognition.Microphone()

#ファイルから入力の場合
#with speech_recognition.AudioFile('sample.wav') as source:
#    audio = r.record(source)

#入力デバイスから直接の場合
with mic as source:
    r.adjust_for_ambient_noise(source)
    audio = r.listen(source)

##Sphinxの場合
#print(r.recognize_sphinx(audio))

##Google Speech Recognitionの場合
#短ければキーなしでもいける
print(r.recognize_google(audio,language='ja-JP'))
#長時間の場合はAPIキーが必要
#print(r.recognize_google(audio,key="GOOGLE_SPEECH_RECOGNITION_API_KEY",language='ja-JP'))

#Google Cloud Speech APIの場合
#GOOGLE_CLOUD_SPEECH_CREDENTIALS = r"jsonファイルの中身をペースト"
#print(r.recognize_google_cloud(audio,credentials_json=GOOGLE_CLOUD_SPEECH_CREDENTIALS))

##Wit.aiの場合（日本語未対応）
#WIT_AI_KEY = "INSERT WIT.AI API KEY HERE"
#print(r.recognize_wit(audio, key=WIT_AI_KEY))

##Microsoft Bing Voice Recognitionの場合
#BING_KEY = "INSERT BING API KEY HERE" 
#print(r.recognize_bing(audio, key=BING_KEY))

##Microsoft Azure Speech
#AZURE_SPEECH_KEY = "INSERT AZURE SPEECH API KEY HERE"
#print(r.recognize_azure(audio, key=AZURE_SPEECH_KEY))

##Houndify APIの場合
#HOUNDIFY_CLIENT_ID = "INSERT HOUNDIFY CLIENT ID HERE"  
#HOUNDIFY_CLIENT_KEY = "INSERT HOUNDIFY CLIENT KEY HERE"  
#print(r.recognize_houndify(audio, client_id=HOUNDIFY_CLIENT_ID,client_key=HOUNDIFY_CLIENT_KEY))

##IBM Speech to Textの場合
#IBM_USERNAME = "INSERT IBM SPEECH TO TEXT USERNAME HERE"
#IBM_PASSWORD = "INSERT IBM SPEECH TO TEXT PASSWORD HERE"
#print(r.recognize_ibm(audio, username=IBM_USERNAME, password=IBM_PASSWORD))
```

# eSpeak [[github]](https://github.com/GikonyoBrian/speake3)

音声合成は外部APIのeSpeakを利用する

```cheat06.py
import speake3

engine = speake3.Speake()
engine.set('voice', 'en') # 言語指定
engine.set('speed', '107') # 再生速度
engine.set('pitch', '99') # ピッチ
engine.say("Hello world!") # 音声合成
engine.talkback() # 再生
```

# さいごに

自分用の意味合いで書いているもののため、微妙な書き方になっているところがあります。ご容赦ください・・・

次回は [UWSC を Python で置換しよう（4） チートシート[2]](https://qiita.com/hirohiro77/items/0b7fa5bea1024b39af6b)