自ドメインから送信したlogwatchがGmail宛に届かない。

logwatchを自分のドメインからGmail宛に送信しているのですが、ある日突然届かなくなりました。
迷惑メールにも入っていないし、logwatchコマンドも動作するため、メール送信時のトラブルのようです。
解決までにチェックしたことをメモとして残します。

環境

  • CentOS 8.1
  • Logwatch 7.4.3
  • Postfix 3.3.1
  • DNS設定はValue-Domain
  • 送信用のドメインはサブドメイン mail.example.jp を使用する。

maillogを確認する

 (host gmail-smtp-in.l.google.com[108.177.125.26] said: 550-5.7.26 This message does not have authentication information or fails to 550-5.7.26 pass authentication checks. To best protect our users from spam, the 550-5.7.26 message has been blocked. Please visit 550-5.7.26  https://support.google.com/mail/answer/81126#authentication for more 550 5.7.26 information. e15si7269825pfl.346 - gsmtp (in reply to end of DATA command))

This message does not have authentication information or fails to 550-5.7.26 pass authentication checks.

この設定で5年以上運用してたけど今までそんなこと一言も言ってなかったやんけお前…。送信ドメイン認証に対応してないので、そのチェックで弾かれたようです。
送信ドメイン認証のSPFとDKIMの設定を行います。

SPFレコードを設定する

以下の記事が大変詳しいため、こちらで説明できる事が特にないです。
自ドメインのDNSとPostfixをSPF/DKIM対応させてみた - Qiita

Value-Domainの場合の設定例は以下です。

txt mail v=spf1 ip4:{サーバのIPアドレス} ~all

DKIMレコードを設定する

SPFの記事を見ればOKです。

Value-Domainでサブドメインを使う場合、ちょっとだけ設定がややこしいかもしれない。
DKIM署名に失敗したときもメールは送信してほしいので、ADSPレコードの値はunknownとしました。
Value-Domainの場合の設定例は以下です。

txt {セレクタ名}._domainkey.mail v=DKIM1;k=rsa;p={公開鍵};
txt _adsp._domainkey.mail dkim=unknown

注意点として、v=DKIM1;(DKIMのバージョン)はレコードの一番最初に設定する必要があるため、p v kの順序で設定するとDKIMをPASSしません。(なぜこんなことを書いてるかというと、「CentOS DKIM Postfix」 でググって10位以内に出てくるITコンサル会社の技術ブログの記事が間違ってるからです。2年前の記事ですが、2年前でも設定通らないはずなんだよなぁ…。)
また、SPF, DKIM共にAレコードの設定は不要です。

SPF/DKIMレコードのチェックをする

Value-Domainの場合、DNS設定更新されるまで1時間はかかったので、ある程度待ってからテストしたほうがいいです。

Gmailで動作確認する

logwatch --mailto {Gmailのメールアドレス}でメールを飛ばして、メールが送信できるか確認します。SPFとDKIMを設定しておけば送信できるはずです。
受信したメールのソースを確認して、Authentication-Resultsにdkim=passとspf=passがあればOKです。

この設定するまで知らなかったのですが、アイコンが?のメールってドメイン認証が通ってないメールなんですね。連絡先にlogwatchの送信元を登録してるのに、やたら迷惑メール判定されていたのはこれが原因だったようです。

勉強になりました。

RTX1100をCATVで使う。

ヤマハのRTX1100を中古で買いました(送料込みで500円)。
研究室の先輩とオンラインで飲んでたときに「ヤマハのルータはいいよ~」と薦められたのと、ちょうど家のルータの機能がしょぼくて不満もあったので「勉強のためにも1台くらいほしいなぁ」と思ったからです。最初RTX1000を買おうとして、IPv6対応してないからやめろと止められたくらいには知識がありません。

シリアルケーブルなしでセットアップする

RTX1100は初期状態だとシリアルケーブルがないとセットアップできないのですが、MACアドレスからIPv6アドレスを計算する、もしくは ping ff02::2 でルータからのリプライをパケットキャプチャしてIPv6アドレスを取得するとtelnetから接続できるため、その方法を使いました。
私は以下のツールを使った上でWiresharkで答え合わせしました。計算結果と同じIPだったのでちょっと感動しました。
【ツール】MACアドレスをIPv6に変換

telnet 取得したIPv6アドレス で接続するとパスワードを聞かれますが、そのままEnterでコンソールにログインできました。
ファームウェアは最新のもの(RTX1100 Rev.8.03.94)でした。

必要最低限の設定

とりあえず、ドキュメントとか、ググって出てきたページを読みながら必要そうな設定をしました。

> administrator # パスワードをきかれるがそのままEnter

コンソールの文字セットをASCIIにして文字化けを防ぐ
# console character ascii

LAN1にIPアドレスを設定。私は192.168.2.1にしました
# ip lan1 address 192.168.2.1/24

LAN1ポートに接続した機器にDHCPでIPアドレスを振る
# dhcp service server
# dhcp server rfc2131 compliant except remain-silent
# dhcp scope 1 192.168.2.2-192.168.2.100/24 DHCPのIPアドレスの範囲

ログイン用パスワード変更
# login password
Old Password: そのままEnter
New Password: 新しいパスワード

管理者用パスワード変更
# administrator password
Old Password: そのままEnter
New Password: 新しいパスワード

時刻変更
# timezone jst
# date 2020/7/24
# time 17:13

sshで接続可能にする
# login user admin YOUR_PASSWORD
# sshd host key generate
# sshd service on
# sshd host 192.168.2.1-192.168.2.254 sshdにアクセスできるホスト

設定保存
# save

192.168.2.1 にsshできるのを確認したらtelnetを無効化する
# telnetd service off

設定保存
# save
# exit

CATV向けの設定

CATVインターネットなどイーサネット回線を利用する
WAN側の設定と、NATの設定と、フィルターの設定はヤマハのサイトのconfigをそのまま使いました。雑ゥ~。RTX1100は対象機種になってませんが、特にエラーは出ませんでした。

接続した

LAN2ポート(WAN)にケーブルモデムを接続・LAN1ポート(LAN)にPCを接続して動作を確認しました。おお~動いた~~~。ポートスキャンもしましたがちゃんと外からアクセスできないようになっています。すごい。

あれ?

ケーブルモデム(ARRIS CM820C)のLinkのLEDは、緑点滅が1000BASE-T、オレンジで点滅している場合、100BASE-Tで通信しているのですが、ルータをRTX1100に変えたらオレンジに変わってしまいました。
今契約してるプランは最大速度160Mbpsなので、100BASE-Tで通信されると困ります。スピードテストをしても、いつもは160Mbps出るのに100Mbps近くしか出ません。
ここまできてようやくRTX1100が1000BASE-Tに対応していないことに気づきました。おせえよ。
発売時期がBフレッツかADSLの時期なので対応しているわけがないのですが、全然考えてませんでしたね…。とりあえずケーブルモデムに直接つなげて運用するのは諦めました。

使ってみた感想

家で使ってるルータで設定できない箇所も細く設定できて、かつ、コマンドラインベースで設定できるのはかなり楽なことがわかったので、RTX1200かRTX810の安いやつが手に入ったら使いたい気持ちです。
RTX1100はIPv6 IPoEに対応しているので、マンションのVDSLで100Mbpsしか出ないならこのルータで全然問題ないと思いました。今住んでいるところがVDSL回線だったのでCATVを契約しているのですが、CATV契約してなかったらそのまま使ってたと思います。

retrorocket.bizのサーバでrm -rf /* をやらかした。

今日の夕方

別の用事をしながら使い捨てのシェルスクリプトを書いていました。

#!/bin/bash

TARGET_DIR=/target/dir

## 中略
rm -rf ${TARGET_DI}/* # あっ
## 略

やりました。やってしまった。し、しんだ~~~ほあああああああ~~~~。
upicoとかtwimageとかのアプリ実行用ユーザで作業していたので、rootではなかったのが救いですが、ホームディレクトリの中身は全部吹っ飛びました。Ctrl+Cしたけど間に合わなかった。アプリ自体は/var配下にあるのですが、そちらは無事でした。
各アプリはホームディレクトリの中に設定値を持っているため、アプリを再起動すると動かなくなります。なお、listは他のアプリとちょっと別の動かし方をしていて、毎回プロセスを生成しているため、即死しました。

どうしたか

ファイルシステムがxfsなのですが、xfsでファイルを復元する方法がなさそうなので、諦めて自力でファイルを修復しました。.sshと.vimrcとfishの設定飛んだのが痛い。

どうすべきだったか

今回は自分のサーバなので良かったですが、これが違うサーバだったら…と思うとぞっとします。以下反省点。

ポケモン剣盾のランクバトルで1人しか使ってなさそうなポケモンを探す。

こういう記事を書きました。
ポケモン剣盾のランクバトルのバトルデータをMetabaseで可視化する。 - Qiita
JSONからだとアプリから参照できないポケモンの情報も参照できるので、1人しか使ってなさそうなポケモンもいくつか検索にひっかかります。
ダブルバトルでコロモリとか何に使うのかめちゃくちゃ興味があります。他にもそういうポケモンがいそうでわくわくしたので、Metabaseで検索してみることにしました。

JSONを加工してCSVにする

わざ・とくせい・もちもののデータをそれぞれ別のテーブルに保存するため、それぞれを別々のCSVに変換します。
Python3を使っています。

import json

pokedex = ""
#  https://resource.pokemon-home.com/battledata/js/bundle.js の図鑑と持ち物情報を抜き出してjsonにしたものを読み込む
with open("./bundle.json", "r") as json_open:
    pokedex = json.load(json_open)

pdetail = ""
# https://resource.pokemon-home.com/battledata/ranking/{シングル or ダブルのID}/{rstの値}/{ts2の値}/pdetail-{1から5} をcatで全部連結させたjsonを読み込む
# 私はダブルバトルのプレイヤーなので、ダブルバトルのJSONだけ使っています。
with open("./pdetail-1-5.json", "r") as json_open:
    pdetail = json.load(json_open)

waza_str = ""
item_str = ""
tokusei_str = ""
for pokenum in pdetail.keys():
    for p_detail_id in pdetail[pokenum].keys():
        name = pokedex["poke"][int(pokenum) -1]
        if p_detail_id != "0": # 0以外はフォルム・性別・リージョンetc違いなので分けて扱う。わざをみればどのフォームか分かるので数字だけでも特に問題ない。
            name = name + p_detail_id
        for pokewaza in pdetail[pokenum][p_detail_id]["temoti"]["waza"]:
            waza_str = waza_str + name + "," + pokedex["waza"][pokewaza["id"]] + "," + pokewaza["val"] + "n"
        for pokeitem in pdetail[pokenum][p_detail_id]["temoti"]["motimono"]:
            item_str = item_str + name + "," + pokedex["item"][pokeitem["id"]] + "," + pokeitem["val"] + "n"
        for poketokusei in pdetail[pokenum][p_detail_id]["temoti"]["tokusei"]:
            tokusei_str = tokusei_str + name + "," + pokedex["tokusei"][poketokusei["id"]] + "," + poketokusei["val"] + "n"

with open("waza.csv", mode='w') as f:
    f.write(waza_str)
with open("item.csv", mode='w') as f:
    f.write(item_str)
with open("tokusei.csv", mode='w') as f:
    f.write(tokusei_str)

CSVをSQLite3に変換

$ sqlite3 double_move.db
sqlite> create table move(name text, move text, adoption_rate real); # わざテーブルの作成
sqlite> .mode csv
.import ./waza.csv move
# item, tokuseiも同様のテーブルを作成してインポートする

作ったDBをmetabaseに読み込む

Qiitaの記事と同じなので割愛。

1人しか使ってなさそうなポケモンを探す

推理が雑ですが、とくせいともちものの採用率が100%、かつ、使われてるわざの数が4から6なら、使ってる人が1人(もしくはその人のレンタルパ)と言えそうです。
3つのテーブルをjoinして検索します。

metabaseのjoin

全部joinしてフィルターをかけるとこんな感じ。


たまもちのコイキングとかいう気が狂ってるとしか思えないのがいますね。どういう構築なんだこれ。
このワンリキーはカ・エールさん究極激可愛運勝ビートのワンリキーですね。すごい。

6/12のデータを検索したところ、ダブルバトルで1人しかつかってなさそうなポケモンは以下であることがわかりました。
(型が1つしかなさそうなポケモンもいるので、実際は1人かどうかはわからないです)
ロコンはアローラで、ダルマッカはガラルですね。バスラオはJSONの中を見ないとどっちがどっちかわかんねえな。
ホエルコは究極激可愛運勝ビートのホエルコですね。
みんな個性的で面白いなと思います。

ポケモンの名前	とくせい	とくせいの採用率	もちもの	もちものの採用率	わざ	わざの採用率
フシギソウ	ようりょくそ	100	しんかのきせき	100	てだすけ	100
フシギソウ	ようりょくそ	100	しんかのきせき	100	ねむりごな	100
フシギソウ	ようりょくそ	100	しんかのきせき	100	まもる	100
フシギソウ	ようりょくそ	100	しんかのきせき	100	やどりぎのタネ	47.1
フシギソウ	ようりょくそ	100	しんかのきせき	100	ギガドレイン	52.9
ロコン1	ゆきふらし	100	しんかのきせき	100	こおりのつぶて	100
ロコン1	ゆきふらし	100	しんかのきせき	100	つぶらなひとみ	100
ロコン1	ゆきふらし	100	しんかのきせき	100	オーロラベール	100
ロコン1	ゆきふらし	100	しんかのきせき	100	フリーズドライ	100
クサイハナ	ようりょくそ	100	しんかのきせき	100	あまえる	87.5
クサイハナ	ようりょくそ	100	しんかのきせき	100	ちからをすいとる	12.5
クサイハナ	ようりょくそ	100	しんかのきせき	100	ねむりごな	100
クサイハナ	ようりょくそ	100	しんかのきせき	100	ギガドレイン	100
クサイハナ	ようりょくそ	100	しんかのきせき	100	ヘドロばくだん	100
ワンリキー	ノーガード	100	しんかのきせき	100	はたきおとす	100
ワンリキー	ノーガード	100	しんかのきせき	100	ばくれつパンチ	100
ワンリキー	ノーガード	100	しんかのきせき	100	れいとうパンチ	100
ワンリキー	ノーガード	100	しんかのきせき	100	バレットパンチ	100
コイキング	びびり	100	いのちのたま	100	じたばた	100
コイキング	びびり	100	いのちのたま	100	たいあたり	100
コイキング	びびり	100	いのちのたま	100	とびはねる	100
コイキング	びびり	100	いのちのたま	100	ハイドロポンプ	100
ピチュー	ひらいしん	100	きあいのタスキ	100	てだすけ	100
ピチュー	ひらいしん	100	きあいのタスキ	100	ねこだまし	100
ピチュー	ひらいしん	100	きあいのタスキ	100	ほっぺすりすり	100
ピチュー	ひらいしん	100	きあいのタスキ	100	リフレクター	100
イノムー	あついしぼう	100	こだわりハチマキ	100	いわなだれ	100
イノムー	あついしぼう	100	こだわりハチマキ	100	こおりのつぶて	100
イノムー	あついしぼう	100	こだわりハチマキ	100	つららおとし	100
イノムー	あついしぼう	100	こだわりハチマキ	100	10まんばりき	100
ホエルコ	みずのベール	100	こだわりメガネ	100	しおふき	100
ホエルコ	みずのベール	100	こだわりメガネ	100	れいとうビーム	100
ホエルコ	みずのベール	100	こだわりメガネ	100	ハイドロポンプ	100
ホエルコ	みずのベール	100	こだわりメガネ	100	ハイパーボイス	100
ヒンバス	どんかん	100	きあいのタスキ	100	さいみんじゅつ	100
ヒンバス	どんかん	100	きあいのタスキ	100	ひかりのかべ	100
ヒンバス	どんかん	100	きあいのタスキ	100	ふぶき	100
ヒンバス	どんかん	100	きあいのタスキ	100	れいとうビーム	100
ヨマワル	おみとおし	100	しんかのきせき	100	かげうち	100
ヨマワル	おみとおし	100	しんかのきせき	100	てだすけ	100
ヨマワル	おみとおし	100	しんかのきせき	100	サイドチェンジ	78.6
ヨマワル	おみとおし	100	しんかのきせき	100	トリックルーム	100
ヨマワル	おみとおし	100	しんかのきせき	100	ナイトヘッド	21.4
ビークイン	きんちょうかん	100	バンジのみ	100	とどめばり	100
ビークイン	きんちょうかん	100	バンジのみ	100	とんぼがえり	100
ビークイン	きんちょうかん	100	バンジのみ	100	まもる	100
ビークイン	きんちょうかん	100	バンジのみ	100	クロスポイズン	100
ゴンベ	あついしぼう	100	しんかのきせき	100	じばく	100
ゴンベ	あついしぼう	100	しんかのきせき	100	のしかかり	100
ゴンベ	あついしぼう	100	しんかのきせき	100	ばかぢから	100
ゴンベ	あついしぼう	100	しんかのきせき	100	れいとうパンチ	100
ガントル	くだけるよろい	100	じゃくてんほけん	100	いわなだれ	100
ガントル	くだけるよろい	100	じゃくてんほけん	100	じだんだ	100
ガントル	くだけるよろい	100	じゃくてんほけん	100	だいばくはつ	100
ガントル	くだけるよろい	100	じゃくてんほけん	100	まもる	100
コロモリ	てんねん	100	しんかのきせき	100	ふういん	100
コロモリ	てんねん	100	しんかのきせき	100	まもる	100
コロモリ	てんねん	100	しんかのきせき	100	サイドチェンジ	100
コロモリ	てんねん	100	しんかのきせき	100	トリックルーム	100
モンメン	いたずらごころ	100	ねらいのまと	100	おきみやげ	100
モンメン	いたずらごころ	100	ねらいのまと	100	すいとる	20
モンメン	いたずらごころ	100	ねらいのまと	100	すりかえ	100
モンメン	いたずらごころ	100	ねらいのまと	100	てだすけ	100
モンメン	いたずらごころ	100	ねらいのまと	100	グラスフィールド	80
バスラオ	てきおうりょく	100	しんぴのしずく	100	あばれる	100
バスラオ	てきおうりょく	100	しんぴのしずく	100	いのちがけ	100
バスラオ	てきおうりょく	100	しんぴのしずく	100	アクアジェット	100
バスラオ	てきおうりょく	100	しんぴのしずく	100	アクアブレイク	100
バスラオ1	てきおうりょく	100	きあいのタスキ	100	しっぽをふる	100
バスラオ1	てきおうりょく	100	きあいのタスキ	100	だくりゅう	100
バスラオ1	てきおうりょく	100	きあいのタスキ	100	みずびたし	100
バスラオ1	てきおうりょく	100	きあいのタスキ	100	アクアジェット	100
ダルマッカ1	はりきり	100	しろいハーブ	100	ばかぢから	100
ダルマッカ1	はりきり	100	しろいハーブ	100	まもる	100
ダルマッカ1	はりきり	100	しろいハーブ	100	れいとうパンチ	100
ダルマッカ1	はりきり	100	しろいハーブ	100	フレアドライブ	100
バチュル	ふくがん	100	きあいのタスキ	100	いとをはく	100
バチュル	ふくがん	100	きあいのタスキ	100	いやなおと	100
バチュル	ふくがん	100	きあいのタスキ	100	ふいうち	100
バチュル	ふくがん	100	きあいのタスキ	100	むしのていこう	100
テッシード	てつのトゲ	100	しんかのきせき	100	てっぺき	100
テッシード	てつのトゲ	100	しんかのきせき	100	はたきおとす	100
テッシード	てつのトゲ	100	しんかのきせき	100	まもる	100
テッシード	てつのトゲ	100	しんかのきせき	100	やどりぎのタネ	100
ジヘッド	はりきり	100	しんかのきせき	100	かみくだく	100
ジヘッド	はりきり	100	しんかのきせき	100	げきりん	100
ジヘッド	はりきり	100	しんかのきせき	100	こおりのキバ	83.3
ジヘッド	はりきり	100	しんかのきせき	100	ばかぢから	100
ジヘッド	はりきり	100	しんかのきせき	100	ほのおのキバ	16.7
ヤンチャム	きもったま	100	しんかのきせき	100	ともえなげ	100
ヤンチャム	きもったま	100	しんかのきせき	100	まもる	100
ヤンチャム	きもったま	100	しんかのきせき	100	ドレインパンチ	100
ヤンチャム	きもったま	100	しんかのきせき	100	ビルドアップ	100
シルヴァディ5	ARシステム	100	ロックメモリ	100	つるぎのまい	100
シルヴァディ5	ARシステム	100	ロックメモリ	100	アイアンヘッド	100
シルヴァディ5	ARシステム	100	ロックメモリ	100	サイコファング	100
シルヴァディ5	ARシステム	100	ロックメモリ	100	マルチアタック	100
シルヴァディ15	ARシステム	100	ドラゴンメモリ	100	くさのちかい	100
シルヴァディ15	ARシステム	100	ドラゴンメモリ	100	だいばくはつ	100
シルヴァディ15	ARシステム	100	ドラゴンメモリ	100	つるぎのまい	100
シルヴァディ15	ARシステム	100	ドラゴンメモリ	100	まもる	100
ジャランゴ	ぼうおん	100	しんかのきせき	100	まもる	100
ジャランゴ	ぼうおん	100	しんかのきせき	100	アイアンヘッド	93.8
ジャランゴ	ぼうおん	100	しんかのきせき	100	ドラゴンクロー	6.3
ジャランゴ	ぼうおん	100	しんかのきせき	100	ドレインパンチ	100
ジャランゴ	ぼうおん	100	しんかのきせき	100	ビルドアップ	100
ヒバニー	リベロ	100	こだわりハチマキ	100	たいあたり	14.3
ヒバニー	リベロ	100	こだわりハチマキ	100	とびはねる	85.7
ヒバニー	リベロ	100	こだわりハチマキ	100	とびひざげり	98.4
ヒバニー	リベロ	100	こだわりハチマキ	100	なきごえ	14.3
ヒバニー	リベロ	100	こだわりハチマキ	100	ふいうち	98.4
ヒバニー	リベロ	100	こだわりハチマキ	100	ブレイズキック	85.7
ラビフット	リベロ	100	いのちのたま	100	すてみタックル	83.3
ラビフット	リベロ	100	いのちのたま	100	とびひざげり	83.3
ラビフット	リベロ	100	いのちのたま	100	とんぼがえり	16.7
ラビフット	リベロ	100	いのちのたま	100	ふいうち	16.7
ラビフット	リベロ	100	いのちのたま	100	ダストシュート	100
ラビフット	リベロ	100	いのちのたま	100	フレアドライブ	100

今回はSQL書いたほうが早そうでしたが、こういうデータが簡単にとれるのでMetabaseは便利ですね。

追記

とくせい(もしくはもちもの)だけ途中で変えてわざは同じってパターンもありそうなので、フィルターを追加した方が良さそうですね。
ドラメシヤはこんな感じなので、使ってる人が同じに見えました。

ドラメシヤ	92.3	のろわれボディ	100	きあいのタスキ	100	てだすけ
ドラメシヤ	92.3	のろわれボディ	100	きあいのタスキ	100	でんこうせっか
ドラメシヤ	92.3	のろわれボディ	100	きあいのタスキ	100	でんじは
ドラメシヤ	92.3	のろわれボディ	100	きあいのタスキ	100	まとわりつく
ドラメシヤ	7.7	すりぬけ	100	きあいのタスキ	100	てだすけ
ドラメシヤ	7.7	すりぬけ	100	きあいのタスキ	100	でんこうせっか
ドラメシヤ	7.7	すりぬけ	100	きあいのタスキ	100	でんじは
ドラメシヤ	7.7	すりぬけ	100	きあいのタスキ	100	まとわりつく

ポケモンホームのバトルデータ(ランクバトル)のJSONを解析する。

概要

ポケモンホームのバトルデータ、UIがクソすぎるとても癖があるので、自分で加工したいと思いました。
バトルデータの中身は普通のWebページで、中でWeb API的なものが使われているので、自分でこのAPIを叩けばクソみてえな癖のあるUIを使わなくて済む上に検索もできます。いいことしかない。

ちょっとJSONの量が多いので記事を折りたたみます。続きを読むからどうぞ。

2020/08/17追記

せいかくが取得できるようになったので、書き直しました

ランクバトルのシーズン情報用のJSONを取得する

ランクバトルの場合、APIを実行するために、どのシーズンのランクバトルかを示すIDと、ランクバトルのデータの更新日時を示す数字が必要なので、その値が取得できるAPIを叩きます。

リクエスト

スマホ向けのアプリのAPIなのでUAは偽装しています。

curl 'https://api.battle.pokemon-home.com/cbd/competition/rankmatch/list' \
  -H 'accept: application/json, text/javascript, */*; q=0.01' \
  -H 'countrycode: 304' \
  -H 'authorization: Bearer' \
  -H 'langcode: 1' \
  -H 'user-agent: Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Mobile Safari/537.36' \
  -H 'content-type: application/json' \
  -d '{"soft":"Sw"}'

レスポンス

後で以下でコメントをつけた箇所の値を使います。

{
  "code": 200,
  "detail": 0,
  "list": {
    "7": {
      "10072": { // ダブルバトルのID
        "name": "シーズン7",
        "start": "2020/06/01 13:00",
        "end": "2020/07/01 08:59",
        "cnt": 147244, // (参加人数)
        "rule": 1, // (ダブルバトル)
        "season": 7,
        "rst": 0, // 月の上旬・中旬・下旬で分かれてるっぽい
        "ts1": 1591187503, // バトルの情報はこちらの値を使う。情報の更新日時のUnix Time
        "ts2": 1591187515, // ポケモンの情報はこちらの値を使う。情報の更新日時のUnix Time
        "reg": "000000248"
      },
      "10071": { // シングルバトルのID
        "name": "シーズン7",
        "start": "2020/06/01 13:00",
        "end": "2020/07/01 08:59",
        "cnt": 147202, // (参加人数)
        "rule": 0, // (シングルバトル)
        "season": 7,
        "rst": 0,
        "ts1": 1591187503,
        "ts2": 1591187515,
        "reg": "000000247"
      }
    }, // 以下略
}

この記事を書いた時は、更新間隔は1時間に1回で、毎時31分45秒位に更新していました。

ポケモンの情報を取得する

UI上ではランキング外のポケモンの情報も、APIからは取得できます。この記事を書いた時は220匹分記録がありました。結構多い。

リクエスト

ランクバトルのシーズン情報用のJSONの値を使って、ポケモンの情報を取得します。

curl -XGET 'https://resource.pokemon-home.com/battledata/ranking/{シングル or ダブルのID}/{rstの値}/{ts2の値}/pdetail-{1から5の値。全国図鑑を5分割している}'  \
# 例:2020-06-03 22:31:56時点のシーズン7のダブルの図鑑番号が後半のポケモン
# https://resource.pokemon-home.com/battledata/ranking/10072/0/1591191116/pdetail-5
      -H 'user-agent: Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Mobile Safari/537.36'  \
      -H 'accept: application/json'

レスポンス

図鑑番号に対応したポケモンの情報が取得できます。

以下のJS(bundle.js)が技データやポケモンの特性・持ち物・性格のDBになっているので、DBのIDと照らし合わせると、目当てのポケモンの情報がわかるようになっています。作りがはちゃめちゃすぎる。
特性・持ち物のDB: https://resource.pokemon-home.com/battledata/js/bundle.js
bundle.jsについてはJSONではなく、ただのJavaScriptなので、必要な情報だけ抜き出して加工する必要があります。

以下はAPIのレスポンスです。フォーム違いのポケモンの場合、図鑑番号は共通で、フォームのIDが異なる作りになっています。

{
  "810": { // 図鑑No.810はサルノリ
    "0": { // フォルムのID。0以外は性別・リージョン・フォルム違い。例えば、ロトムなら1が火で2が水。
      "temoti": {
        "waza": [ // おぼえているわざ
          {
            "id": "10", // わざのID10はひっかく
            "val": "67.0" // 採用率。67%のサルノリが使用する
          },
          {
            "id": "45", // なきごえ
            "val": "67.0"
          },
          // 以下省略
        ],
        "tokusei": [ // とくせい
          {
            "id": "229", // グラスメイカー
            "val": "97.5" // 採用率
          },
          {
            "id": "65",
            "val": "2.5"
          }
        ],
        "seikaku": [ // せいかく
          {
            "id": "3", // いじっぱり
            "val": "65.0"
          },
          {
            "id": "13",
            "val": "32.5"
          },
          // 以下省略
        ],
        "motimono": [ // もちもの
          {
            "id": "275", // きあいのタスキ
            "val": "97.5"
          }
        ],
        "pokemon": [ // 一緒にバトルチームに入れられているポケモン
          {
            "id": 813, // ヒバニー
            "form": 0 // フォルムのID。(ヒバニーは0しかない。)
          },
          {
            "id": 815,
            "form": 0
          },
          // 以下省略
        ]
      },
      "lose": {
        "waza": [ // このポケモンを倒したわざ
          {
            "id": "814",
            "val": "9.4"
          },
          // 以下省略
        ],
        "pokemon": [ // このポケモンを倒したポケモン
          {
            "id": 212,
            "form": 0
          },
          // 以下省略
          }
        ]
      },
      "win": {
        "waza": [ // このポケモンが相手を倒したわざ
          {
            "id": "803",
            "val": "100.0"
          }
        ],
        "pokemon": [ // このポケモンが倒したポケモン
          {
            "id": 812,
            "form": 0
          },
         // 以下省略
        ]
      }
    }
  },

面白いですね。bundle.jsの情報をsqlに書き込んだら自分用のDBが作れそうです。
過去の更新時間のUnixTimeさえわかっていれば、過去のデータも参照可能なようです。例えば以下のJSONは取得可能ですね。

# 例:2020-06-03 22:31:56時点のシーズン7のダブルの図鑑番号が後半のポケモン
# https://resource.pokemon-home.com/battledata/ranking/10072/0/1591191116/pdetail-5

トレーナーランキングを取得する(1000位まで)

リクエスト

ランクバトルのシーズン情報用のJSONの値を使って、トレーナーのランキング情報を取得します。

curl -XGET 'https://resource.pokemon-home.com/battledata/ranking/{シングル or ダブルのID}/{rstの値}/{ts1の値}/traner-1' \
# 例:シーズン7のダブルなら https://resource.pokemon-home.com/battledata/ranking/10072/0/1591183903/traner-1 \
    -H 'user-agent: Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Mobile Safari/537.36'  \
    -H 'accept: application/json" -H "Accept-Encoding:gzip,deflate' -H 'accept-language: ja' --compressed --raw -o trainer.json.gz

レスポンス

gzipを解凍するとランキングが見られます。

[
    {
        "rank": 1,
        "rating_value": "1768534",
        "icon": "xxx.png",
        "name": "めっちゃ強い人",
        "lng": "1"
    },
    {
        "rank": 2,
        "rating_value": "1761355",
        "icon": "xxx.png",
        "name": "すごい強い人",
        "lng": "1"
    },
    {
        "rank": 3,
        "rating_value": "1759116",
        "icon": "xxx.png",
        "name": "とんでもなく強い人",
        "lng": "2"
    },
    // 以下略
]

UI上レートは4桁までしか表示されないけど、内部的には6桁で保持されてるみたいですね。面白いなー。