RでCOTOHAを使ってみる（『グスコーブドリの伝記』からキーワード抽出）

[COTOHA API](https://api.ce-cotoha.com/contents/index.html)がすごく面白そうだったので、Rでやってみたメモ
httrでリクエストを送ればRでもできる！

# 対象の文章
宮沢賢治の[『グスコーブドリの伝記』](https://www.aozora.gr.jp/cards/000081/card1924.html)（9章構成）
> **あらすじ**
　**グスコーブドリ（ブドリ）**はイーハトーブの森に暮らす樵（きこり）の息子として生まれた。冷害による飢饉で両親を失い、**妹（ネリ）**と生き別れ（1章　森）、工場に労働者として拾われるも火山噴火の影響で工場が閉鎖するなどといった苦難を経験するが（2章　てぐす工場）、農業に携わったのち（3章　沼ばたけ）、**クーボー大博士**に出会い学問の道に入る（4章　クーボー大博士）。課程の修了後、彼は**ペンネン老技師**のもとでイーハトーブ火山局の技師となり（5章　イーハトーヴ火山局）、噴火被害の軽減に携わり（6章　サンムトリ火山）、人工降雨を利用した施肥などを実現させる（7章　雲の海）。前後して、無事成長し牧場に嫁いでいた妹との再会も果たすのであった（8章　秋）。
　ところが、ブドリが27歳のとき、イーハトーブはまたしても深刻な冷害に見舞われる。カルボナード火山を人工的に爆発させることで大量の炭酸ガスを放出させ、その温室効果によってイーハトーブを暖められないか、ブドリは飢饉を回避する方法を提案する。しかし、クーボー博士の見積もりでは、その実行に際して誰か一人は噴火から逃げることができなかった。犠牲を覚悟したブドリは、彼の才能を高く評価するが故に止めようとするクーボー博士やペンネン老技師を冷静に説得し、最後の一人として火山に残った。ブドリが火山を爆発させると、冷害は食い止められ、イーハトーブは救われたのだった（9章　カルボナード島）。
    [グスコーブドリの伝記 - Wikipedia](https://www.google.com/search?client=ubuntu&channel=fs&q=%E3%80%8E%E3%82%B0%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%96%E3%83%89%E3%83%AA%E3%81%AE%E4%BC%9D%E8%A8%98%E3%80%8F&ie=utf-8&oe=utf-8)を一部改変

昔読んだことがあり、章ごとに別れていて扱いやすかったためこの作品を選んだ。

青空文庫からテキストをダウンロードして解凍し、`gusukobudorino_denki.txt`を作業ディレクトリに配置しておく。

# 準備
[COTOHA for Developers](https://api.ce-cotoha.com/contents/developers/index.html)にユーザー登録する。

# コード
## パッケージの呼び出し
使用するパッケージを呼び出す。インストールされていない場合はインストールする。

```r
library(httr) # APIへの接続用
library(jsonlite) # jsonの処理用
library(magrittr) # パイプとエイリアス用
library(tidyverse) # データ成形用
```

## データのロード
テキストファイルを読み込んで章ごとのテキストをまとめる。
この文章用に作ってあるので、他の青空文庫のテキストでやる場合は適宜自分で書く必要がある。

```r
doc <- scan("gusukobudorino_denki.txt", what = character(), fileEncoding = "cp932") %>% magrittr::extract( - c(1:11, 290:300)) # 読み込みとメタ情報の削除

doc.list <- doc %>% 
    str_replace_all(pattern = "［＃５字下げ.+は中見出し］", replacement = "####") %>% # 見出しを別の文字列に置換
    paste0(collapse = "") %>% str_split(pattern = "####") %>% unlist %>% # 全文を1つの文字列に連結した後、見出しを区切りに分割し、ベクトル化
    str_replace_all(pattern = "［.+］", replacement = "") %>% magrittr::extract(-1) # 注釈を削除し、空になっている1つめの要素を除外
```
これで各章のテキストが`doc.list`に格納される。

## アクセストークンの取得
COTOHAのアカウントホームで各種情報を確認し、以下の`config.json`の該当部分を書き換えて作業ディレクトリに保存する。

```config.json
{
  "grantType": "client_credentials",
  "clientId": "[client id]",
  "clientSecret": "[client secret]"
}
```
次にアクセストークンを取得する。詳しくは[COTOHA API　アクセストークン取得](https://api.ce-cotoha.com/contents/reference/accesstoken.html)を参照。

```r
url.token <- "[Access Token Publish URL]"
config <- read_json("config.json") # リクエストボディのロード
token <- POST(url.token, body = config, encode = "json", content_type = "application/json", verbose()) # リクエストをPOST
access.token <- content(token) %>% magrittr::extract2("access_token") # レスポンスからアクセストークンを取得
```

## 章ごとにキーワード解析
COTOHAで章ごとにキーワード解析を行う。詳しくは[COTOHA API　キーワード抽出](https://api.ce-cotoha.com/contents/reference/apireference.html)を参照。
遅延時間はもう少し長いほうがいいかも？

```r
url.keyword <- "[API Base URL]/nlp/v1/keyword"

result.tmp <- map(doc.list, ~ {
    body.key <- list(document = ., type = "default", max_keyword_num = 2) # リクエストボディを作成
    result.key <- POST(url.keyword, body = body.key, encode = "json", content_type = "application/json;charset=UTF-8", add_headers(Authorization = paste("Bearer", access.token)), verbose()) # リクエストをポスト
    Sys.sleep(60) # サーバーに負荷をかけないように、1分程度遅延させる
    return(result.key)
})
```
`500 internal Server Error`でうまくいかない章もあるが、概ねきちんと返ってくる。
エラーになるかどうかはタイミングによって変わるので、おそらくはサーバーの処理の問題。長い文を連続で送るのは良くないのかもしれない。

## 結果の整形
`result.tmp`はリストの各要素にjsonが入っている状態なので、整形して見やすくする。

```r
result <- result.tmp %>% 
    map(~ {content(.) %>% magrittr::extract2("result") %>% bind_rows})
# 各章の抽出結果をtibbleにまとめる
```

# 結果
`result`の中は次のようになっている。エラーした章は中身がない。
おおよそ各章の主要な人物や物事を拾えていると思う。
7章は「イーハトーヴ」や「雲」のほうが適切な気がするが、**なぜか「受話器」が選ばれた。**

```
[[1]]
# A tibble: 2 x 2
  form       score
  <chr>      <dbl>
1 二人        210 
2 おかあさん  172.

[[2]]
# A tibble: 2 x 2
  form   score
  <chr>  <dbl>
1 ブドリ  200 
2 男      110.

[[3]]
# A tibble: 0 x 0

[[4]]
# A tibble: 2 x 2
  form   score
  <chr>  <dbl>
1 ブドリ  250 
2 大博士  137.

[[5]]
# A tibble: 2 x 2
  form   score
  <chr>  <dbl>
1 ブドリ 180  
2 火山    55.0

[[6]]
# A tibble: 0 x 0

[[7]]
# A tibble: 2 x 2
  form   score
  <chr>  <dbl>
1 ブドリ 120  
2 受話器  65.5

[[8]]
# A tibble: 2 x 2
  form   score
  <chr>  <dbl>
1 ブドリ  190 
2 ネリ    108.

[[9]]
# A tibble: 2 x 2
  form   score
  <chr>  <dbl>
1 ブドリ 150  
2 爆発    54.7
```

# 参考にしたサイト
[自然言語処理を簡単に扱えると噂のCOTOHA APIをPythonで使ってみた](https://qiita.com/gossy5454/items/83072418fb0c5f3e269f)
[［R］テキストファイル（改行有り）の中身を簡単に読み込んでベクトルにする](http://goldenstate.cocolog-nifty.com/blog/2017/10/r-b926.html)
[stringrを使って文字列処理をやってみる](https://kazutan.github.io/kazutanR/stringr-intro.html#%E5%8A%A0%E5%B7%A5)
[基本的な正規表現一覧](https://murashun.jp/blog/20190215-01.html#chapter-1)
[[翻訳] httr vignette: httrはやわかり](https://qiita.com/nakamichi/items/14f9952445089927c38e#%E3%83%9C%E3%83%87%E3%82%A3)
[httrを使ってRからREST APIを叩く](https://qiita.com/komde/items/22c8a4f809e46cdd70f8)
[httr POST authentication error](https://stackoverflow.com/questions/41809707/httr-post-authentication-error)