Google Photos の「容量解放」操作を自動実行

【2020/11/12更新】
[Google フォトのストレージに関する変更](https://support.google.com/photos/answer/10100180)
「2021 年 6 月 1 日以降、高画質とエクスプレス画質のコンテンツは Google アカウントの保存容量を使用するようになります。」だそうで、アップロード後「容量を解放」を行って高画質に変換すれば無制限に保存できていたものができなくなるようです。残念。

【2020/03/08更新】ログイン画面が元に戻ったようなので、以前のものと変更時のもの、両方に対応できるよう修正

【2020/02/29更新】2月21日辺りからログイン画面に変更があったようなので対応

- Password入力のinputタグ内の変更に対応

#概要

「[Google Photos API を使用した画像の自動アップロード](https://qiita.com/inasawa/items/e5362dec4bd45d6900f7)」の仕組みで自動撮影した画像の自動アップロードを行っており、当初は手動での容量解放を月１回程度の間隔で行えば十分でしたが、撮影画像のサイズ・枚数を増加したことで容量解放の実施間隔を短くする必要があるため自動化を行いました。

Google Photos API では容量解放を行う手段が提供されていないため、Selenium を使用して Google Photos の設定画面で「容量を解放」ボタンをクリックする方式です。

環境は Docker で作成し、cron 設定で１日１回実行するようにしていますが「ストレージを復元できるのは 1 日 1 回」ということで、きっちり２４時間間隔で実行すると圧縮操作が正常に行われる日とエラーになる日を交互に繰り返すことになります。

##環境

- Raspberry Pi 3B
- Raspbian のバージョンは以下の通り

```shell-session
$ lsb_release -a
No LSB modules are available.
Distributor ID:	Raspbian
Description:	Raspbian GNU/Linux 9.4 (stretch)
Release:	9.4
Codename:	stretch
```

- Docker

```shell-session
$ docker version
Client:
 Version:           18.06.0-ce
 API version:       1.38
 Go version:        go1.10.3
 Git commit:        0ffa825
 Built:             Wed Jul 18 19:19:46 2018
 OS/Arch:           linux/arm
 Experimental:      false

Server:
 Engine:
  Version:          18.06.0-ce
  API version:      1.38 (minimum version 1.12)
  Go version:       go1.10.3
  Git commit:       0ffa825
  Built:            Wed Jul 18 19:15:34 2018
  OS/Arch:          linux/arm
  Experimental:     false
```

```docker:Dockerfile
FROM arm32v7/python:3.7.3-alpine3.9
RUN  apk --update add tzdata coreutils chromium chromium-chromedriver && \
     cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime && \
     apk del tzdata && \
     rm -rf /var/cache/apk/* && \
     pip install selenium

# 日本語の画面キャプチャーを行う場合は以下の日本語フォントのインストール
# あるいはホスト側の /usr/share/fonts を共有する
#RUN mkdir /noto
#ADD https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip /noto
#WORKDIR /noto
#RUN unzip NotoSansCJKjp-hinted.zip && \
#    mkdir -p /usr/share/fonts/noto && \
#    cp *.otf /usr/share/fonts/noto && \
#    chmod 644 -R /usr/share/fonts/noto/ && \
#    /usr/bin/fc-cache -fv
#WORKDIR /
#RUN rm -rf /noto

COPY google_photos_recover_storage.py google_photos_params.py /
COPY crontab /var/spool/cron/crontabs/root

ENTRYPOINT ["crond", "-f", "-d", "8"]
```

```:crontab
# m h  dom mon dow   command
30 09 * * * python /google_photos_recover_storage.py
```

Docker Image の作成、コンテナの作成、実行は以下の通り。

```shell-session
$ docker build -t google-photos-recover-storage-arm32v7 .
$ docker create --restart=always \
  --name google-photos-recover-storage \
  --log-opt max-size=100k \
  --log-opt max-file=3 \
  google-photos-recover-storage-arm32v7
$ docker start google-photos-recover-storage
```
Chromium および Python モジュールのバージョン

```shell-session
$ apk list -I chromium*
chromium-72.0.3626.121-r0 armv7 {chromium} (BSD) [installed]
chromium-chromedriver-72.0.3626.121-r0 armv7 {chromium} (BSD) [installed]

$ pip list
Package    Version
---------- -------
pip        19.1.1 
selenium   3.141.0
setuptools 41.0.1 
urllib3    1.25.3 
wheel      0.33.3 
```

#実行結果

今回のプログラムは以下のような画面操作を自動実行しています。

１. メールアドレスを入力
　　Google Photosの設定画面にアクセスするとログイン画面が表示されます。
![google_photos_20190622-231807_1_LoginId.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133064/27b35612-788a-6a2a-7d9f-de4abcd769c2.png)

２. パスワードを入力
![google_photos_20190622-231807_2_Password.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133064/52e41016-c7cf-9c73-9453-d0054b2ff8dd.png)

３.（ケース１） 「容量を解放」ボタンをクリック
![google_photos_20190622-231807_3_Recover_Storage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133064/bc03cced-eff6-9119-6c50-7c80a619d3c5.png)

３.（ケース２） 「容量を解放」ボタンなし
　　圧縮対象なし（全て圧縮済み）の場合は「容量を解放」ボタンは存在しない
![google_photos_20190623-022935_3_Recover_Storage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133064/3c0d4009-dc20-017c-5f72-b8689d78e22a.png)

３.（ケース３） 圧縮中
　　「容量を解放」ボタンは表示されておらず、クリック不可
![google_photos_20190623-093652_3_Recover_Storage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133064/bb141987-bb40-9372-6123-14f11a2ec881.png)

４. 「圧縮」ボタンをクリック
![google_photos_20190622-231807_4_Compress-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133064/dd2e00ae-a5be-5f03-728c-810be7adada5.png)

５. 「圧縮」ボタンをクリック
![google_photos_20190622-231807_5_Compress-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133064/02c08aa0-8698-6c7a-4e31-426ffbe04ed7.png)

６. 「OK」ボタンをクリック
　　正常処理では前画面で終了ですが、１日に複数回実行すると以下の確認画面が表示されます。
![google_photos_20190622-231807_6_Trouble_compressing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133064/98c89be6-682c-ed43-ce20-5dfef4edfc6d.png)

#Pythonプログラム

```python:google_photos_params.py
# ログイン用の Google Account 
google_loginid  = 'Google Account Mail Address'
google_password = 'password'
```

```python:google_photos_recover_storage.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import logging
import argparse
import os
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options
from selenium.common.exceptions import NoSuchElementException, ElementNotInteractableException

import google_photos_params


def save_screenshot(name):
    if args.screenshot is not None:
        driver.save_screenshot(os.path.join(args.screenshot, 'google_photos_{}_{}.png'.format(screenshot_time, name)))


def google_photos_login():
    logger.info('Input [LoginId]')
    """
    <input id="Email" type="email" value="" spellcheck="false" name="Email" placeholder="メールアドレスまたは電話番号" autofocus="">
    <input id="next" name="signIn" class="rc-button rc-button-submit" type="submit" value="次へ">
    """
    element = driver.find_element_by_id('Email')
    logger.debug(element.get_attribute('outerHTML'))
    save_screenshot('1_LoginId')
    element.send_keys(google_photos_params.google_loginid)

    logger.info('Click [次へ]')
    element = driver.find_element_by_id('next')
    logger.debug(element.get_attribute('outerHTML'))
    element.click()

    logger.info('Input [Password]')
    """
    <input id="Passwd" name="Passwd" type="password" placeholder="パスワード" class="" autofocus="">
    <input id="signIn" name="signIn" class="rc-button rc-button-submit" type="submit" value="ログイン">
    or
    <input autofocus="" class="mCAa0e" id="password" jsname="pRFXed" name="Passwd" spellcheck="false" type="password"/>
    <input class="MK9CEd MVpUfe" id="submit" jsaction="aJAbCd:zbvklb" jscontroller="rrJN5c" jsname="M2UYVd" type="submit" value="ログイン"/>
    """
    submit_id = 'signIn'
    try:
        element = driver.find_element_by_id('Passwd')
    except NoSuchElementException as e:
        logger.info(e)
        element = driver.find_element_by_id('password')
        submit_id = 'submit'
    except Exception as e:
        logger.error(e)
    logger.debug(element.get_attribute('outerHTML'))
    save_screenshot('2_Password')
    element.send_keys(google_photos_params.google_password)

    logger.info('Click [ログイン]')
    element = driver.find_element_by_id(submit_id)
    logger.debug(element.get_attribute('outerHTML'))
    element.click()


def google_photos_compress():
    """
    <div jsname="an3wJb" class="IGdgBf">元のサイズ （空き容量 xx.x GB）</div>
    """
    logger.info(driver.find_element_by_css_selector('div.IGdgBf').text)

    logger.info('Click [容量を解放]')
    """
    ケース１：圧縮対象あり
        「容量を解放」ボタン表示
    <div class="hjVFKe" jscontroller="wSpjSb" jsaction="aPFThb:J9cGQc">
      <div class="DNAsC X7j0Rc SuJ5zd" jscontroller="v4VSme" jsaction="click:npT2md;">
        <div class="VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-k8QpJ nCP5yc NXvGIf ndDvOd" jscontroller="Pgu0ub" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="LgbsSe" jslog="9755; track:JIbuQc">
          <span jsname="V67aGc" class="VfPpkd-vQzf8d" aria-hidden="true">容量を購入</span>
          <a class="WpHeLc" href="https://www.google.com/settings/storage/?hl=ja#upgrade" aria-label="容量を購入" jsname="hSRGPd"/>
        </div>
      </div>
     <div jscontroller="hFNQpd" jsaction="JIbuQc:e0XiEb" class="X7j0Rc">
        <button class="VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-INsAgc Rj2Mlf LEWgre" jscontroller="Yo9Rze" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jslog="17339; track:JIbuQc">
          <span jsname="V67aGc" class="VfPpkd-vQzf8d">容量を解放</span>
        </button>
        <span class="EG8nQb">写真と動画を高画質に圧縮しています...</span>
      </div>
    </div>
    """
    """
    ケース２：圧縮対象なし（全て圧縮済み）
        「容量を解放」ボタンは存在しない
        -> NoSuchElementException
    <div class="hjVFKe" jscontroller="wSpjSb" jsaction="aPFThb:J9cGQc">
      <div class="DNAsC X7j0Rc SuJ5zd" jscontroller="v4VSme" jsaction="click:npT2md;">
        <div class="VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-k8QpJ nCP5yc NXvGIf ndDvOd" jscontroller="Pgu0ub" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="LgbsSe" jslog="9755; track:JIbuQc">
          <span jsname="V67aGc" class="VfPpkd-vQzf8d" aria-hidden="true">容量を購入</span>
          <a class="WpHeLc" href="https://www.google.com/settings/storage/?hl=ja#upgrade" aria-label="容量を購入" jsname="hSRGPd"/>
        </div>
      </div>
    </div>
    """
    """
    ケース３：圧縮中
        「容量を解放」ボタンは表示されておらず、クリック不可
        -> ElementNotInteractableException
    <div class="hjVFKe n09fhe" jscontroller="wSpjSb" jsaction="aPFThb:J9cGQc">
        <div class="DNAsC X7j0Rc SuJ5zd" jscontroller="v4VSme" jsaction="click:npT2md;">
            <div class="VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-k8QpJ nCP5yc NXvGIf ndDvOd" jscontroller="Pgu0ub" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="LgbsSe" jslog="9755; track:JIbuQc">
                <span jsname="V67aGc" class="VfPpkd-vQzf8d" aria-hidden="true">容量を購入</span>
                <a class="WpHeLc" href="https://www.google.com/settings/storage/?hl=ja#upgrade" aria-label="容量を購入" jsname="hSRGPd"></a>
            </div>
        </div>
        <div jscontroller="hFNQpd" jsaction="JIbuQc:e0XiEb" class="X7j0Rc">
            <button class="VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-INsAgc Rj2Mlf LEWgre" jscontroller="Yo9Rze" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jslog="17339; track:JIbuQc">
                <span jsname="V67aGc" class="VfPpkd-vQzf8d">容量を解放</span>
            </button>
            <span class="EG8nQb">写真と動画を高画質に圧縮しています...</span>
        </div>
    </div>
    """
    element = driver.find_element_by_css_selector('div.hjVFKe')
    logger.debug(element.get_attribute('outerHTML'))
    logger.info(element.text)
    save_screenshot('3_Recover_Storage')
    button = element.find_element_by_css_selector('button.VfPpkd-LgbsSe.VfPpkd-LgbsSe-OWXEXe-INsAgc.Rj2Mlf')
    button.click()

    logger.info('Click [圧縮]その１')
    """
    <div class="g3VIld V639qd OFqiSb Up8vH J9Nfi iWO5td" jscontroller="N5Lqpc" jsaction="rcuQ6b:rcuQ6b;Vws5Ae:JIbuQc;DahzHe:U8CY9;vbKBWe:IrPMqd;WB41gf:iuJMzb;eAkbGb:PA60s;CCI6n:zjRS5; keydown:I481le; clickonly:cOuCgd;qUuEUd:H8nU8b;j9grLe:H8nU8b;HUObcd:H8nU8b; mousedown:H8nU8b; touchstart:H8nU8b; focus:H8nU8b; blur:H8nU8b;LNlWBf:.CLIENT;touchmove:.CLIENT" jsshadow="" role="alertdialog" ve-stop-target-search="true" jslog="17342; track:impression" data-position="eEPege" data-cancelids="IbE0S,TvD9Pc" aria-labelledby="dwrFZd0" aria-describedby="dwrFZd1">
      <div tabindex="0" aria-hidden="true" class="pw1uU" jsaction="focus:.CLIENT"/>
      <div jsname="r4nke" class="R6Lfte tOrNgd qRUolc">
        <div jsname="YASyvd" class="PNenzf" role="heading" aria-level="1" id="dwrFZd0">元のファイルを高画質に圧縮します</div>
        <div jsaction="JIbuQc:DJ6zke" class="OllbWe" jsname="c6xFrd">
          <button class="VfPpkd-LgbsSe ksBjEc kHssdc" jscontroller="Yo9Rze" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="LgbsSe" data-id="IbE0S" jslog="8838; track:JIbuQc">
            <span jsname="V67aGc" class="VfPpkd-vQzf8d">キャンセル</span>
          </button>
          <button class="VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-k8QpJ nCP5yc kHssdc HvOprf" jscontroller="Yo9Rze" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="LgbsSe" data-id="EBS5u" autofocus="" jslog="17395; track:JIbuQc">
            <span jsname="V67aGc" class="VfPpkd-vQzf8d">圧縮</span>
          </button>
        </div>
      </div>
      <span jsslot="" jsname="bN97Pc" class="PbnGhe oJeWuf fb0g6" id="dwrFZd1">
        <div class="gVzVIc">写真や動画を元の解像度から高画質に圧縮することで、1.6 GB の保存容量を開放します<ul><li>また、Blogger などの Google サービスにアップロードしたファイルも圧縮されます</li><li>Google ドライブ</li>にアップロードしたファイルには影響しません</ul><a href="https://support.google.com/photos/?p=convert" class="fWsKP" jscontroller="C01I8e" jsaction="click:KySCff(preventDefault=true)">詳細</a></div>
      </span>
      <div jsaction="JIbuQc:DJ6zke" class="XfpsVe J9fJmf" jsname="c6xFrd">
        <button class="VfPpkd-LgbsSe ksBjEc kHssdc" jscontroller="Yo9Rze" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="LgbsSe" data-id="IbE0S" jslog="8838; track:JIbuQc">
          <span jsname="V67aGc" class="VfPpkd-vQzf8d">キャンセル</span>
        </button>
        <button class="VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-k8QpJ nCP5yc kHssdc HvOprf VfPpkd-ksKsZd-mWPk3d-OWXEXe-AHe6Kc-XpnDCe" jscontroller="Yo9Rze" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="LgbsSe" data-id="EBS5u" autofocus="" jslog="17395; track:JIbuQc">
          <span jsname="V67aGc" class="VfPpkd-vQzf8d">圧縮</span>
        </button>
      </div>
      <div tabindex="0" aria-hidden="true" class="pw1uU" jsaction="focus:.CLIENT"/>
    </div>
    """
    element = driver.find_element_by_css_selector('div.g3VIld.V639qd.OFqiSb.Up8vH.J9Nfi.iWO5td')
    logger.debug(element.get_attribute('outerHTML'))
    logger.info(element.text)
    save_screenshot('4_Compress-1')

    button = driver.find_element_by_css_selector('button.VfPpkd-ksKsZd-mWPk3d-OWXEXe-AHe6Kc-XpnDCe')
    # ここでは button.click() が使えないため、ActionChains を使用
    action = webdriver.common.action_chains.ActionChains(driver)
    action.move_to_element(button)
    action.send_keys(Keys.ENTER)
    action.perform()

    logger.info('Click [圧縮]その２')
    """
    <div class="g3VIld V639qd OFqiSb Up8vH Whe8ub J9Nfi iWO5td" jscontroller="N5Lqpc" jsaction="rcuQ6b:rcuQ6b;Vws5Ae:JIbuQc;DahzHe:U8CY9;vbKBWe:IrPMqd;WB41gf:iuJMzb;eAkbGb:PA60s;CCI6n:zjRS5; keydown:I481le; clickonly:cOuCgd;qUuEUd:H8nU8b;j9grLe:H8nU8b;HUObcd:H8nU8b; mousedown:H8nU8b; touchstart:H8nU8b; focus:H8nU8b; blur:H8nU8b;LNlWBf:.CLIENT;touchmove:.CLIENT" jsshadow="" role="alertdialog" ve-stop-target-search="true" jslog="17397; track:impression" data-position="eEPege" data-cancelids="IbE0S,TvD9Pc" aria-describedby="dwrFZd2">
      <div tabindex="0" aria-hidden="true" class="pw1uU" jsaction="focus:.CLIENT"/>
      <span jsslot="" jsname="bN97Pc" class="PbnGhe oJeWuf fb0g6" id="dwrFZd2">
        <div class="gVzVIc">写真や動画の圧縮には 1 時間以上かかる場合があり、操作は元に戻せません</div>
      </span>
      <div jsaction="JIbuQc:DJ6zke" class="XfpsVe J9fJmf" jsname="c6xFrd">
        <button class="VfPpkd-LgbsSe ksBjEc kHssdc" jscontroller="Yo9Rze" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="LgbsSe" data-id="IbE0S" jslog="8838; track:JIbuQc">
          <span jsname="V67aGc" class="VfPpkd-vQzf8d">キャンセル</span>
        </button>
        <button class="VfPpkd-LgbsSe VfPpkd-LgbsSe-OWXEXe-k8QpJ nCP5yc kHssdc HvOprf VfPpkd-ksKsZd-mWPk3d-OWXEXe-AHe6Kc-XpnDCe" jscontroller="Yo9Rze" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="LgbsSe" data-id="EBS5u" autofocus="" jslog="17395; track:JIbuQc">
          <span jsname="V67aGc" class="VfPpkd-vQzf8d">圧縮</span>
        </button>
      </div>
      <div tabindex="0" aria-hidden="true" class="pw1uU" jsaction="focus:.CLIENT"/>
    </div>
    """
    element = driver.find_element_by_css_selector('div.g3VIld.V639qd.OFqiSb.Up8vH.Whe8ub.J9Nfi.iWO5td')
    logger.debug(element.get_attribute('outerHTML'))
    logger.info(element.text)
    save_screenshot('5_Compress-2')

    button = element.find_element_by_css_selector('button.VfPpkd-LgbsSe.VfPpkd-LgbsSe-OWXEXe-k8QpJ.nCP5yc')
    button.click()

    #
    # 正常時は上記処理で設定画面に戻るが、１日複数回圧縮を行おうとした場合は、以下の画面が表示される
    #
    logger.info('Click [OK] if [ファイルを圧縮できませんでした。]')
    """
    <div class="g3VIld V639qd r01sH Up8vH Whe8ub J9Nfi iWO5td" jscontroller="N5Lqpc" jsaction="rcuQ6b:rcuQ6b;Vws5Ae:JIbuQc;DahzHe:U8CY9;vbKBWe:IrPMqd;WB41gf:iuJMzb;eAkbGb:PA60s;CCI6n:zjRS5; keydown:I481le; clickonly:cOuCgd;qUuEUd:H8nU8b;j9grLe:H8nU8b;HUObcd:H8nU8b; mousedown:H8nU8b; touchstart:H8nU8b; focus:H8nU8b; blur:H8nU8b;LNlWBf:.CLIENT;touchmove:.CLIENT" jsshadow="" role="alertdialog" ve-stop-target-search="true" jslog="17398; track:impression" data-position="eEPege" data-cancelids="IbE0S" aria-describedby="dwrFZd3">
      <div tabindex="0" aria-hidden="true" class="pw1uU" jsaction="focus:.CLIENT"/>
      <span jsslot="" jsname="bN97Pc" class="PbnGhe oJeWuf fb0g6" id="dwrFZd3">
        <div class="gVzVIc">ファイルを圧縮できませんでした。ストレージを復元できるのは 1 日 1 回だけです。<a href="https://support.google.com/photos/?p=convert" jscontroller="C01I8e" jsaction="click:KySCff(preventDefault=true)" class="fWsKP">詳細</a></div>
      </span>
      <div jsaction="JIbuQc:DJ6zke" class="XfpsVe J9fJmf" jsname="c6xFrd">
        <button class="VfPpkd-LgbsSe ksBjEc kHssdc HvOprf VfPpkd-ksKsZd-mWPk3d-OWXEXe-AHe6Kc-XpnDCe" jscontroller="Yo9Rze" jsaction="click:cOuCgd; mousedown:UX7yZ; mouseup:lbsD7e; mouseenter:tfO1Yc; mouseleave:JywGue; touchstart:p6p2H; touchmove:FwuNnf; touchend:yfqBxc; touchcancel:JMtRjd; focus:AHmuwe; blur:O22p3e; contextmenu:mg9Pef;" jsname="LgbsSe" data-id="EBS5u" autofocus="">
          <span jsname="V67aGc" class="VfPpkd-vQzf8d">OK</span>
        </button>
      </div>
      <div tabindex="0" aria-hidden="true" class="pw1uU" jsaction="focus:.CLIENT"/>
    </div>
    """
    try:
        element = driver.find_element_by_css_selector('div.g3VIld.V639qd.r01sH.Up8vH.Whe8ub.J9Nfi.iWO5td')
        logger.debug(element.get_attribute('outerHTML'))
        logger.info(element.text)
        save_screenshot('6_Trouble_compressing')

        button = element.find_element_by_css_selector('button.VfPpkd-LgbsSe.ksBjEc.kHssdc.HvOprf')
        button.click()

        # Click後の画面遷移待ち
        time.sleep(1)
    except NoSuchElementException:
        # NoSuchElementException の場合は正常終了
        pass

    save_screenshot('End')


parser = argparse.ArgumentParser(description='Google Photos Recover Storage')
parser.add_argument('--screenshot', help='save screenshot to specified directory')
parser.add_argument('--debug', action='store_true', help='set logging level DEBUG')

args = parser.parse_args()

handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
handler.setLevel(logging.DEBUG)
logger = logging.getLogger(__name__)
if args.debug:
    logger.setLevel(logging.DEBUG)
else:
    logger.setLevel(logging.INFO)
logger.addHandler(handler)

options = Options()

# User-Agentが通常起動時とHeadless起動時で違い、それによってログイン画面も違ってくるため
# 通常起動時で調査する場合もHeadless起動時のUser-Agentを指定する
# 通常起動時
# Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36
# Headless起動時
# Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/75.0.3770.100 Safari/537.36

options.add_argument('--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/75.0.3770.100 Safari/537.36')
options.add_argument('--no-sandbox')
options.add_argument('--headless')
options.add_argument('--window-size=1100,1100')
driver = webdriver.Chrome(options=options)
driver.implicitly_wait(5)

screenshot_time = time.strftime('%Y%m%d-%H%M%S')
url = 'https://photos.google.com/settings'
try:
    logger.info('Access ['+url+']')
    driver.get(url)

    google_photos_login()
    google_photos_compress()

except NoSuchElementException as e:
    save_screenshot('End_NoSuchElementException')
    logger.error(e)

except ElementNotInteractableException as e:
    save_screenshot('End_ElementNotInteractableException')
    logger.error(e)

except Exception as e:
    save_screenshot('End_Exception')
    logger.error(e)

driver.close()
driver.quit()
```