生活の跡

個人的な備忘録

FuelPHPでe-StatのAPIから国勢調査の人口集計を取得する

概要

FuelPHPに慣れてきたので、外部APIからデータを取得する処理を書いてみたいと思います。
試しに、e-Stat の APIから国勢調査の人口集計を取得してみます。前半ではFuelPHPを使わずに、e-Stat の APIの使い方を確認していきます。
なお、取得するデータの形式はいくつか選べますが、今回はJSON形式で取得します。

www.e-stat.go.jp

環境

  • FuelPHP 1.8.2
  • php 5.6

準備

e-Stat の APIを使用するためには、上記のリンクからユーザ登録をして、アプリケーションIDを取得する必要があります。アプリケーションIDは、ログイン後に「マイページ」>「アプリケーションID発行」と進むと発行できます。

e-Stat API の使い方

まずは、e-Stat API の使い方を確認します。

リクエストURLの生成

APIで提供されているデータは、こちらのページからアクセスできます。

提供データ | 政府統計の総合窓口(e-Stat)−API機能

今回は、次のリンク先の表00310「年齢(各歳),男女別人口,年齢別割合,平均年齢及び年齢中位数(総数及び日本人)」を使います。

国勢調査 平成27年国勢調査 人口等基本集計(男女・年齢・配偶関係,世帯の構成,住居の状態など) | データベース | 統計データを探す | 政府統計の総合窓口

右端の「表示・ダウンロード」列の「API」を押すと、次のようにリクエストURLの雛形が生成されます。

f:id:ishii-akihiro:20191030150507p:plain

appId=の後に、各自で発行したアプリケーションIDを貼り付けます。また、JSON形式で取得する場合は、http://api.e-stat.go.jp/rest/2.1/appの後に/jsonを付け加えます。

http://api.e-stat.go.jp/rest/2.1/app/json/getStatsData?appId=[発行したアプリケーションID]&lang=J&statsDataId=0003149249&metaGetFlg=Y&cntGetFlg=N&sectionHeaderFlg=1

これをブラウザのURL入力欄に貼り付ければAPIにリクエストを送信できますが、ちょっと待ってください。このままでは全国のデータが1歳階級別で取得しようとするため、相当なデータ量になります

リクエストパラメータの指定

データを絞り込むため、パラメータを設定します。ドキュメントを読んでもよいですが、手っ取り早い方法があったので紹介します。

先ほど選んだ「API」ボタンの横にある「DB」ボタンを押します。「統計表・グラフ表示」のページに移りますが、次のようなメッセージが表示されていると思います。

画面表示セル数 176,400 は最大画面表示セル数 50,000 を超えました。項目の絞り込みや表示位置のページ上部(欄外)への変更を行ってください。

データ量が多くて表示できないということです。統計表表示エリアの「表示項目選択」をクリックします。 f:id:ishii-akihiro:20191030151759p:plain

すると、現在選択されている項目が表示されます。 f:id:ishii-akihiro:20191030152017p:plain

年齢と地域の種類が150以上あるので、データ量を減らすために絞り込みます。「項目を選択」をクリックして設定します。はじめは全選択されているので、「全解除」をしてから必要な項目を選ぶとよいです。

本記事では、年齢は3階級別のみとし、地域は大阪市だけにします。 f:id:ishii-akihiro:20191030152428p:plain f:id:ishii-akihiro:20191030152442p:plain

「確定」を押すと、年齢3回級別の大阪市の人口が表示されます。

f:id:ishii-akihiro:20191030152757p:plain

表の右上にある「API」を選択すると、同様に絞り込むためのパラメータが設定されたリクエストURLが取得できます。先ほどのように、アプリケーションIDを加えて、JSON形式の指定をします。

http://api.e-stat.go.jp/rest/2.1/app/getStatsData?cdArea=27100&cdCat02=1560%2C1760%2C1770&appId=[発行したアプリケーションID]&lang=J&statsDataId=0003149249&metaGetFlg=Y&cntGetFlg=N&sectionHeaderFlg=1

大阪市を示すcdArea=27100と、年齢の3項目を示すcdCat02=1560%2C1760%2C1770が追加されています(%2Cはカンマをエンコーディングしたものなので、年齢を示すコードは 1560,1760,1770 の3種類です)。
このリクエストURLをブラウザのURL欄に貼り付けてリクエストすると、次のような結果が得られます(折りたたんで一部を表示しています)。 f:id:ishii-akihiro:20191030153647p:plain

FuelPHPでコントローラからAPIリクエストを送信する

ようやく本題です。前置きが長くなったので、早速コントローラとビューのサンプルコードを載せます。

コントローラ

わかりやすくするために、パラメータは配列で設定してからhttp_build_queryで組み立てています。得られたレスポンスは配列に変換してビューに渡します。

<?php

class Controller_Home extends Controller
{
  public function action_index()
  {
    //リクエストURL
    $request_url = 'https://api.e-stat.go.jp/rest/3.0/app/json/getStatsData';

    //リクエストパラメータ
    $params = array(
      'cdArea' => '27100',
      'cdCat02' => '1560,1760,1770',
      'appId' => '[アプリケーションID]',
      'lang' => 'J',
      'statsDataId' => '0003149249',
      'metaGetFlg' => 'Y',
      'cntGetFlg' => 'N',
      'sectionHeaderFlg' => '1'
    );
    
    //リクエストURLにパラメータを追記
    $request_url .= '?'.http_build_query($params);
    
    //Request_Curlを生成
    $curl = Request::forge($request_url, 'curl');

    //HTTPメソッドを指定
    $curl->set_method('get');

    //パラメータを設定
    $curl->set_params($params);

    //実行
    $response = $curl->execute()->response();

    //レスポンスコードチェック
    if($response->status == 200)
    {
      //Formatクラスを利用して、JSONからPHPの配列に変換
      $data = Format::forge($response->body,'json')->to_array();
    
      $view = View::forge('index');
      $view->set_global('data', $data);
      return $view;
    }
    
  }
}

ビュー

コードの内容は、レスポンスの['GET_STATS_DATA']['STATISTICAL_DATA']['CLASS_INF']に含まれています。データの内容は、レスポンスの['GET_STATS_DATA']['STATISTICAL_DATA']['DATA_INF']に含まれています。
詳細の説明は本題から外れるので省きますが、一部の項目だけ表示するテーブルを作成しています。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <?php echo Asset::css('style.css'); ?>
</head>
<body>
  <p>---------------------- コード表 ----------------------</p>
  <?php foreach($data['GET_STATS_DATA']['STATISTICAL_DATA']['CLASS_INF']['CLASS_OBJ'] as $key => $class_obj): ?>
    <!-- 取得したデータに複数のコードが含まれていれば表示 -->
    <?php if(!empty($class_obj['CLASS'][0])): ?>
      <?php echo $class_obj['@id'].':'.$class_obj['@name']; ?>
      <table>
        <thead>
          <tr>
            <th>@code</th>
            <th>@name</th>
            <th>@level</th>
            <th>@unit</th>
          </tr>
        </thead>
        <tbody>
          <?php foreach($class_obj['CLASS'] as $key => $value): ?>
            <tr>
              <td><?php if(!empty($value['@code'])){ echo $value['@code']; } ?></td>
              <td><?php if(!empty($value['@name'])){ echo $value['@name']; } ?></td>
              <td><?php if(!empty($value['@level'])){ echo $value['@level']; } ?></td>
              <td><?php if(!empty($value['@unit'])){ echo $value['@unit']; } ?></td>
            </tr>
          <?php endforeach; ?>
        </tbody>
      </table>
    <?php endif; ?>
  <?php endforeach; ?>
  <p>---------------------- データ内容 ----------------------</p>
  <table>
    <thead>
      <th>@cat01</th>
      <th>@cat02</th>
      <th>@cat03</th>
      <th>@cat04</th>
      <th>@unit</th>
      <th></th>
    </thead>
    <tbody>
      <?php foreach($data['GET_STATS_DATA']['STATISTICAL_DATA']['DATA_INF']['VALUE'] as $key => $value): ?>
        <tr>
          <td><?php if(!empty($value['@cat01'])){ echo $value['@cat01']; } ?></td>
          <td><?php if(!empty($value['@cat02'])){ echo $value['@cat02']; } ?></td>
          <td><?php if(!empty($value['@cat03'])){ echo $value['@cat03']; } ?></td>
          <td><?php if(!empty($value['@cat04'])){ echo $value['@cat04']; } ?></td>
          <td><?php if(!empty($value['@unit'])){ echo $value['@unit']; } ?></td>
          <td><?php if(!empty($value['$'])){ echo $value['$']; } ?></td>
        </tr>
      <?php endforeach; ?>
    </tbody>
  </table>
  <?php
    $data['GET_STATS_DATA']['STATISTICAL_DATA']['DATA_INF']['VALUE']
  ?>
</body>
</html>

ブラウザの出力結果

レスポンスの内容を表示できました。 f:id:ishii-akihiro:20191030154654p:plain

感想

今回参照したデータは、全国の市町村に対して1歳階級別に用意されていたため、必要なデータを抽出するのが大変でした。データもコードによって整理されているため、視覚的にわかりやすくするにはコードの内容と結合した方がよいです。

また、本記事のようにビューで整理しようとすると面倒になるので、コントローラで整理してから表示した方がよいと思います。できたら一旦DBに格納した方が、その後の集計は楽になると思います。