小説家になろうAPIを叩いてランキングを取得

#目次
1. 概要
2. APIを確認
3. コード①（取得・保存）
4. コード①について
5. コード②（出力）
6. 実行結果
7. 終わり



#1. 概要
- 小説家になろう（以下なろう）のAPIからランキング情報を取得する
- その後ローカルに保存して、ファイルから読み込む
- PHPで「Hello,World!」を表示できる方向け
- [なろうランダム](https://narou.club)というサイトを作る際に最初に取り組みました
- 環境
    - macOS Catalina ver.10.15.4
    - PHP 7.3.11 (cli)



#2. APIを確認
「[なろうデベロッパー](https://dev.syosetu.com/man/api/)」で詳細に解説されているので、必読です。

例えば以下の条件で取得したい場合
・週間ランキング上位　▶︎　order=dailypoint
・5件  ▶︎  lim=5
・「タイトル／著者名／週間ポイント」のみ　▶︎　of=t-w-wp

アクセスするURLは「[https://api.syosetu.com/novelapi/api/?order=dailypoint&lim=5&of=t-w-wp](https://api.syosetu.com/novelapi/api/?order=dailypoint&lim=5&of=t-w-wp)」となります。リンクから確認してみて下さい。

- PHPから取得するときは「out=php」を指定します
- 項目は出力時に限定すればいいので、取得時には「of=」指定せず、全項目を保存します（[こんな感じです※PC](https://api.syosetu.com/novelapi/api/?order=dailypoint&lim=1)）
- 大量取得する場合はAPI制限に抵触しないよう、of指定やgzip指定による通信量軽減をご検討下さい



#3. コード①（取得・保存）
```php:index.php
<?php
define("EOL", "\n\r<br>");//改行を簡略化(End Of Line)
  $filePath = "./novels.dat";     //入力①
  $order = "dailypoint";          //入力②
  $limit = 5;                     //入力③
  $myUserAgent = "Your UserAgent";//入力④
  // ファイルが無い場合のみAPIを読み込む
  if( !file_exists($filePath) ){
      echo "APIにアクセスして情報をファイルに保存します。相対パス：「{$filePath}」".EOL.EOL;
      $url = "https://api.syosetu.com/novelapi/api/?out=php&order={$order}&lim={$limit}";
      $option = array(
        'http' => array(
            'method'=> "GET",
            'header'=> "User-Agent:".$myUserAgent
         ) );
      $context = stream_context_create($option);
      $novels = unserialize(file_get_contents($url, false, $context));//APIから取得
      sleep(3);//API負荷防止、3秒スリープ
      file_put_contents($filePath, serialize($novels));//ローカルに保存
  // ファイルがあればローカルから読み込む
  } else {
      echo "APIにアクセスせずファイルから読み込みます。相対パス：「{$filePath}」".EOL.EOL;
      $novels = unserialize(file_get_contents($filePath));
  }
```


#4. コード①について
- 入力①：保存ファイル名を`$filePath`で指定
- 入力②：並び順を`$order`に代入（"dailypoint"など）
- 入力③：取得件数を`$limit`に代入（1~500件）
- 入力④：【注意】ユーザーエージェントを明記していないと不正アクセスとみなされて「403 Forbidden」（閲覧禁止）が返される。
変数`$myUserAgent`に自分のユーザーエージェントを忘れず代入する。[この確認ページ](https://www.cloudgate.jp/ua.php)で表示したものを丸ごとコピペでOK

###その他
- 全体をif文で囲み、`$filePath`のファイルが存在しない場合のみAPIにアクセスして取得・保存
- 「out=php」で取得したデータの利用には「unserialize」が必要で、保存の際に再度「serialize」
- 小説情報の取得：`file_get_contents()` ／ 保存：`file_put_contents()`


  以上で取得した情報が`$novels`に入ります。
  `$novels`から出力するのが以下のコードです。



#5. コード②（出力）
```php:index.php（続き）
  unset($novels[0]);//配列0番目の「allcount」を消す。消さない場合はコメントアウト
  //foreachでの出力（一部項目）
  echo "【ポイント・作者・タイトルのみ表示】".EOL;
  foreach($novels as $key => $novel){
    $dailyPoint = $novel['daily_point'];
    $title = $novel['title'];
    $writer = $novel['writer'];
    echo "{$key}／{$dailyPoint}ポイント／{$writer}／{$title}".EOL;
  }
  echo EOL;
  //forでの出力（全項目）
  echo "【全項目の表示】".EOL;
  for($i=1; $i <= count($novels); $i++){
    print_r($novels[$i]);
    echo EOL;
  }
?>
```


- `$novels`は配列なので、「echo」や「var_dump()」では出力不可
- 配列全体の確認は「print_r()」や「var_export()」
- 任意の情報表示はfor文かforeach文を使用



#6. 実行結果
```html:実行結果（初回）
APIにアクセスして情報をファイルに保存します。相対パス：「./novels.dat」

【ポイント・作者・タイトルのみ表示】
1／8972ポイント／まきぶろ／悪役令嬢の中の人
2／7378ポイント／徳川レモン／勇者に恋人を寝取られ追放されたが、『経験値貯蓄』スキルが壊れてレベル300になったのでのんびり傷心旅行でもしようかと思ってます
3／5580ポイント／桜井ゆきな／義妹が聖女だからと婚約破棄されましたが、私は妖精の愛し子です
4／4014ポイント／万野みずき／【さびついた剣】を試しに強化してみたら、とんでもない魔剣に化けました
5／3856ポイント／桐島ヒスイ／２周目侯爵令嬢は婚約者の溺愛に気付かない

【全項目の表示】
Array ( [title] => 悪役令嬢の中の人 [ncode] => N2326GF [userid] => 851881 [writer] => まきぶろ [story] => 　乙女ゲームの好きな平凡な少女、小林恵美は交通事故に巻き込まれ、目を覚ますと乙女ゲームアプリ「星の乙女と救世の騎士」の悪役令嬢レミリアになっていた。世界の滅亡と自身の破滅を回避するために恵美は奔走する！ 　……その努力も虚しく、同じく転生者であるヒロインの「星の乙女」に陥れられた恵美は婚約破棄された上で星の乙女の命を狙ったと断罪された。そのショックで意識を失った恵美の代わりに、中から見守っていた「レミリア」が目を覚まし、可愛い「エミ」を傷付けた星の乙女と元婚約者の王子達に復讐を行う。 　主人公は「レミリア」です。 [biggenre] => 1 [genre] => 101 [gensaku] => [keyword] => R15 乙女ゲーム 悪役令嬢 ヤンデレ ざまぁ 主人公にとっては ハッピーエンド [general_firstup] => 2020-05-06 03:35:15 [general_lastup] => 2020-05-06 10:24:37 [novel_type] => 2 [end] => 0 [general_all_no] => 1 [length] => 55709 [time] => 112 [isstop] => 0 [isr15] => 1 [isbl] => 0 [isgl] => 0 [iszankoku] => 0 [istensei] => 0 [istenni] => 0 [pc_or_k] => 2 [global_point] => 12718 [daily_point] => 8972 [weekly_point] => 2174 [monthly_point] => 2174 [quarter_point] => 2174 [yearly_point] => 0 [fav_novel_cnt] => 1124 [impression_cnt] => 31 [review_cnt] => 1 [all_point] => 10470 [all_hyoka_cnt] => 1104 [sasie_cnt] => 0 [kaiwaritu] => 39 [novelupdated_at] => 2020-05-07 21:26:15 [updated_at] => 2020-05-07 21:56:42 )
〜2件目以降省略
```

二度目の実行から、冒頭の文が
「APIにアクセスせずローカルファイルから読み込みます。」に変わっていれば
ローカルファイルからの読み込みに成功しています。
更新したい場合は、if文をコメントアウトすればAPI取得が実行されて上書き保存されます。



#7. 終わり
初Qiita投稿でした。お粗末様です！

- 参照リンク:
    - [日間ランキング｜小説を読もう！](http://yomou.syosetu.com/rank/list/type/daily_total/)
    - [なろう小説API｜なろうデベロッパー](https://dev.syosetu.com/man/api/)
    - [ユーザーエージェント確認サイト](https://www.cloudgate.jp/ua.php)
    - [PHP: file_get_contents｜Manual](https://www.php.net/manual/ja/function.file-get-contents.php)
    - [PHP: file_put_contents｜Manual](https://www.php.net/manual/ja/function.file-put-contents.php)