「今日は誕生日です」が10周年なので、この10年を振り返る

この記事は Otaku Advent Calendar 2025 の24日目の記事です。

adventar.org


突然ですが…………

今日は誕生日です!!!!!

その証拠に Twitter 1 の私のプロフィール画面(https://twiter.com/gecko655) では風船が飛んでいます。

Twitter も私の誕生日を祝ってくれています。


……

………

というのが冗談であることは、私の長年のフォロワーは全員ご存知のことかと思います。念の為知らない方向けに説明すると、私の Twitter アカウントでは毎日風船が飛んでいます。 昨日も一昨日も風船が飛んでいましたし、きっと明日も風船が飛ぶでしょう。

これはなにをしているのかというと、↓のリポジトリに置いてあるスクリプトを用いて、 Twitter のアカウントの誕生日設定を毎日0時頃2に当日の日付に変更しています。 これにより、私の Twitter アカウントはいつ見ても365日風船が飛び続けており、「今日はお誕生日です。」の表示が出続ける状態になっています。

github.com

そして、このスクリプトを起動して、初めて誕生日の自動更新に成功した日が、10年前のちょうど今日である2015年12月24日でした。 すなわち、今日は「今日は誕生日です」の10周年記念日です

↑初めて Twitter の誕生日の自動更新をスクリプトで成功させたときのツイート

この記事では、なぜ Twitter で毎日風船を飛ばすようになったのか、この10年間で起こった出来事等々を語っていきたいと思います。

なぜ毎日風船を飛ばすのか

そもそも、私は人に誕生日がバレたくありません。 誕生日はその人の個人情報であるばかりでなく認証情報として使われることが有り、みだりに人に教えるのはセキュリティ的によろしくないと思っているからです。

例えば、(どことは言いませんが)ある病院の窓口で作らされたアカウントでは、パスワードは誕生日から勝手に決められ、ユーザーが自身で変更する方法は全く用意されていませんでした。 この病院の診察券をどこかで落としてしまい、そこから SNS を追跡するなどして誕生日がバレてしまうと、 ID とパスワードが揃ってしまい、不正な認証が通ってしまう危険があるわけです。

また、多くの Web サービスの「パスワードの再発行」画面では誕生日を要求してきます。 今でこそパスワードレスが普及し、誕生日を使うパスワード再発行フォームは珍しくなりましたが、10年前は当たり前にあったように思います。 パスワード再発行を他人に使われてアカウントを盗まれないようにするためにも、人に誕生日は教えたくないなと思っています。

https://share.timescar.jp/view/pwd/reissue.jsp の例

7pay のパスワードリセットがヤバかった例

↑これと考えは似ているかもしれない

というわけで、私は特に必要性がない場合3、誕生日を公開しないようにしています。

で、誕生日を公開しないとなると Twitter の誕生日欄は常に空白になり、私のアカウントでは風船が全く飛ばない状態になってしまうわけですが、 せっかく風船機能があるのに使えないのはつまらないですよね?

そこで、逆に風船を毎日飛ばすことを思いつきました。 毎日 Twitter の誕生日を更新すれば、たとえ真の誕生日に風船が飛んでいても、私のフォロワーの皆さんは私の真の誕生日に風船が飛んでいることに気付けないわけです。

この10年で起きたこと

2015年:初期実装

Twitter に、誕生日を更新する公開 API は存在しません。 これはイーロンマスク体制による API 有料化/廃止API が消えたとかとかではなく、最初からありません。 普通の人は誕生日の更新ってしないらしいですからね。 非公開 API を適当に HTTP POST することで更新できないかと検討したものの4、うまくいく方法は見つかりませんでした。

そのため、誕生日の更新はブラウザのエミュレート(スクレイピング)による、 Twitter Web の操作が必要となりました。

初期の実装は 「当時借りていたさくら VPS5 + Docker + Selenium for Ruby6 という構成で、これを OS の cron で毎日日付が変わったときに起動して誕生日を更新するというものでした。 これは見事成功し、2015年12月24日に初めて cron による無人での自動更新に成功しました7

成功のタイミングはたくさんお祝いされました(同じ人のリプライが多い気がするのは気のせい)

2016年~2018年 Selenium やサーバーの運用

当時の Selenium はなんか挙動が不安定で、気がついたら誕生日の更新が止まっていて風船が飛ばない日がよく発生していました。

また、私のサーバー管理が雑すぎてセキュリティ的にまずい時期もありました。

当時まだ大学院生でサーバー知識がゴミだったので許してほしい

2019年 puppeteer への移行

Puppeteer のロゴ

Puppeteer2018年1月12日にリリースされた、軽量なスクレイピングツールです。

当時、 Selenium が謎の死を遂げて誕生日更新に失敗するのに嫌気が差していた私は、最近リリースされた Puppeteer というやつが軽量に動作していいらしいぞという噂を聞いて、実際に移行を行いました

これにより実装は「さくら VPS + Docker + Puppeteer(node.js) + OS cron」という構成になりました。

結果的にはこれは大変良い判断で、 Selenium と比べ puppeteer では謎の死が発生しにくくなり、可用性が一気に上がりました。

2020年 GitHub Actions への移行

2019年の Puppeteer への移行により、 Puppeteer やサーバーインフラに起因する、すなわち私が原因の障害は少なくなっていましたが、この年は Twitter 側で仕様変更が度々発生し、スクレイピング実装の修正が必要になりました8。 公開 API ではなくスクレイピングというグレーゾーンな技術を使っているので仕方のないことですね……

また、社会人として昼間仕事をしていると、さくら VPS に置いている cron の面倒を見るのもだんだんつらくなってきました。

ちょうどいいことに、2019年11月から GitHub Actions が一般利用開始され、気前のいい事にパブリックリポジトリにおいては一定の実行時間までは無料で利用できるようになりました。

github.blog

ありがたいことに Github Actions は cron 機能も内包していて9、誕生日を毎日0時に更新するのにとても都合が良いことがわかり、2020年1月GitHub Actions に乗り換えました。

ここまででお気づきの方もいるかも知れませんが、この変更により、初期実装で使っていた技術構成はすべて他の技術に置き換えられてしまっていました。テセウスの船状態です。

2020年 pixe.la 導入

誕生日の自動更新の可用性が実際どのくらいあるのかが気になった私は、過去の誕生日更新成功率が何%あったのかを測定してみたくなりました。可用性99.9%みたいなことが言えると なんかかっこいい ですよね。

pixe.la

pixela は、草を生やせる Web サービスです。 ユーザー登録し、日付を指定してincrement APIを叩くと、その日に草が生えた状態の画像を生成してくれます。

このサービスを2020年5月に導入し、リポジトリREADME に草画像を載せることで、誕生日更新が直近ではどのくらい安定して実行できているのかを視覚的に表示することができるようになりました。

直近365日では3日障害発生している……

2021年 2FA 対応、 UA 偽装、新しいログインフローに対応……

実は、誕生日の自動更新を行っている都合上、当時の私の Twitter アカウントには二段階認証を設定することができない状態でした。 また、二段階認証の設定をしていない Twitter アカウントを使っていると、誕生日更新の直後に人間が Twitter にアクセスした時に毎日 reCAPTCHA を要求される状態でした。

↑こういうの

アクセス元が急激に変化しているのを不審に思った Twitter のセキュリティ機能が作動しているぽかったのですが、「まあ誕生日更新できているし、毎日 reCAPTCHA すればいいか~」くらいに思っていました。

ところが、2021年3月、銀行 ATM イーネットの公式アカウントが乗っ取られる事件が起きました10

www.itmedia.co.jp

今回の事件を見て、流石に対策しないとまずいなということで、本腰を入れて二段階認証をアカウントに設定しつつ、誕生日の自動更新時も認証が通るように実装を修正しました。

ちなみに、TOTPによる二段階認証をスクレイピングツールで突破するのは非常に簡単です。

https://github.com/gecko655/everyday-birthday/issues/10#issuecomment-804864700

また、 User Agent の偽装が必要になったり、 Twitter 側のログインページのデザインが大きく変更されたり、ログインフォームの 細かい DOM 構造がコロコロ高頻度に変わるなど、いろいろ変更の大きい一年でした。

デザイン変更でスクレイピングに失敗したことにキレている様子

2022~2023年 平和(ただしアカウントが凍結した)

この期間、誕生日自動更新の世界は平和で、大変安定的に運用ができていました。

ただし、2022年6月9日10時〜2022年10月6日12時の間、私の Twitter アカウントは凍結されてしまいました。今でも原因は不明です。多分誕生日自動更新とはなんの関係もないと思うのですが……

↓くわしくはこちらの記事へ gecko655.hatenablog.com

(2016年&2020年&)2024年 うるう年の更新に失敗する

2016年と2020年の2月29日は、誕生日更新ロジックがうるう年を考慮していなかったため誕生日の更新に失敗していました。 私の誕生年はうるう年でない1991年なのですが、当時の誕生日更新ロジックは存在しない1991年2月29日を誕生日に設定しようとして落っこちていました。

うるう年の2月29日は、1991年から最も近いうるう年である別の年を誕生年とするようロジックを変更し、2024年2月29日は 誕生日を1992年2月29日に変更して無事風船を飛ばすことに成功しました

しかし、翌3月1日に誕生日更新に失敗してしまいました。

うるう年の2月29日の次の日(3月1日)の誕生日更新時に、誕生日入力のフォームに(閏年でない)年→月→日の順に日付を入力すると、 年を入力した時点で 「閏年でない年の2月29日」を一時的に入力したことになり、このとき Twitter の誕生日入力フォームは年部分を消してしまうという仕様があることがわかりました

というわけで、うるう年対策は2016年、2020年に続き2024年も失敗に終わりました。 今回の「うるう年の3月1日に誕生日が更新できない」問題はすでに修正を実装済みで、次は2028年にその実装が動作するはずです。次はうまく動いてほしいですね……

2025年 ログインを辞めログインセッションを維持する実装に変更&近代化改修

2025年10月7日、 Puppeteer が Twitter へのログインに急に失敗するようになります。

どうも、なんらかの方法で Twitter が Puppeteer からのログインを弾くようになったようで、 User Agent 偽装などの突破方法が通用しなくなりました。

Twitter 上で解決方法を検索したところ、「もはやスクレイピングツールでログイン認証を通すのは諦めて、人がログインしたときのセッションクッキーをスクレイピングツールに食わせたほうがいい」という情報を見て、私もそれに追従することにしました11。 ログインが通らなくなったことで一時は誕生日更新の死を覚悟したのですが、なんとかなってよかったです。

終わりを覚悟したときの様子。なんとかなってよかった

その他、 Puppeteer に移行して以来コードベースが2019年当時からほとんど変わっていなかったため古臭いコードになっていた12のを、2025年の AI Agent パワーでいい感じに書き換えたりなどしました。AI は便利でいいですねぇ。


こんな長く書くつもり無かったのに10年分を振り返ったらめっちゃ長くなっちゃった。

また人を騙してしまった

毎日 Twitter のプロフィール画面で風船を飛ばすのはとても楽しいのですが、たまに新規のフォロワーを迎えると誤解が生じることがあります。

↑誤解が生じた例

↑2019年5月、声優の青山吉能さんの偽アカウントが出現し、そのお祝いを呟いたところ、エゴサに引っかかった上で誕生日を祝われた例(当該アカウントは凍結済みのため現存せず)

大きな問題が発生しているように見えますが、初対面の人とのトークデッキとして使えるので便利さが勝っています。 これからも人を騙し続けていこうと思います。

なお、これまでの人を騙してきた履歴はgecko655(@gecko655)/「また人を騙してしまった」の検索結果 - Twilog (ツイログ)で確認できます。

四半期に1人以上は騙されてる

Twitter 以外の SNS では

Misskey

Misskey には誕生日を変更する API が存在します! 誕生日を変更するニーズが満たされていてとても良いですね。

Misskey の誕生日を更新するリポジトリも作っており、運用していました が、 Misskey を全然使わなくなってしまったので、いつの間にか止まってました……

github.com

Facebook

Facebook で誕生日を変更できるのは1回だけのようです。残念。

仕方がないので4月1日(エイプリルフール)を設定してあります。

Instagram, Bluesky, mixi2

案外、多くの SNS には誕生日の設定がありません。 もし今後の機能追加で誕生日の設定ができるようになったら、誕生日を毎日更新できるか検証したいなと思っています。 mixi2 でスクレイピングをするのはあんまりやりたくないですが……

まとめ

思い返すと色々なことが有りましたが、数々の仕様変更に耐えながらなんとか10年間毎日誕生日を維持することができました。 今後も Twitter の機嫌がよほど悪くならなければ、毎日誕生日を維持していこうと思っています。

そして、ソースコードGitHub 上で無料公開13しています。 もしよろしければ、皆様も毎日を誕生日にして、365日風船を飛ばしてみませんか14? README.md の説明が不足している気がするので、わかりにくいところあれば Issue などにてご連絡ください。README.md への加筆を検討します。


  1. この記事では、 https://twitter.com でアクセスできる SNS サービスのことを一貫して "Twitter" と呼びます。
  2. 日本時間
  3. SNS 以外の Web サービスでも、誕生日の入力が必要なときはなるべく真の誕生日以外の日付を入力するようにしています。ただし、金融系、 EC サイトなどのお金が絡む Web サービスでは、誕生日の照合を取ってくる場合があるので、真の誕生日を入力しています。
  4. いわゆるリプレイ攻撃。今改めて考えると、 nonce とかリクエストハッシュとかで失敗していたんじゃないかと思う。
  5. 一番やっすいプランだったはず
  6. 当時のリポジトリ https://github.com/gecko655/everyday-birthday/tree/05b53a9615374b9ee7ea16f3f7db15b622d03899
  7. デバッグの意味では12月22日に初めて成功していたらしい https://x.com/gecko655/status/678979873818284032
  8. 画面レイアウトが変わるだけの簡単なやつは対応するだけでよいのだが、ログインチャレンジを求めてくることがあるのは画面遷移が変化して困った
  9. 余談ですが、さくら VPS の時に辛かった「 cron 実行のときだけ PATH が違うせいで、マニュアル実行したときと動作が違う」みたいなことも発生しなくなったのが地味に嬉しかった
  10. 現在は鍵垢みたいですね…… https://x.com/enetATM
  11. 後日、やっぱり UA 偽装でなんとかなるという報告が上がってきたので、スクレイピングによるログインは引き続きできた説がありますが、戻すのもめんどくさくて現在もセッションクッキーを使う実装のままになっています https://github.com/mikf/gallery-dl/issues/8362#issuecomment-3411493729
  12. 2020年に開発停止された moment.js を使っているとかパッケージ管理が yarn v1とか。
  13. The MIT License (MIT) Copyright (c) 2015 gecko655 https://github.com/gecko655/everyday-birthday/blob/master/LICENSE
  14. ただし、このソフトウェアを使ったことによって被ったいかなる損害について私は責任を取りません