開発financial-data

サムスンのセグメント別財務を8期分取得し、トップに「メモリーメーカー動向」カードを新設した

メモリメーカーの業績を継続的に追える場所をサイトに作りたかった。第一弾はサムスン電子。直近8四半期(2Q24〜1Q26)のセグメント別の売上高・営業利益・営業利益率と、全社の粗利率を取得して、トップページに「メモリーメーカー動向」のカードを1枚足した。今後 SKハイニックスや台湾勢の月次売上をデータを足すだけで増やせる土台にするのが狙いだ。

1日では終わらなかった。データ取得とチャート部品まで固めて、ページ実装は翌日に持ち越した。その試行錯誤を記録しておく。


なぜセグメント別を、しかも8期分なのか

メモリ業界はサイクルが激しい。AIサーバー向けの高帯域メモリ(HBM)が効きはじめてから、半導体部門の利益が一気に振れる。1四半期のスナップショットでは何も読めない。底からどう戻したのかを並べて初めて意味が出る。だから時系列で8期分、しかもセグメント別に分けて取ることにした。

サムスンは家電・モバイルの DX、半導体の DS、ディスプレイの SDC、車載の Harman と部門が分かれている。メモリの動きを見たいなら、全社の数字を眺めていても DX の好不調に埋もれてしまう。DS だけを切り出して追える形にする必要があった。

agent-browser での取得 — CSV検索でタイムアウトした

データの取り方を Claude Code に任せた。公式IRの四半期 Earnings Release(PDF)に「Results by Business Segment」というセグメント別の数表があり、ここが原典になる。ただし PDF からのテキスト抽出は、売上と営業利益が左右2カラムで交錯していて、数値がどの行に属するのか崩れた。テキスト抽出を信じると数字が1つずれる事故が起きる。

結局、該当ページを画像として視覚的に読み取らせるのが一番固かった。8本の PDF の「セグメント数表ページ」をそれぞれ特定して、当四半期の列から値を拾わせた。隣り合う四半期の PDF には重複する期があるので、その重複値が一致するかで整合性を確かめた。一致したので取得値は信用できる。

詰まりもあった。取得した値を一時 CSV にまとめる過程で、CSV を探索する処理がタイムアウトして止まった。原因と回避策は .claude/issues/ に記録に残してある。揮発する一時ファイルに依存しないよう、確定値はそのままデータファイル(samsungSegments.ts)に直接書き込んで、CSV を後から参照しない構成にした。

WebFetch がペイウォールやボット対策で弾かれる場面も多かった。そういうときは agent-browser(自分のログイン済み Chrome を裏で操作するブラウザ自動化)にフォールバックする。これで「アクセスできませんでした」で止まらずに済む。

セグメント区分の変更には「取れる分だけ取る」で対応した

着手前から、HBM 周りでセグメント区分が変わっている可能性は読んでいた。実際、資料のフォーマットは年度で揺れていた。2Q24・3Q24 は数値が小数2桁、4Q24 以降は1桁に丸められている。区分が完全に揃わない期があるなら、無理に埋めず取れる分だけ取る方針にした。

具体的には、データ構造で欠損を null として許容した。セグメント別の粗利率はサムスンが開示していないので、粗利・粗利率は全社ベースだけにとどめた。DS 内のメモリは売上のみ開示で営業利益の内訳がないので、そこも欠損として扱う。無いものを推計でこしらえると、後で自分が嘘の数字に騙される。欠損は欠損のまま持つのが正しい。

数字の動き自体は鮮明だった。DS(半導体)の営業利益率は 2Q25 の 1.4%(メモリ不況の底)から、1Q26 に大きく跳ね上がった。全社の粗利率も同じ向きに戻している。AIメモリの超サイクルが効いているのだが、ここでは投資判断はしない。あくまでデータを取得して並べた、という作業の記録にとどめる。

インデックスのカード化 — 銘柄別にさらに分割する設計判断

可視化の入口をどう作るかで少し考えた。トップにいきなりサムスンの表を置くのは違う。今後 SKハイニックスや台湾メーカーが増えるからだ。

そこで2階層に分けた。トップ / には「メモリーメーカー動向」のカードを1枚だけ置く。その先の /memory-makers ハブでメーカーをカードでフラットに並べ、各メーカーの個別ページ /memory-makers/[maker] の中で、四半期業績・月次売上といったデータ種別ごとにセクションを分ける。

この分割の肝は、メーカーを足す=データファイルを1つ追加するだけで済むようにしたこと。データの種類(四半期セグメント/月次売上)を判別する型を切って、レジストリに登録すればハブにカードが生え、個別ページが生成される。SKハイニックスは「四半期」、台湾勢は「月次」と性質が違うが、同じ仕組みに乗せられる。

チャートは Chart.js を使わず SVG の自前描画にした。CDN 読み込みや初期化タイミングに依存すると、静的サイト生成(SSG)で中身が空のまま出力されることがある。SVG なら描画の実体がそのまま HTML に乗るので、SEO 面でも初回表示のちらつき面でも堅い。データも8四半期と少量なので、自前で十分だった。

営業利益率の計算など、数字を加工する部分は純粋関数に切り出して app/utils/memorySegments.ts に置いた。opMargin(営業利益÷売上、売上が0以下なら null を返す)のような小さな関数を組み合わせて、チャート用の系列やラベルを作る。副作用がないのでテストしやすく、Vitest の対象にできる。

// 営業利益率(%) = 営業利益 / 売上 × 100。売上が 0 以下なら null。
export const opMargin = (op: number, sales: number): number | null =>
  sales > 0 ? (op / sales) * 100 : null

欠損や赤字をそのまま null や負値で扱うので、チャート側は点を飛ばしたり0基準線をまたいだりして描く。「無いものは無い」をデータからUIまで貫いた。

翌日への引き継ぎ

今日でデータ基盤とチャート部品まで固めた。実装済みは次の通り。

  • データ層 app/data/memory-makers/(型・サムスン8四半期実データ・レジストリ・バレル)
  • 純粋関数 app/utils/memorySegments.ts
  • Vitest tests/memorySegments.test.ts(次回まず走らせて通す)
  • SVG折れ線チャート app/components/memory-makers/SegmentLineChart.vue(props駆動・副作用なし)

残りはページ実装と小改変だ。1日で全部やろうとして雑にページを作るより、土台を確かめてから組んだ方がいい。引き継ぎメモ(memo/2026-06-01/memory-makers-handoff.md)に、残タスクの実装方針まで詳しく書いて翌日へ回した。

  • ハブページ app/pages/memory-makers/index.vue
  • 個別ページ app/pages/memory-makers/[maker].vue(未登録メーカーは404)
  • トップ app/pages/index.vue にカード1枚追加
  • パンくず app/utils/breadcrumbs.ts にラベル追加
  • prerender seed に /memory-makers を追加
  • 検証(pnpm test:run → dev で3ページ目視)

SKハイニックスの方は別働で取得を進めたが、こちらは難所にぶつかった。メモリ専業ゆえに事実上「半導体」単一セグメントで、DRAM/NAND/HBM 別の粗利・営業利益は公式に開示されていない。さらに古い3期(2018〜2020)の確定粗利は無料サイトが軒並み直近5年止まりで届かず、監査済み財務(DART)の自動抽出を試みたが、会社選択のモーダルがヘッドレス操作を拒み続けて今回は完了できなかった。こちらも進捗を引き継ぎメモ(memo/2026-06-01/sk-hynix-segment-financials-handoff.md)に残して翌日へ持ち越した。


メモリは数字が荒く振れる業界だから、点ではなく線で、しかも部門ごとに切って追える場所が欲しかった。今日できたのはサムスン1社分のデータと、それを継続的に並べていく器の半分。器が固まれば、あとは銘柄を足していくだけになる。明日はページを2本組んで、トップから実際にたどれる形にする。