class属性の難読化をされても狙ったElementを駆逐したい(できそうにない)

要約すると、クラス名ではなく、CSSセレクタ:nth-childを使って階層の位置で表現すれば、削除したいElementを特定できるんじゃないかな、と思ってやってみたが、しんどくて諦めてます、という感じです。

最近仕事していても楽しくなくて愚痴が出がちです。 でも、愚痴っても誰も助けてくれないし、見てる方も「こいつずっと愚痴ってんな、さっさと仕事辞めるか死ねばいいのに」って思うに違いないんです。

それでも、助けを求めるように呟いてしまうわけです。ならいっそのことTwitterを呟けなくすればよいのではないか、と考えました。

ということで、Twitterで呟けないようにするために、DOMからTweetする場所(テキストボックス、リプライアイコン等)を削除するWebExtensionを書き始めた。ついでにプロモートツイートも消してる。

github.com

ただ画面表示時とbody以下のelementの変化を拾って特定のCSSセレクタにマッチするElementを削除しているだけです。

とりあえずデバッグモードで動いているけども、早くも問題がにぶち当たった。

Twitterが新しいデザインになるらしく、アカウントによってはこんな感じで選べるようになっている。

右上の自分のアイコンをクリックすると出るメニュー

f:id:ryousanngata:20190309071008p:plain

で、切り替えると2カラムスタイルになるのだけれど、DOMベースで探している都合上、デザインが変わると当然機能しない。 さらに厄介なのが、デザインが変わっただけではなく、 Class名の難読化を入れている

f:id:ryousanngata:20190309071344p:plain

普通の開発ならこんな面倒なことする意味がないので、多分Adblocker対策なんだろうか。

なので、もうこのWebExtensionはあきらめているのだけれど、ふと難読化はしても早々DOMの構造は替えないよな?というアイディアを思いつく。

つまり、ネストを重ねていても、n番目の子のm番目の子のo番目の子の....とやってDOMを辿れば目的の要素を見つけられるはず。 さらに、timelineのように連続した要素を並べる場合でも、n番目の子のすべての子のo番目の子の...とやれば、全部引っこ抜けるはず。

それどうやるの?というと、CSSセレクターに:nth-childがあるのでこれでやります。

例: timeline中のリプライアイコンを消す CSSセレクタ(リツイート、プロモーションは除く)

#react-root > *:nth-child(2) > *:nth-child(2) > *:nth-child(1) > *:nth-child(2) > *:nth-child(1) > *:nth-child(1) > *:nth-child(1) > *:nth-child(2) > *:nth-child(1) > *:nth-child(1) > *:nth-child(2) > *:nth-child(1) > *:nth-child(1) > * > *:nth-child(1) > *:nth-child(1) > *:nth-child(1) > *:nth-child(1) > *:nth-child(2) > *:nth-child(2) > *:nth-child(1)

分かりにくいですが途中に> * >というセレクタがあり、これがtimelineの連続しているツイートの要素に対応します。

実際に開発者ツールを開いて以下のスクリプトを流せばどのElementが取れるかは分かるはず。

document.querySelector('#react-root > *:nth-child(2) > *:nth-child(2) > *:nth-child(1) > *:nth-child(2) > *:nth-child(1) > *:nth-child(1) > *:nth-child(1) > *:nth-child(2) > *:nth-child(1) > *:nth-child(1) > *:nth-child(2) > *:nth-child(1) > *:nth-child(1) > * > *:nth-child(1) > *:nth-child(1) > *:nth-child(1) > *:nth-child(1) > *:nth-child(2) > *:nth-child(2) > *:nth-child(1)')

これであればデザイン修正されるまでは安定してDOMを消せるんじゃないかな、って思った。 (しかしこっちの方法も無意味なDOMを間に挟まれたり、囲まれたりすると順番が狂うので死ぬ。そんな複雑化することはしないようにしてほしい・・・)

で、これどうやって作るかというと、最初は手で数えてた。しかし結構しんどかったので、JavaScriptを書きました。 ベースになるCSSセレクタと、消したいCSSセレクタと、連続する要素なので無視したいCSSセレクタ(option)の2~nの引数を取るconvertNthChild関数です。

function findTarget(root, target, ignoreElements){
    for(let i=0;i<root.children.length; ++i){
        if(root.children[i] === target){
            return [i]
        }
        const idx2 = findTarget(root.children[i], target, ignoreElements)
        
        if(idx2 !== undefined){
          if(ignoreElements.indexOf(root.children[i]) === -1){
            return [i].concat(idx2)
          }else{
            return [-1].concat(idx2)
          }
        }
    }
    return undefined
}

function nthchild(arr){
  return arr.map(n => n === -1 ? "*" : `*:nth-child(${n+1})`).join(' > ')
}

function convertNthChild(root, target, ...ignores){
  let ignoreElements = ignores.map(el => document.querySelector(el))
  const a = findTarget( document.querySelector(root),  document.querySelector(target), ignoreElements)
  if(a){
    return root + " > " + nthchild(a)
  }
  return undefined
}

// 使用例
a = convertNthChild(
    '#react-root',
    '#react-root > div.rn-1oszu61.rn-1efd50x.rn-14skgim.rn-rull8r.rn-mm0ijv.rn-13yce4e.rn-fnigne.rn-ndvcnb.rn-gxnn5r.rn-deolkf.rn-6koalj.rn-1qe8dj5.rn-1mlwlqe.rn-eqz5dr.rn-1pi2tsx.rn-1mnahxq.rn-61z16t.rn-p1pxzi.rn-11wrixw.rn-ifefl9.rn-bcqeeo.rn-wk8lta.rn-9aemit.rn-1mdbw0j.rn-gy4na3.rn-bnwqim.rn-13qz1uu.rn-1lgpqti > main > div > div.rn-1oszu61.rn-aqfbo4.rn-e84r5y.rn-1efd50x.rn-14skgim.rn-rull8r.rn-mm0ijv.rn-13yce4e.rn-fnigne.rn-ndvcnb.rn-gxnn5r.rn-deolkf.rn-6koalj.rn-1qe8dj5.rn-1mlwlqe.rn-eqz5dr.rn-16y2uox.rn-1mnahxq.rn-61z16t.rn-p1pxzi.rn-11wrixw.rn-ifefl9.rn-bcqeeo.rn-wk8lta.rn-9aemit.rn-1mdbw0j.rn-gy4na3.rn-bnwqim.rn-1lgpqti > div > div.rn-1oszu61.rn-14lw9ot.rn-1efd50x.rn-14skgim.rn-rull8r.rn-mm0ijv.rn-13yce4e.rn-fnigne.rn-ndvcnb.rn-gxnn5r.rn-deolkf.rn-6koalj.rn-1qe8dj5.rn-1mlwlqe.rn-eqz5dr.rn-1mnahxq.rn-lchren.rn-p1pxzi.rn-1jj8364.rn-1ye8kvj.rn-ifefl9.rn-bcqeeo.rn-wk8lta.rn-9aemit.rn-1mdbw0j.rn-gy4na3.rn-bnwqim.rn-13qz1uu.rn-184en5c > div > div.rn-1oszu61.rn-1efd50x.rn-14skgim.rn-rull8r.rn-mm0ijv.rn-13yce4e.rn-fnigne.rn-ndvcnb.rn-gxnn5r.rn-deolkf.rn-6koalj.rn-1qe8dj5.rn-1mlwlqe.rn-eqz5dr.rn-1mnahxq.rn-lchren.rn-p1pxzi.rn-1jj8364.rn-1ye8kvj.rn-ifefl9.rn-bcqeeo.rn-wk8lta.rn-9aemit.rn-gy4na3.rn-6337vo.rn-bnwqim.rn-13qz1uu.rn-1lgpqti > div > section > div > div > div > div:nth-child(4) > div > div > article > div > div.rn-1oszu61.rn-1efd50x.rn-14skgim.rn-rull8r.rn-mm0ijv.rn-13yce4e.rn-fnigne.rn-ndvcnb.rn-gxnn5r.rn-deolkf.rn-6koalj.rn-1qe8dj5.rn-1iusvr4.rn-eqz5dr.rn-46vdb2.rn-1mnahxq.rn-7o8qx1.rn-p1pxzi.rn-1f6r7vd.rn-ifefl9.rn-bcqeeo.rn-wk8lta.rn-9aemit.rn-1mdbw0j.rn-gy4na3.rn-bnwqim.rn-1lgpqti > div.rn-1oszu61.rn-1efd50x.rn-14skgim.rn-rull8r.rn-mm0ijv.rn-13yce4e.rn-fnigne.rn-ndvcnb.rn-gxnn5r.rn-deolkf.rn-6koalj.rn-1qe8dj5.rn-1mlwlqe.rn-18u37iz.rn-1wtj0ep.rn-61z16t.rn-p1pxzi.rn-11wrixw.rn-156q2ks.rn-1mdbhws.rn-ifefl9.rn-bcqeeo.rn-wk8lta.rn-9aemit.rn-1mdbw0j.rn-gy4na3.rn-bnwqim.rn-1lgpqti > div:nth-child(1)',
    '#react-root > div.rn-1oszu61.rn-1efd50x.rn-14skgim.rn-rull8r.rn-mm0ijv.rn-13yce4e.rn-fnigne.rn-ndvcnb.rn-gxnn5r.rn-deolkf.rn-6koalj.rn-1qe8dj5.rn-1mlwlqe.rn-eqz5dr.rn-1pi2tsx.rn-1mnahxq.rn-61z16t.rn-p1pxzi.rn-11wrixw.rn-ifefl9.rn-bcqeeo.rn-wk8lta.rn-9aemit.rn-1mdbw0j.rn-gy4na3.rn-bnwqim.rn-13qz1uu.rn-1lgpqti > main > div > div.rn-1oszu61.rn-aqfbo4.rn-e84r5y.rn-1efd50x.rn-14skgim.rn-rull8r.rn-mm0ijv.rn-13yce4e.rn-fnigne.rn-ndvcnb.rn-gxnn5r.rn-deolkf.rn-6koalj.rn-1qe8dj5.rn-1mlwlqe.rn-eqz5dr.rn-16y2uox.rn-1mnahxq.rn-61z16t.rn-p1pxzi.rn-11wrixw.rn-ifefl9.rn-bcqeeo.rn-wk8lta.rn-9aemit.rn-1mdbw0j.rn-gy4na3.rn-bnwqim.rn-1lgpqti > div > div.rn-1oszu61.rn-14lw9ot.rn-1efd50x.rn-14skgim.rn-rull8r.rn-mm0ijv.rn-13yce4e.rn-fnigne.rn-ndvcnb.rn-gxnn5r.rn-deolkf.rn-6koalj.rn-1qe8dj5.rn-1mlwlqe.rn-eqz5dr.rn-1mnahxq.rn-lchren.rn-p1pxzi.rn-1jj8364.rn-1ye8kvj.rn-ifefl9.rn-bcqeeo.rn-wk8lta.rn-9aemit.rn-1mdbw0j.rn-gy4na3.rn-bnwqim.rn-13qz1uu.rn-184en5c > div > div.rn-1oszu61.rn-1efd50x.rn-14skgim.rn-rull8r.rn-mm0ijv.rn-13yce4e.rn-fnigne.rn-ndvcnb.rn-gxnn5r.rn-deolkf.rn-6koalj.rn-1qe8dj5.rn-1mlwlqe.rn-eqz5dr.rn-1mnahxq.rn-lchren.rn-p1pxzi.rn-1jj8364.rn-1ye8kvj.rn-ifefl9.rn-bcqeeo.rn-wk8lta.rn-9aemit.rn-gy4na3.rn-6337vo.rn-bnwqim.rn-13qz1uu.rn-1lgpqti > div > section > div > div > div > div:nth-child(4)'
)

最後のCSSセレクターの嵐は開発者ツールを使い、以下のようにして取得できます。

f:id:ryousanngata:20190309072308p:plain

1つ目は基準になるlementのCSSセレクタです。ここから下を辿って目的のElementを探します。

2つ目は狙っているElementのCSSセレクタです。連続した要素であってもかまいません。

3つ目以降は連続要素と見なすlementのCSSセレクタを指定します。うまく言葉で説明できないんですが、これも開発者ツールで見ると簡単に見つけられます。

f:id:ryousanngata:20190309075311p:plain

ここまでやって画像をぺたぺたしてる時に気づいたのですが、アクセシビリティの考慮なのか、aria-labelが結構個性的な名前付いていたり、articleタグが使われていたりするので、そっちで見て削除していった方がよさそうにも見えます。

まぁでも、多分対策されるor変更の影響を受けやすすぎて安定しなさそうなので、ちょっと諦めてます。