Python에서 Teams 휴대폰 작업을 자동화해보기

하고 싶은 일



하고 싶은 것은 간단합니다.
Teams 통화의 전송처를, 출근시에 「통화 그룹 또는 대리인」으로 설정해, 퇴근시는 「음성 메일」에 되돌린다, 라고 하는 것.
실제로는 계정마다 각 팀분, 이 조작이 필요하게 되기 때문에, 그것이 매일이 되면 부담도 큰 셈입니다.

요점은 유수전이므로, 아래의 동영상으로 해설하고 있는 방법으로도 실현할 수 있을 것 같습니다만, Teams(라고 하는지 마이크로소프트 제품 전반)에 거기까지 자세하지 않은 데다, 마이크로소프트의 파트너 회사에 (듣)묻지 못하고, 잘 알 수 있습니다 아니.

Teams의 설정을 커멘드로 실시한다면, PowerShell로부터 Connect-MicrosoftTeams 로 접속해 고뇨고뇨 하는 것이 정평이라고 생각합니다만, 전송처에 상당하는 오브젝트/프로퍼티를 찾을 수 없습니다. 찾는 방법이 나쁠 뿐일지도.

치마치마 조사하는 것보다, 서버로 써 버리는 것이 빠르 것 같기 때문에, Python/Flask 베이스로 「Teams 유수전 전환 어플리」를 만들어 보았습니다.

구현



로그인



Teams는 데스크톱 버전도 있지만 Selenium에서 웹 버전 Teams에 로그인합니다.
driver.get('https://teams.microsoft.com')
WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located)
driver.implicitly_wait(30)
driver.find_element_by_id('i0116').send_keys(user_id)  # ユーザID
driver.find_element_by_id('idSIButton9').click()       # 次へ
driver.find_element_by_id('i0118').send_keys(passwd)   # パスワード
time.sleep(3)
driver.find_element_by_id('idSIButton9').click()       # サインイン

2요소 인증



2요소 인증이 필수인 계정에서는 pyotp 으로 일회용 비밀번호를 생성합니다.
import pyotp

totp = pyotp.TOTP(secret_key)
driver.find_element_by_id('idTxtBx_SAOTCC_OTC').send_keys(totp.now())  # コード
driver.find_element_by_id('idSubmit_SAOTCC_Continue').click()  # 検証

오류시 재시도



만약 이런 화면이 되면 재시도를 클릭합니다.

oops_btn = driver.find_elements_by_class_name('oops-button')
if len(oops_btn) > 0:
    driver.execute_script('arguments[0].click()', oops_btn[0])

통화 설정 화면



통화 설정 화면을 표시합니다.
driver.find_element_by_id('settings-menu-button').click()  # 設定
driver.switch_to.active_element.send_keys(Keys.ENTER)
driver.find_element_by_xpath('//*[@id="options-dialog-focus-default"]/div/span[text()="通話"]').click()  # 通話
driver.find_element_by_id('immediate-dropdown-btn').click()  # 転送先ドロップダウン

입력에 따라 전송 대상을 전환합니다.
if voice_flag:
    driver.find_element_by_xpath('/html/body/ul/li/a[text()="ボイス メール"]').click()  # 転送先をボイスメールに設定
    print('Switch to enable voice mail')
else:
    driver.find_element_by_xpath('/html/body/ul/li/a[text()="' + forward + '"]').click()  # 転送先を通話グループ/代理人に設定
    print('Switch to disable voice mail')

예외 처리



뭔가 이상이 있으면 스크린 샷을 찍고 스택 추적의 문자 정보를 겹쳐서 프런트 엔드에 반환합니다.
다시 시도할지 수동으로 조작할지 여부는 사용자가 웹 응용 프로그램에서 응답합니다.
이미지의 가공은 opencv-python 에서 실시했습니다.
import cv2
import traceback

except Exception as e:
    driver.save_screenshot(screenshot_file)
    img = cv2.imread(screenshot_file)
    exc = traceback.format_exc()
    for i, line in enumerate(exc.split('\n')):
        cv2.putText(img, line, (10, 100 + i * 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 160, 240), 1, cv2.LINE_AA)
    cv2.imwrite(screenshot_file, img)
    print(exc)

성공/실패를 판정하고 이라 스토야 에서 픽업한 투과 이미지를 마스크 처리하여 스크린샷과 합성합니다.

이미지의 합성은, 이쪽의 기사를 참고로 했습니다.

실패 알림



Incoming Webhook 에서 웹 후크를 만들고 curl 명령으로 알렸습니다.

Bash 스크립트
FLAG=$1
while read CLIENT; do
    if /usr/local/bin/foo.py $CLIENT $FLAG; then
        echo "$CLIENT($FLAG) Success."
    else
        if [ $FLAG -eq 0 ]; then
            TEXT="留守電の解除に失敗しました。クライアントは「$CLIENT」です。"
        else
            TEXT="留守電の登録に失敗しました。クライアントは「$CLIENT」です。"
        fi
        curl -X POST -d '{"text":"'$TEXT'"}' https://foo.webhook.office.com/webhookb2/XXXXXX
    fi
done <<EOF
foo
bar
baz
qux
quux
corge
grault
EOF

좋은 웹페이지 즐겨찾기