Twitterのシャドウバンとセンシティブ判定をチェックする拡張機能を作った
Twitterのシャドウバンとセンシティブ判定を検出するブラウザー拡張機能「Shadowban Scanner」をリリースしました。この記事では、Shadowban Scannerの特長を説明したあと、技術的な仕組みについて解説します。
なお、Shadowban Scannerはユーザースクリプト版(日本語版 / 英語版)も存在しますが、設定を変更できないので拡張機能版がおすすめです。
Shadowban Scannerを使うと、アカウント単位のシャドウバンとツイート単位のセンシティブ判定を検出できます。シャドウバンやセンシティブ判定を検知すると、画像のように、ツイートやプロフィールにメッセージを表示します。
シャドウバンの検知については、他の多くのツールと同様に、偽陽性や偽陰性が発生することがあります。一方で、センシティブ判定についてはほとんど正確に検出できます。
類似のツールとの違い
Twitterのシャドウバンを検知するツールは複数ありますが、それらとShadowban Scannerの違いには次のようなものがあります。
類似のツール | Shadowban Scanner |
---|---|
専用のサイトを開き、スクリーンネームを入力する必要がある | ✅普通にTwitterを使っているだけでツイートやプロフィールに結果を表示する |
アカウント単位のシャドウバンを検出できる | ✅アカウント単位のシャドウバンに加えて、ツイート単位のセンシティブ判定を軽度・重度のどちらも検出できる |
✅シャドウバンの他にSearch Suggestion Banも検出できる | Search Suggestion Banは検出できない |
✅PCとスマホの両方で利用できる | PCでのみ利用できる |
ここからは、この拡張機能の仕組みなどの技術的な情報について解説します。
シャドウバンについて
いわゆる「シャドウバン」には、Twitter公式の定義と、一般的な定義の2つがあります。
Twitter公式の定義では、「元の投稿者に知られずに、意図的に誰かのコンテンツを投稿者以外の誰もが発見できないようにすること」とされています。一方で、一般的には「ツイートが検索結果に表示されなくなること」をシャドウバンと呼ぶことが多いです。
ここでは、後者の一般的な定義を用います。
シャドウバンの検出方法
TwitterのAPIにアクセスするか、WebクライアントのReact Propsを参照すると、アカウントの情報にpossibly_sensitive
というフラグの存在を確認できます。
このフラグがtrue
になっている場合、シャドウバンされている可能性が高いです。たまに、false
なのにシャドウバンされていたり、true
なのにシャドウバンされていなかったりすることもありますが、概ねこのフラグで判断できます。
センシティブ判定の検出方法
Twitterにはアカウント単位のシャドウバンとは別に、ツイート単位のセンシティブ判定が存在しています。
センシティブ判定には軽度のものと重度のものがあります。
軽度のものでは、閲覧者側の設定で[センシティブな内容を含むものを表示しない]がオンになっている場合に、ツイートが検索結果に表示されなくなります。重度のものでは、設定にかかわらずツイートが検索結果に表示されなくなり、年齢制限がかかります。年齢制限がかかった状態では、未成年者のアカウントや非ログイン状態で閲覧できなくなります。
ツイートのpossibly_sensitive
フラグがtrue
になっており、かつpossibly_sensitive_editable
フラグがtrue
になっているのが軽度のセンシティブ判定です。重度のセンシティブ判定では、これらがそれぞれtrue
とfalse
になっています。
React Propsの取得方法
ここまでで説明したような、アカウントやツイートに関するフラグを取得するには、WebクライアントのReact Propsを参照する必要があります。
React Propsを参照する方法の他にも、Twitterの通常のAPIにアクセスする方法と、内部向けAPIにアクセスする方法があります。
しかし、通常のAPIは有料化されてしまいましたし、内部向けAPIを使うにはCookieからユーザーの認証情報を(勝手に)引っこ抜く必要があります。後者の方法は、一部の人気なTwitter向け拡張機能で実際に使われていますが、セキュリティー的にあまりよくありません。
そこで、React Propsに格納されている情報を参照するわけです。React Propsは、対象となるHTML要素の、__reactProps$
から始まる名前のプロパティーに格納されています。変数targetElement
に対象となるHTML要素が格納されているとき、次のコードでReact Propsを取得できます。
const reactPropsName = Object.getOwnPropertyNames(targetElement).filter((n) => n.startsWith("__reactProps$"))[0];
const reactProps = targetElement[reactPropsName];
工夫した点
コンテンツスクリプトとページスクリプトの連携を工夫しました。
というのも、拡張機能の多言語対応や設定の読み書きのためにコンテンツスクリプトが必要ですが、React Propsはページスクリプトからでないと参照できません。この拡張機能を動作させるには、コンテンツスクリプトとページスクリプトの両方が必要であり、それらの間でデータをやり取りする必要があります。
参考:コンテンツスクリプトからはHTML要素の一部のプロパティーにアクセスできない - Qiita
そこでまず、コンテンツスクリプトを使ってページにページスクリプトを挿入します。次に、ページスクリプトを使い、コンテンツスクリプトと情報のやり取りをするためのHTML要素を作成します。コンテンツスクリプトは、このHTML要素に対してカスタムイベントを監視します。ページスクリプトからコンテンツスクリプトに情報を送るときは、カスタムイベントを発火させます。
このようにすることで、コンテンツスクリプトとページスクリプトの間でデータをやり取りできます。ただし、Chromeではコンテンツスクリプトからカスタムイベントのdetailプロパティーを参照できません。
そのため、データの送受信のタイミングを知らせるためにのみカスタムイベントを使い、実際のデータのやり取りにはクラスやデータ属性を駆使する必要があります。
まとめ
この記事では、Twitterのシャドウバンとセンシティブ判定を検出する拡張機能「Shadowban Scanner」の仕組みについて解説しました。ソースコードはGitHubで公開しているので、興味のある方は覗いてみてください。
今のところ、表示されるメッセージは日本語と英語に対応していますが、言語の追加や翻訳の改善なども受け付けています。翻訳も含めて、開発に興味のある方はIssueやPull Requestなどをお待ちしています!
宣伝
Twitterのインプレッション数(閲覧数)を非表示にする拡張機能「Hide View Count」も作っています。こちらもぜひチェックしてみてください。
Discussion