Twitterの興味関心チェックリストを自動で外したい
このチェックボックス、すぐ復活して3日も放っとけばあの紫の星の通知が飛んでくるので
そもそもブラウザの操作を自動化する手段を全く知らなかったので色々調べた
今のところはなんか新しめでよさげなPlaywrightを使おうと思っている
とりあえずローカルでちゃんと動くところまで完成までさせて、余裕があればAWS LambdaかCloud Functionsにデプロイしたい
その場合、インストールにやや苦労する可能性があるらしいことをメモしておく
Twitterにログインする処理を書くとき参考になりそうな資料
上記記事で紹介されているcookiesやlocal storageを使う方法はその点良さそう
↓にログイン状態をjsonに保存する簡単な方法が載っていた
コマンドを打つだけなので、このためだけのスクリプトを書かなくて済む
--save-storage
オプションをつけてcodegen
コマンドを実行
ログイン後、ウィンドウを閉じるとauth.json
が保存されている
npx playwright codegen --save-storage=auth.json
# Perform authentication and exit.
# auth.json will contain the storage state.
--load-storage
オプションでちゃんとログインできることを確認できる
npx playwright open --load-storage=auth.json twitter.com
複数アカウントにログインしたらどうなるかはまだ調べていないが、腹減ったんで一旦終わり
取得したauth.json
をスクリプトから参照するには次のように書けばよい
+ // Create a new context with the saved storage state.
+ const context = await browser.newContext({ storageState: 'auth.json' })
+
+ const page = await context.newPage()
- const page = await browser.newPage()
page
をbrowser.newpage()
から作っている場合はcontext.newpage()
に直すのを忘れてはいけない
複数アカウントにログインしても問題なかった
アカウント切り替えのモーダルに自分のアカウントがズラッと並んでいるはずなので、あとはここのクリックを自動化できればok
codegen
コマンドでいい感じのコードができるので、それをひな形にすれば良い
さて、ループ回数を決めるためにここからアカウントの数を取得したいわけだが、アカウント切り替えモーダルが表示されるまでのラグを明示的に待つ必要があることに気づかず、ちょっとつまずいた
click
やhover
などの操作をする際、実行可能になるまで自動で待ってくれる仕組みがある
しかし、数を数えるcount
は(対象が0個のときもありえるので)その仕組みがなく、表示待ちをしたいときは以下のように明示してやる必要がある
// Wait until all the accounts become visible (i.e. countable)
await page.waitForSelector('[data-testid="UserCell"]')
// Now count them
const myAccountNum = await page.locator('[data-testid="UserCell"]').count()
あとはアカウントを末尾から選んでいけば良い
N-th element selectorで-1
を指定すればok
await Promise.all([
page.waitForNavigation(),
page.click('[data-testid="UserCell"] >> nth=-1')
])
なお、同じことをtwitterのホームでやるとおすすめユーザーのUserCell
も引っかかって、しかも末尾にくるので、ひと工夫必要(アカウント切り替えモーダルを出す前のUserCell
の数を数えておくとか)
https://twitter.com/i/api/1.1/account/personalization/p13n_preferences.json
をブロックするのが中々うまくいかず断念してしまった
playwrightではroute(url, route => route.abort())
でリクエストをブロックできる
しかし、現状service workerが絡むリクエストには介入できないようで、まさにここに引っかかってしまった
実は部分的には解決できていて、一番目のアカウントのみに限れば、service workerを無効化できて、リクエストブロックもできた
ただアカウント切替時、ゾンビのように復活するservice workerを無効化する手立てが見つからなかった
結局採用はしていないのだが、一応その方法を残しておく
具体的には↓のように書くと、service workerを登録解除する処理をページ内環境で実行させられる
async function killSW() {
const registrations = await navigator.serviceWorker.getRegistrations()
registrations.forEach( r => r.unregister() )
}
page.evaluate(killSW)
どうもアカウントが切り替わる瞬間にtwitter.com/home
に飛んでいくのが鍵な気はするのだが、割といろいろ試してもう疲れたのでここは妥協することにした
まあそもそもブロックが必要なのは、解除しなきゃいけないチェックがいっぱいあるという前提で、リクエストが大量に送信されるのを防ぐためだったりする
で、毎日自動実行してたらそんなにチェックたまらんやろ!wということでここらへんの対策は何もしないことにした
初回だけはブラウザでやってあげたほうがいいかもしれない