LoginSignup
7

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-09-15

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

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

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('左下の座標を設定します。5秒後にマウス位置座標を取得します。', 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('右上の座標を設定します。5秒後にマウス位置座標を取得します。', 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()

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7