情報の自由は自然に進化するものではなく、劣化する。
—— オープン情報マニフェスト
Twitter は 8 月に公開アクセスと API インターフェースを全面的に制限し、第三者の統合が正常に機能しなくなりました。オープンユーザーデータは私的な収益化ツールに誘拐され、かつてのオープンウェブの基準であった Twitter はこのような状況に陥りました。デジタル奴隷制が最もあってはならない場所に現れ、感慨深いものがあります。これにより、多くのユーザーが Fediverse に流れましたが、社会的関係や習慣が一度形成されると、それを迅速に変えることは容易ではなく、より多くの人々は耐えることを選びました。Musk もこの点を見抜いているからこそ、彼は恐れを知らないのです。
しかし、私たちは Twitter が閉鎖的だと一概に言うことはできません。結局のところ、彼らは月額 4 万ドルというスタート価格で企業 API を開放しています。
何ですって?あなたはそれを使えないと言うのですか?
それなら、私のように一万のアカウントを作成して封鎖を回避することができます。
Twitter はすべての公開アクセスを制限しましたが、新しくダウンロードした Twitter モバイルクライアントではユーザーの動向を正常に確認できることがわかりました。これにより、私たちは潜在的な利用方法を提供され、パケットキャプチャを通じて、クライアントが一連の特殊なインターフェースをリクエストして、権限が低く、頻度制限が厳しい一時的なアカウントを作成していることがわかります。このアカウントを使用して、必要なデータの大部分を取得できます。しかし、このアカウントはリクエスト頻度の制限が非常に厳しいため、基本的な使用ニーズを満たすには大量のこのようなアカウントが必要です。また、各 IP は一定の時間内に 1 つの一時的なアカウントしか取得できないため、大量の IP プロキシも必要です。
具体的なパッケージ分解とパケットキャプチャのプロセスについては、BANKA の「どうやって Twitter をクローリングするか(Android)」を参照してください。BANKA の肩に立って、私たちはこのような登録スクリプトを書くことができます(Nitter - ゲストアカウントブランチのデプロイから):
#!/bin/bash
guest_token=$(curl -s -XPOST https://api.twitter.com/1.1/guest/activate.json -H 'Authorization: Bearer AAAAAAAAAAAAAAAAAAAAAFXzAwAAAAAAMHCxpeSDG1gLNLghVe8d74hl6k4%3DRUMF4xAQLsbeBhTSRrCiQpJtxoGWeyHrDb5te2jpGskWDFW82F' | jq -r '.guest_token')
flow_token=$(curl -s -XPOST 'https://api.twitter.com/1.1/onboarding/task.json?flow_name=welcome' \
-H 'Authorization: Bearer AAAAAAAAAAAAAAAAAAAAAFXzAwAAAAAAMHCxpeSDG1gLNLghVe8d74hl6k4%3DRUMF4xAQLsbeBhTSRrCiQpJtxoGWeyHrDb5te2jpGskWDFW82F' \
-H 'Content-Type: application/json' \
-H "User-Agent: TwitterAndroid/10.10.0" \
-H "X-Guest-Token: ${guest_token}" \
-d '{"flow_token":null,"input_flow_data":{"flow_context":{"start_location":{"location":"splash_screen"}}}}' | jq -r .flow_token)
curl -s -XPOST 'https://api.twitter.com/1.1/onboarding/task.json' \
-H 'Authorization: Bearer AAAAAAAAAAAAAAAAAAAAAFXzAwAAAAAAMHCxpeSDG1gLNLghVe8d74hl6k4%3DRUMF4xAQLsbeBhTSRrCiQpJtxoGWeyHrDb5te2jpGskWDFW82F' \
-H 'Content-Type: application/json' \
-H "User-Agent: TwitterAndroid/10.10.0" \
-H "X-Guest-Token: ${guest_token}" \
-d "{\"flow_token\":\"${flow_token}\",\"subtask_inputs\":[{\"open_link\":{\"link\":\"next_link\"},\"subtask_id\":\"NextTaskOpenLink\"}]}" | jq -c -r '.subtasks[0]|if(.open_account) then {oauth_token: .open_account.oauth_token, oauth_token_secret: .open_account.oauth_token_secret} else empty end'
そして、このようなバッチ登録スクリプト(私自身から):
const got = require('got');
const { HttpsProxyAgent } = require('https-proxy-agent');
const fs = require('fs');
const path = require('path');
const concurrency = 5; // Twitterに私たちの小さな秘密を発見されないように、あまり大きく設定しないでください
const proxyUrl = ''; // ここにあなたのプロキシを追加してください
const baseURL = 'https://api.twitter.com/1.1/';
const headers = {
Authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAAFXzAwAAAAAAMHCxpeSDG1gLNLghVe8d74hl6k4%3DRUMF4xAQLsbeBhTSRrCiQpJtxoGWeyHrDb5te2jpGskWDFW82F',
'User-Agent': 'TwitterAndroid/10.10.0',
};
const accounts = [];
function generateOne() {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve) => {
const timeout = setTimeout(() => {
// eslint-disable-next-line no-console
console.log(`アカウントの生成に失敗しました。続行... タイムアウト`);
resolve();
}, 30000);
const agent = {
https: proxyUrl && new HttpsProxyAgent(proxyUrl),
};
try {
const response = await got.post(`${baseURL}guest/activate.json`, {
headers: {
Authorization: headers.Authorization,
},
agent,
timeout: {
request: 20000,
},
});
const guestToken = JSON.parse(response.body).guest_token;
const flowResponse = await got.post(`${baseURL}onboarding/task.json?flow_name=welcome`, {
json: {
flow_token: null,
input_flow_data: {
flow_context: {
start_location: {
location: 'splash_screen',
},
},
},
},
headers: {
...headers,
'X-Guest-Token': guestToken,
},
agent,
timeout: {
request: 20000,
},
});
const flowToken = JSON.parse(flowResponse.body).flow_token;
const finalResponse = await got.post(`${baseURL}onboarding/task.json`, {
json: {
flow_token: flowToken,
subtask_inputs: [
{
open_link: {
link: 'next_link',
},
subtask_id: 'NextTaskOpenLink',
},
],
},
headers: {
...headers,
'X-Guest-Token': guestToken,
},
agent,
timeout: {
request: 20000,
},
});
const account = JSON.parse(finalResponse.body).subtasks[0].open_account;
if (account) {
accounts.push({
t: account.oauth_token,
s: account.oauth_token_secret,
});
} else {
// eslint-disable-next-line no-console
console.log(`アカウントの生成に失敗しました。続行... アカウントなし`);
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(`アカウントの生成に失敗しました。続行... ${error}`);
}
clearTimeout(timeout);
resolve();
});
}
(async () => {
const oldAccounts = fs.readFileSync(path.join(__dirname, 'accounts.txt'));
const tokens = oldAccounts.toString().split('\n')[0].split('=')[1].split(',');
const secrets = oldAccounts.toString().split('\n')[1].split('=')[1].split(',');
for (let i = 0; i < tokens.length; i++) {
accounts.push({
t: tokens[i],
s: secrets[i],
});
}
for (let i = 0; i < 1000; i++) {
// eslint-disable-next-line no-console
console.log(`アカウントを生成中 ${i * concurrency}-${(i + 1) * concurrency - 1}, 合計 ${accounts.length}`);
// eslint-disable-next-line no-await-in-loop
await Promise.all(Array.from({ length: concurrency }, () => generateOne()));
fs.writeFileSync(path.join(__dirname, 'accounts.txt'), [`TWITTER_OAUTH_TOKEN=${accounts.map((account) => account.t).join(',')}`, `TWITTER_OAUTH_TOKEN_SECRET=${accounts.map((account) => account.s).join(',')}`].join('\n'));
}
})();
これらのスクリプトは RSSHub リポジトリに置かれています: https://github.com/DIYgod/RSSHub/blob/master/scripts/twitter-token/generate.js
使用する前に、購入した IP プロキシサービスのアドレスを入力する必要があります。スクリプトは自動的にタイムアウト、リクエストなどのエラーを処理し、5 の同時実行で一時的なアカウントを自動的に取得します。1000 個のアカウントを取得すると停止します。並行処理はあまり高く設定しないでください。私の観察によると、Twitter は大量のリクエストを発見すると、しばらくインターフェースを停止します。
私はテストのために 5 つのプロキシサービスを購入しましたが、効果はほとんど変わらないと感じました。最も安いサービスを選ぶだけで大丈夫です。通常、最低価格の 1G プランで約数万から十数万のアカウントを取得するのに十分です。私が見つけた最も安いサービスはproxy-cheapですが、より良い選択肢があれば教えてください。
この方法は Nitter で安定して運用されており、現在 RSSHub およびその公式サンプルにも実装されています。私たちは邪悪な Twitter の奴隷主との戦争が段階的に勝利したことを宣言できます。