なりそこない救世主: chrome.exe --remote-debugging-port

「出来たぜやったね」を強調する手もないではないけれどだがしかし。

selenium webdriver で chrome をコントロールする動機のほとんど大半が web サービスから何らか結果を得るための操作の自動化、すなわちアウトプットが得られればいいというものなので、その向きには「開いている chrome のインスタンスにアタッチして、それをコントロールする」ことは大抵考えなくていい。つまりは、プロセスとして chrome をバックグラウンドで起動してそのインスタンスをコントロール出来れば良い。ワタシが書いたネタであれば例えばこれとか。

けれども、例えばメモリが何らかの理由で逼迫しているとして、そうしたケースで「メモリ喰いの「タブを大量に開いた」chrome を整理する術が欲しい」と思ったとする。というか思った。

今ワタシはこのページを書くための chrome を、80くらいのタブを開いた状態で書いている。色んな調べものをしつつ、エロいタブも日常的に開いている、とかだと、気付いたらこんな状態になってることが多い。ここまでタブを開いていると、結構同じページを複数開いていたりするし、もうとっくに用済みになってるページも開きっぱなしになってることも多い。そしてメモリが逼迫してる状態だと「各々のタブにマウス操作などで移動してみて、開きっぱなしにしとく意味がないと判断出来るなら閉じる」という繰り返し行為そのものが「重くて操作に耐えない」ので、ということ。このために、たとえばコンソールからタブを閉じる操作は出来ないだろうか、みたいなことを考えたわけだ。

けれどもこれが非常によろしくない。

最も望むものに近かったのが見出しにした「chrome.exe --remote-debugging-port」を使う方法なのだが、まぁ…「今開いている全タブ」にアクセス出来んのだわ。これについての情報はどこにもない。あと、キー操作なども出来ないなど制約が非常に多くて、救世主度は非常に低い。

これをするためにはまずは:

参考にしたサイトが皆 9222 を選んでるんで、指定しなければ自動でポートが開いてたりしないんだろうかと思ったけれど、そうでもなさそう。いや、あるかもしれんけど、情報は一切見つからず。ともあれ、この状態で常に chrome を起動するようにしておけば:

 1 # -*- coding: utf-8 -*-
 2 from selenium import webdriver
 3 from selenium.webdriver.chrome.options import Options
 4 
 5 chrome_options = Options()
 6 chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
 7 driver = webdriver.Chrome(options=chrome_options)
 8 for h in driver.window_handles:
 9     driver.switch_to.window(h)
10     print(h, driver.title)

ワタシのその「80くらい開いてる」タブのほとんどが無視され、このスクリプトは20くらいだけのタブ切り替えを「してくれる」。この「20くらいしか」という制約が気にならない用途であるならば、例えば「それらタブを全部閉じる」ということは出来る。

どの「20くらい」になるかは、アクティブな chrome インスタンスで最後に手動操作した状態に依存する。LRU みたいなことだろう、きっと。最後にアクティブにしたもののキャッシュにアクセス出来ている、という感じかもしれない。

あと、この debuggerAddress は REST API を提供してくれている。9222 で設定して起動したなら http://127.0.0.1:9222/json にアクセスしてみよ。これに基づいてなんらか処理をすることも無論可能で:

 1 # -*- coding: utf-8 -*-
 2 import requests  # これも標準バンドルではないので pip install しとくれ
 3 from selenium import webdriver
 4 from selenium.webdriver.chrome.options import Options
 5 
 6 chrome_options = Options()
 7 chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222")
 8 driver = webdriver.Chrome(options=chrome_options)
 9 res = requests.get("http://127.0.0.1:9222/json")
10 #for h in driver.window_handles:
11 #    driver.switch_to.window(h)
12 #    print(h, driver.title)
13 for d in [d for d in res.json() if d["type"] == "page"]:
14     print(d["type"])
15     driver.switch_to.window(d["id"])
16     print(driver.title)

はっきりいって本質的にやってることは何ら変わらないので、「20しか…」問題の解決にはならないけれど、まぁ知識として知っといて損はないかなというレベル。

てなわけで、メモとして書いておく価値はないとは言えないけれど、即戦力として使えるものではなかった、てことで。