敵のいない勉強部屋

日々学んだことや感じたことを書きます

英語字幕DB作成への道_Flask編① (QuickStart)

seleniumで字幕データをダウンロードすることができるようになったので、
後はこれをAPIで呼び出せるようにしたい。

ということで前々から気になっていたFlaskを使ってみることにしました。
flask.palletsprojects.com

評判通りとてもシンプル!
今までDjangoを使っていたので、導入の簡単さに驚きました。

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"

今回はAPIは少ししか書かない予定なので、
これくらいシンプルなのがちょうどよいです!

今日も新しい発見ができてよかった!

英語字幕DB作成への道_Selenium編⑩ (selenium-wire)

DisneyPlusの動画を再生すると、ブラウザが裏側で .vtt という字幕ファイルをダウンロードします。

このファイルを手動でダウンロードするには、開発者ツールを開いて、Networkタブを開いて、
.vtt のURLをコピーして、wgetする必要があります。

なんとかこれを自動化したい。
ChromeOptionsやDesiredCapabilitiesで頑張ればなんとかできそうではあったのですが、
ChromeDriverのドキュメントがあまり親切ではなくて使い方がよくわかりませんでした。

そうしてネットの海をさまようことになったのですが、
そこで素晴らしいライブラリを見つけました。
それはselenium-wire
pypi.org

こんな感じで、Chromeがバックグラウンドで通信しているデータを取得できます。

from seleniumwire import webdriver  # Import from seleniumwire

# Create a new instance of the Chrome driver
driver = webdriver.Chrome()

# Go to the Google home page
driver.get('https://www.google.com')

# Access requests via the `requests` attribute
for request in driver.requests:
    if request.response:
        print(
            request.url,
            request.response.status_code,
            request.response.headers['Content-Type']
        )

※今回はこのrequest.urlが欲しかった

なんと素晴らしいライブラリでしょう。
無事に .vtt のURLを取得することができました。

ありがとう! selenium-wireの開発者の方!

英語字幕DB作成への道_Selenium編⑨ (ElementClickInterceptedException)

要素が画面上に表示されているのに、クリックすると ElementClickInterceptedException で失敗するときの解決方法が見つかりました。
それはexecute_script()。

Before

element = driver.find_element_by_css_selector('a.small-btn')
element.click()

After

element = driver.find_element_by_css_selector('a.small-btn')
driver.execute_script('arguments[0].click();', element)

今のところ百発百中で成功しています。
なんなら element.is_displayed() が Falseでも成功します。
素晴らしい。

裏側の動きがどういう風に違うのかはわかりませんが、
一旦この例外が出たときはexecute_script()を使っていくことにします。

解決策がみつかってよかった!

英語字幕DB作成への道_Selenium編⑧ (explicit_waitの一本化)

下記の通り、waitの処理を一本化してみました!

def find_element(driver, *args, **kwargs):
    element = WebDriverWait(driver, timeout=120).until(
        lambda d: d.find_element(*args, **kwargs)
    )
    return element


def find_elements(driver, *args, **kwargs):
    elements = WebDriverWait(driver, timeout=120).until(
        lambda d: d.find_elements(*args, **kwargs)
    )
    return elements
|python|<

これで毎回explicit_waitのコードを書かずに済みます!

我ながら結構いいアイデアだと思います!
ネットで検索したらもっといいアイデアが出てくるかもとは思いますが、
しばらくは安易に検索しないで、自分で色々アイデアを出して行きたいと思います。

英語字幕DB作成への道_Selenium編⑦ (Xpath関数)

今日は初めてXpathの関数を使いました。

 //button[starts-with(@data-testid, 'season-') and contains(@data-testid, '-button')]

とても便利でよいのですが、ends-withもしくはmatchみたいな関数も欲しかったです。
starts-withとcontainsだけでもなんとかなるのですが、少しモヤっとしますね。

他にもいくつか関数があるようなので、機会があったら使ってみます!
developer.mozilla.org

今日も新しいことを学べてよかったです!

英語字幕DB作成への道_Selenium編⑥ (Profile)

やっとログイン情報を使い回すことに成功しました。

こんな簡単なコードで実装できました。

options = webdriver.ChromeOptions()
options.add_argument("user-data-dir=./profile")
driver = webdriver.Chrome(options=options)

これでChromeを立ち上げるたびにChromeが持つ情報がリセットされなくなります。
より普段遣いのChromeに近いイメージで使えるということですね!

これでようやく次の実装に進めます。
よかった、よかった!

英語字幕DB作成への道_Selenium編⑤ (Profile)

一度ログインしたときの認証情報をそのまま使う方法が、Cookie以外にないかを調べていると、
プロファイルに関する記事が何個か見つかりました。

これを使えば、普段Chromeを使っているときと同様、
一度訪れたサイトの情報を保存してくれるそうな。

これがいい!
今日は眠すぎるのでまた今度試してみよう。

良い突破口がみつかってよかった!