Python:自動でZoomに参加する

準備

OS:

MacOS Sonoma 14.2.1

ENV:

python 3.12.5
opencv 4.10.0
opencv-python 4.10.0
selenium 4.24.0
PyAutoGui 0.9.54
chromedriver_autoinstaller 0.6.4
Pillow 10.4.0
カーネルに入っていないモジュールをインストールしてから、インポートする。

import subprocess
import importlib
import sys
Required_Modules=['selenium','chromedriver_autoinstaller','pyscreeze','time','datetime','pyautogui','opencv-python','Pillow']
for module in Required_Modules:
    try:
        importlib.import_module(module)
    except ImportError as e:
        print(f'install {module}')
        subprocess.check_call([sys.executable, '-m', 'pip', 'install', module])

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
import chromedriver_autoinstaller
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import NoAlertPresentException
from selenium.common.exceptions import TimeoutException
import pyscreeze
from pyscreeze import ImageNotFoundException
pyscreeze.USE_IMAGE_NOT_FOUND_EXCEPTION = True
import time
import datetime
from sys import exit
import pyautogui as pa
chromedriver_autoinstaller.install()
pa.useImageNotFoundException()

seleniumが制御できるポップアップウィンドウは、"OK"が前提の単純な警告、ユーザーIDやパスワードの入力が必要なprompt alert、サイトを閉じる等の承認を得るconfirmation alertの三つである。
Chromeのサイトで、Developer Toolsからセレクトモードで、サイトのどの部分がどのソースコードで制御されるか確認できる。

逆に言えば、このソースコードに出てこないポップアップウィンドウは、ブラウザが出しているのではなく、起動を要求されているアプリのOSのコントロール下にあるので、Seleniumではコントロールできない。このため、最も簡単な方法として、PyAutoGuiの画面位置確認とクリック機能を使用する。
zoomアプリが制御している"Open zoom.us?"ポップアップウィンドウの"Open zoom.us"ボタンの画像を撮り、zoom_us.pngとして保存する。

zoom.usが起動するクリック位置
zoom_us.png

同様に、パスコードを必要とするミーティングの時には、

Meeting passcodeの記入位置
zoom_pc.png

をzoom_pc.pngとして保存する。
Zoomでは、有料の場合は、ホスト側で、ホストが認証するまで待機室からの入室とパスコード入室が選べるが、無料版ではこのパスコード入室がデフォルトになっている。
最後の入室ボタンの画像も保存する。

zoom_join.png

Python Selenium

seleniumでブラウザを立ち上げ、zoom.us/joinでMeetingIDを入れ、クッキーを承諾するコードは以下のようになる。

def StartZOOM(MeetingID,url):
    
    driver = webdriver.Chrome()
    driver.get(url)
    driver.maximize_window()
    wait = WebDriverWait(driver,60)
    time.sleep(3)
    try:
        WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH,'//button[@id="onetrust-accept-btn-handler"]'))).click()
        print("accepted cookies")
    except Exception as e:
        print('no cookie button')

    target = driver.find_element(By.ID,"join-confno")
    target.send_keys(MeetingID)
    btn = driver.find_element(By.ID,"btnSubmit").click()
    return driver

画像位置の取得

zoom_us.png, zoom_pc.png, zoom_join.pngの画像の位置を取得するコードは以下のようになる。

def FindLoc(pngfile):
    while True:
        try:
            p= pa.locateCenterOnScreen(pngfile,grayscale=False,confidence=0.7)
            if(p is not None):
                print('location:',p)
                break
        except pa.ImageNotFoundException:
            print(" Image not found, will exit")
            sc = pa.screenshot()
            name = 'screenshot%s.png' % (datetime.datetime.now().strftime('%Y-%m%d_%H-%M-%S-%f'))
            sc.save(name)
            exit()
    return p

画像が見つからなかった場合、スクリーンショットを保存する。

ミーティングの時間設定

終了時間が過ぎたら、退出するため、ミーティングの時間を設定する。

def MeetingMinute(MeetingDuration):
    minutes =0
    second = 0
    if MeetingDuration[-1]=='h' :
        minutes=60*float(MeetingDuration[:-1]))
    elif MeetingDuration[-1]=='m':
        minutes= float(MeetingDuration[:-1])
    return 60*minutes

メインのコードでtime.sleep()を使うので、最後に秒に直す。また、実数時間指定は繰り上げて整数にしている。

自動入室

上記の関数を書き込んだファイルをPyZoomとし、PZでインポートし、MeetingID、Meeting Passcodeの有無、MeetingDurationを指定する。入室後はマイクをミュートにし、ミーティング時間が経過したら、退出のプロンプトが出て退出する。

def AutoZoom(MeetingID,MeetingDuration,url='http://zoom.us/join',Passcode=None):

    driver=StartZOOM(MeetingID,url)
    time.sleep(3)
    p_zu=FindLoc('zoom_us.png')
    pa.moveTo(p_zu.x/2,p_zu.y/2)
    pa.click(p_zu.x/2, p_zu.y/2,clicks=2, interval=1)
    time.sleep(3)
    
    if Passcode is not None:
        time.sleep(5)
        p_pc=FindLoc('zoom_pc.png')
        pa.moveTo(p_pc.x/2,p_pc.y/2)
        pa.write(Passcode)
        pa.press('enter')
    else: 
        time.sleep(10)
        p_join=FindLoc('zoom_join.png')
        pa.moveTo(p_join.x/2,p_join.y/2)
        pa.click(p_join.x/2, p_join.y/2,clicks=2, interval=1)

    time.sleep(10)
    # Mute own mic
    pa.hotkey('command','shift','A')
    time.sleep(3)
    pa.hotkey('enter')

    time.sleep(MeetingMinute(MeetingDuration))

    #Leaving prompt
    pa.hotkey('command','q')
    time.sleep(3)
    pa.hotkey('enter')
    driver.close()

pyAutoGuiで得られている位置を2で割っているのは、Mac上では位置が2倍で出力されるからである。
main で、AutoZoomを呼び出す。

import PyZoom as PZ

MeetingID='XXX XXXX XXXX'
Passcode='XXXXXX'

MeetingDuration='0.5h'
PZ.AutoZoom(MeetingID,MeetingDuration,Passcode=Passcode)

いいなと思ったら応援しよう!