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
早速ですがプログラムは以下です。
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()