2023-01-20

GASを用いてTwitterアカウントのShadowBAN状況を一括で取得する

Twitterで気づかぬうちにツイート検索から除外されたり、相手へのリプライが表示されないなど制限がかけられることがあります。この制限はShadowBANと呼ばれています。Twitter Shadowban Testでアカウントの存在とBANの有無を確認できますが、1件ずつしかできないので、複数のアカウントをまとめて検査できるツールをGoogle Spread Sheetを使って組みました。

Spreadsheetの外観

SourceCode

const ROW_OFFSET = 3;
const EOA_COL_NUM = 3;
const SSB_COL_NUM = 4;
const RD_BOL_NUM = 5;
const SB_COL_NUM = 6;
const GB_COL_NUM = 7;
const SHEET_ID = "sheet_id_xxxxxxxxxxxxxxx"; // URLからシートIDを取得して置き換えてください
const SHEET_NAME = "Checker";
let spreadSheet = SpreadsheetApp.openById(SHEET_ID);
let sheet = spreadSheet.getSheetByName(SHEET_NAME);

function timestamp(){
  let now = new Date();
  let fmtDt = Utilities.formatDate(now, "Asia/Tokyo", "yyyy-MM-dd HH:mm:ss")
  let stamp = `Last Updated: ${fmtDt}`;
  sheet.getRange(1, 1).setValue(stamp);
}

function banAvailability(res) {
  return (res ? "O": "X");
}

function checker() {
  const twitterIds = sheet.getRange(3, 2, 20, 1).getValues();
  for (let i = 0; i <= 20; i++) {
    let twitterId = twitterIds[i][0];
    if (twitterId == "") {
      break;
    }
    let url = `https://as.hisubway.online/?username=${twitterId}`;
    let res = UrlFetchApp.fetch(url).getContentText();
    let json = JSON.parse(res);
    let profile = json["profile"];
    let rowNum = i + ROW_OFFSET;
    sheet.getRange(rowNum, EOA_COL_NUM).setValue(banAvailability(profile["exists"]));
    if (!profile["exists"]) {
      continue;
    }
    let tests = json["tests"];
    sheet.getRange(rowNum, SSB_COL_NUM).setValue(banAvailability(tests["ghost"]));
    sheet.getRange(rowNum, RD_BOL_NUM).setValue(banAvailability(tests["more_replies"]));
    sheet.getRange(rowNum, SB_COL_NUM).setValue(banAvailability(tests["search"]));
    sheet.getRange(rowNum, GB_COL_NUM).setValue(banAvailability(tests["typeahead"]));
  }
  timestamp();
}

function clear() {
  sheet.getRange(3, 3, 20, 5).clearContent();
  timestamp();
}

うまく動作しない場合にはまずchecker関数のurl変数1をご確認ください。

出力データおよびBANの種類の説明

Output Description
ExistenceOfAccount アカウントが存在するか
SearchSuggestionBan ログアウト中の検索結果やハッシュタグでの検索結果からツイートを除外するBAN
Reply Deboosting 攻撃的なリプライと判断された場合に元ツイートをクリックしたうえで表示ボタンを押さないと返信を見られなくするBAN
SearchBan 検索結果から該当のアカウントのツイートをすべて除外するBAN
GhostBan 第三者からリプライが見られない状態となるBAN

コードの説明

スプレッドシートのTwitterID列にTwitterIDを入力することで検査対象のTwitterIDを設定できます。設定後、「CHECK」ボタンをクリックするとchecker()関数が実行されて、BAN状況の確認をしてSpreadSheetにその結果を出力します。

twitterIds変数にTwitterID列のセル範囲を格納して、for文を使って順番にTwitterIDを読み出します。TwitterIDが空欄の場合にはfor文を抜け出す処理をつけて検査を終了します。

TwitterIDが空白でない場合にはTwitterIDを代入したurl変数を定義してHTTP-GETでそのURLにアクセスします。私のTwitterID(@rmc_km)であればURLはhttps://as.hisubway.online/?username=rmc_kmとなります。このURLにアクセスすると以下のようなJSONが結果として返されます。

{
   "profile":{
      "exists":true
   },
   "tests":{
      "ghost":true,
      "more_replies":true,
      "search":true,
      "typeahead":true
   },
   "region":"X233"
}

json内のbool値がtrueであれば異常なし、falseであればアカウントが存在しなかったりBANがかかっていたりなどの異常が生じていることになります。これらの値を取り出しながら対応する行・対応する列に結果を埋め込みます。

行番号はrowNum変数で定義しています。for文で定義したi変数は0からスタートしますが、実際に結果を入力する行は3行目となっています。その差分を調整するためROW_OFFSET定数で3を設定してi変数と足し合わせることで3行目から値を入力できるようにしています。列番号はコードの2行目から6行目の定数を使って行・列の番号を設定します。

この行・列の番号をsheetオブジェクトのgetRangeメソッドにセットしてセルを取得します。取得したセルに値をセットする処理としてsetValueメソッドを使用します。出力する値はbool値のままではわかりづらいため、oxかに変換するためにbanAvailability関数を使います。この関数はres引数がtrueであればoを返しそれ以外であればxを返す三項演算子が設定されています。TwitterIDが連続して入力されている範囲内の最終行分までかつC列~G列までの範囲でoxかを出力する処理を実行します。

最終行まで処理をしたら最後にシート内にタイムスタンプを埋め込み処理が終了となります。

そのほかこれらの処理の結果を削除する用にclear関数を記載しており、「CLEAR」ボタンを押すとCHECKの結果をすべて削除します。

まとめ

APIを解析してプログラムに取得の処理をさせることで複数件の処理に対応させるような拡張を作ることができました。スプレッドシート上で動作するため、条件付き書式や関数との併用で少ないコードでリッチな機能を実装することもできます。少ないコードであれば実装もメンテナンスも楽になるため、少ないコード・手間で開発していく手法に積極的に取り組みたいと思えるような成果物となりました。

Annotation


  1. Twitter Shadowban Testの問い合わせ先のURLがしばしば変わることがありコードが動作しない場合もあります。ご不便をおかけして恐縮です。 ↩︎