Youtube「広告をスキップ」を自動でクリック（python）

PythonがWindows上できちんと動くことに今更ながら気づき、ちょっと楽しくなっております。

Youtubeの「広告をスキップ」を自動でクリックするプログラムを書いてみました。
画面内で「広告をスキップ」が出てくる領域を指定して、OCR処理で文字列化して、
「広告をスキップ」が出るまで、待ち続けて、出たら、自動クリックするプログラムです。

　画面クリックは、「pyautogui」
　文字列OCRは、「Tesseract-OCR」、「pyocr」
　GUI化は、「PySimpleGUI」
を利用していています。

といいますか、これらのツールの利用方法の勉強ですね。
各ツールをインストールしてください。

参考にさせていただきましたページ
[Tesseract、pyocr]
https://qiita.com/ku_a_i/items/93fdbd75edacb34ec610
[pyautogui]
https://slash-z.com/python-pyautogui/
[pysimplegui]
https://www.pysimplegui.org/en/latest/
https://www.pysimplegui.org/en/latest/cookbook/#the-thread-based-solution

早速ですがプログラムは以下です。

```shell: koukoku_click.py
import pyautogui as pg
import time
import pyocr
import PySimpleGUI as sg
from PIL import Image, ImageEnhance
import os
import threading

def koukoku_click(mouse_x, mouse_y, mouse_x2, mouse_y2, window):
    #Tesseract
    #Pah設定
    TESSERACT_PATH = 'C:\\Users\\username\\AppData\\Local\\Tesseract-OCR' #インストールしたTesseract-OCRのpath
    TESSDATA_PATH = 'C:\\Users\\username\\AppData\\Local\\Tesseract-OCR\\tessdata' #tessdataのpath

    os.environ["PATH"] += os.pathsep + TESSERACT_PATH
    os.environ["TESSDATA_PREFIX"] = TESSDATA_PATH

    #OCRエンジン取得
    tools = pyocr.get_available_tools()
    if len(tools) == 0:
        print("No OCR tool found")
        sys.exit(1)
    tool = tools[0]
    langs = tool.get_available_languages()
    ## 'script/Japanese'を設定
    lang = langs[2]
    
    #OCRの設定
    builder = pyocr.builders.TextBuilder(tesseract_layout=6)

    #「広告をクリック」の左下へ移動して
    pg.moveTo(x=mouse_x, y=mouse_y, duration=0.5, logScreenshot=False)

    #マウスを揺らしながら、「広告をクリック」が出てないかOCRして確認
    while True:
        #マウスを大きく動かしたら、処理をやめることにして、ループから出る
        mouse_new_x, mouse_new_y = pg.position()
        if ( ( abs(mouse_x - mouse_new_x) > 40 ) or ( abs(mouse_y - mouse_new_y) > 40 ) ):
            break
        #マウスを揺らして、「広告をクリック」をハッキリと表示させる
        pg.moveTo(x=mouse_x+10, y=mouse_y, duration=0.5, logScreenshot=False)
        pg.moveTo(x=mouse_x, y=mouse_y, duration=0.5, logScreenshot=False)
        #「広告をクリック」の画像部分を切り抜き
        img = pg.screenshot(region=(mouse_x, mouse_y2, mouse_x2 - mouse_x , mouse_y - mouse_y2))

        #OCR前の処理
        img_g = img.convert('L') #Gray変換
        enhancer= ImageEnhance.Contrast(img_g) #コントラストを上げる
        img_con = enhancer.enhance(2.0) #コントラストを上げる

        #画像からOCRで日本語を読んで、文字列として取り出す
        txt_pyocr = tool.image_to_string(img_con , lang=lang, builder=builder)

        #半角スペースを消す（不必要なスペースの検知を読み飛ばし）
        txt_pyocr = txt_pyocr.replace(' ', '')

        #「広告をスキップ」が検知されたら、自動クリックする
        if(txt_pyocr == '広告をスキップ'):
            pg.leftClick(mouse_x, mouse_y)

        #ちょっと待って、無限ループ
        time.sleep(1)

    #マウスを動かした場合に、このループを終了して、PySimpleGUIのWindowにイベント通知
    window.write_event_value('-END_OF_KOUKOKU_CLICK-', '広告クリックのループを終了')

if __name__ == "__main__":
    #PySimpleGUIでの画面作り
    sg.theme('DarkAmber')   # デザインテーマの設定

    layout = [  [sg.Text('左下(x,y)=('), sg.Input(size=4, key='-LEFTBOTTOM_X-'),sg.Text(','),sg.Input(size=4, key='-LEFTBOTTOM_Y-'),sg.Text(')'),sg.Button('左下座標取得'),
                 sg.Text('右上(x,y)=('), sg.Input(size=4, key='-RIGHTTOP_X-'),sg.Text(','),sg.Input(size=4, key='-RIGHTTOP_Y-'),sg.Text(')'),sg.Button('右上座標取得'),
                ], 
                [sg.Button('スタート', key='-START-')],
                [sg.Text('座標を設定してください', key='-MESSAGE-')],            
            ]

    #マウス位置標情報の初期値
    ( mouse_x, mouse_y ) = ( 0 , 0 )
    ( mouse_x2, mouse_y2 ) = ( 0 , 0 )

    #PySimpleGUIでのWindow
    window = sg.Window('広告スキップのクリック', layout)

    while True:
        event, values = window.read()
        if event == sg.WIN_CLOSED:
            break
        elif event == '左下座標取得':
            window_x, window_y = window.current_location()
            
            sg.popup_annoying('左下の座標を設定します。５秒後にマウス位置座標を取得します。', location=(window_x, window_y + 150))
            sg.popup_annoying('5秒', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
            sg.popup_annoying('4秒', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
            sg.popup_annoying('3秒', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
            sg.popup_annoying('2秒', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
            sg.popup_annoying('1秒', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
            mouse_x, mouse_y = pg.position()
            window['-LEFTBOTTOM_X-'].Update(f'{mouse_x}')
            window['-LEFTBOTTOM_Y-'].Update(f'{mouse_y}')
            sg.popup_annoying('0秒 設定しました', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
        elif event == '右上座標取得':
            window_x, window_y = window.current_location()

            sg.popup_annoying('右上の座標を設定します。５秒後にマウス位置座標を取得します。', location=(window_x, window_y + 150))
            sg.popup_annoying('5秒', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
            sg.popup_annoying('4秒', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
            sg.popup_annoying('3秒', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
            sg.popup_annoying('2秒', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
            sg.popup_annoying('1秒', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))
            mouse_x2, mouse_y2 = pg.position()
            window['-RIGHTTOP_X-'].Update(f'{mouse_x2}')
            window['-RIGHTTOP_Y-'].Update(f'{mouse_y2}')
            sg.popup_annoying('0秒 設定しました', auto_close=True, auto_close_duration=1.0, button_type=5, location=(window_x + 50, window_y + 150))        
        elif event == '-START-':
            mouse_x = int(values['-LEFTBOTTOM_X-'])
            mouse_y = int(values['-LEFTBOTTOM_Y-'])
            mouse_x2 = int(values['-RIGHTTOP_X-'])
            mouse_y2 = int(values['-RIGHTTOP_Y-'])
            if not ( mouse_x < mouse_x2 and mouse_y > mouse_y2):
                window['-MESSAGE-'].Update(f'座標が適切に設定されていません')
                break
            window['-MESSAGE-'].Update(f'「広告をスキップ」の自動クリック処理中：時々マウスを揺らします')
            #「広告をスキップ」を自動でクリックする処理は、別スレッドで実施
            threading.Thread(target=koukoku_click, args=(mouse_x, mouse_y, mouse_x2, mouse_y2, window,), daemon=True).start()
            window['-START-'].Update(f'処理中', disabled=True)
        elif event == '-END_OF_KOUKOKU_CLICK-':
            window['-MESSAGE-'].Update(f'「広告をスキップ」の自動クリック処理を停止しています')
            window['-START-'].Update(f'スタート', disabled=False)

    window.close()
```