それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

chrome履歴画面の検索結果を全部クリックする(shadowroot経由のDOM JS)

特定の検索結果の履歴を全部消したい

Googleの閲覧履歴を検索して消したい。消したいけど、「すべて消す」が無い。

検索結果をすべて選択がない。

すべて選択がないので、ちまちま消す必要があるだるすぎる。

Devtoolでまとめてチェックしたい

ボタンがないならDevtoolでアクセスだ。ぜんぶチェックしてやる。

React?Angular?かなshadowRootがある。

id=history-app に下に shadow-root(open) がある。このままでは css セレクタでアクセスできない。

ShadowRootへアクセスするには

エレメントに shadowRootが生えている。これを使う。コンテキストを切り替えて要素をたどってしまえば、強引にクリックできる。この手はSeleniumなどでも使える。まぁ通常はスクリーンの指定領域にClickイベントを送るだろうけど、直接要素を触ることも出る。

const e = document.querySelector('#some-app')
SomeRoot = e.shadowRoot
SomeRoot.querySelector(' div ')
div.click()

履歴の検索結果をぜんぶクリックする。

Chrome のコンソールを使ってつぎのようにする。

appRoot = $('#history-app').shadowRoot
historyRoot = appRoot.querySelector('#main-container #content #tabs-container history-list').shadowRoot
for ( e of historyRoot.querySelectorAll('iron-list history-item[tabindex="-1"]') ){
  e.shadowRoot.querySelector('cr-checkbox#checkbox.no-label').click()
}

コンソールに貼り付けて

実行

一気に選択できた。

仕組み

冒頭で書いた通り、shadowRootを辿っていく。

historyRoot.querySelectorAll('iron-list history-item[tabindex="-1"]') でアイテムを探している

アイテムをクリックする。

#shadowRootに入っていく
appRoot = $('#history-app').shadowRoot
historyRoot = appRoot.querySelector('#main-container #content #tabs-container history-list').shadowRoot
itemRoot =  historyRoot.querySelectorAll('iron-list history-item')[10].shadowRoot # index=10 
# 該当のアイテムをクリック
itemRoot.querySelector('cr-checkbox#checkbox.no-label').click()

表示中のアイテムを全部クリックする。

appRoot = $('#history-app').shadowRoot
historyRoot = appRoot.querySelector('#main-container #content #tabs-container history-list').shadowRoot
for ( e of historyRoot.querySelectorAll('iron-list history-item[tabindex="-1"]') ){
  e.shadowRoot.querySelector('cr-checkbox#checkbox.no-label').click()
}

削除ボタンを押す場合

appRoot = $('#history-app').shadowRoot
toolbar = appRoot.querySelector('#toolbar').shadowRoot
selectionOverlay = toolbar.querySelector('cr-toolbar-selection-overlay').shadowRoot
selectionOverlay.querySelector("#delete").click()

ダイアログボックスを押す場合

appRoot = $('#history-app').shadowRoot
historyRoot = appRoot.querySelector('#content history-list').shadowRoot
historyRoot.querySelector('cr-dialog cr-button:nth-child(2)').click()

表示中のアイテムをすべて削除(コピペ用)

(async function delete_displayed(){
  async function select_displayed(){
    appRoot = $('#history-app').shadowRoot
    historyRoot = appRoot.querySelector('#main-container #content #tabs-container history-list').shadowRoot
    for ( e of historyRoot.querySelectorAll('iron-list history-item[tabindex="-1"]') ){
      e.shadowRoot.querySelector('cr-checkbox#checkbox.no-label').click()
    }  
  }
  async function click_delete(){
    appRoot = $('#history-app').shadowRoot
    toolbar = appRoot.querySelector('#toolbar').shadowRoot
    selectionOverlay = toolbar.querySelector('cr-toolbar-selection-overlay').shadowRoot
    selectionOverlay.querySelector("#delete").click()
  
  }

  async function click_confirm(){
    appRoot = $('#history-app').shadowRoot
    historyRoot = appRoot.querySelector('#content history-list').shadowRoot
    historyRoot.querySelector('cr-dialog cr-button:nth-child(2)').click()  
  }
  await select_displayed();
  await click_delete();
  await click_confirm();
  
})();

インフィニット・ロード

無限ロードなので、スクロールバーが最下部まで行かないと、次がロードされないんので、全部選択したつもりでも残ることはある。

非表示もクリックしてしまう。

ざっと書いただけなので、非表示になってるAppもクリックしてしまうので、エラーになることがある。

async をする必要がある。

shadowrootへのアクセス方法

Shadowrootへの強引なアクセス方法を覚えておくと、一番低レイヤなので、Seleniumなどでスクレーピングするときに使えそう。

Chromeは履歴を消させたくない?

履歴の絞り込みで一気に消したいときなのに、すべて選択がない。

履歴の絞り込みができるのに、マッチ結果をすべて削除が機能にない。

マッチ結果を削除がないのは致命的な欠陥である、Vivaldiなど別のブラウザでは簡単にできるのだが。

ほかブラウザでは可能なのに、Chrome だけが履歴削除について機能を制限している。

これは、アクセス履歴を「何らかの広告」にいや「個人の追跡」に使っている傍証ではないかと想像する。やはり、Googleは組織として邪悪になってるのかなと信用を置けない。

2022/09/10

HTMLの構造が若干変わってたので記述内容を変更