QiitaのView数を取得する


初めに

QiitaのLGTM数とView数を取得するにあたって、
APIの仕様が変わったのか参考にさせていただいたもので取得できなかった箇所があったので、
取得方法を記載していきます。

環境

Go 1.15.2

1. アクセストークンを取得

ユーザ管理画面からトークンを取得

スコープはread_qiitaとwrite_qiitaを選択

2. 取得したい情報のURLを確認

公式ドキュメントより取得したい情報のURLを確認。今回利用するのは以下の2種類です。

GET /api/v2/authenticated_user/items
認証中のユーザの記事の一覧を作成日時の降順で返します。
GET /api/v2/items/:item_id
記事を取得します。

3. jsonを変換するstructを作成

公式ドキュメントよりAPIを叩いたときに返却される情報がJsonで返却されるため、
返却されたデータを扱うstructを作成。

UserInfo.go
package data

type UserInfo struct {
    Id               string `json:"id"`
    Likes_count      int    `json:"likes_count"`
    Title            string `json:"title"`
    Page_views_count int    `json:"page_views_count"`
}

4. Qiita APIを叩く

web.go
package qiita

import (
    "../data"
    "../exporter"
    "encoding/json"
    "io/ioutil"
    "net/http"
)

func GetQiitaViews() {                                      // main.goから呼び出す
    url := "https://qiita.com/api/v2/authenticated_user/items?page=1&per_page=20"
    resp, err := doHttpRequest(url)
    defer resp.Body.Close()                                 // Bodyをクローズ

    body, err := ioutil.ReadAll(resp.Body)                  // レスポンスのBodyから取得

    var userInfos []data.UserInfo
    if err = json.Unmarshal(body, &userInfos); err != nil { // jsonの読み出し
        return
    }

    index := 0
    for _, user := range userInfos {                       // 1記事ずつ読み出す
        url = "https://qiita.com/api/v2/items/" + user.Id  // 記事のIDを利用、view数を取得
        resp, err := doHttpRequest(url)
        defer resp.Body.Close()

        body, err := ioutil.ReadAll(resp.Body)

        if err := json.Unmarshal(body, &user); err != nil {return}
        userInfos[index].Page_views_count = user.Page_views_count
        index += 1
    }
    exporter.ToCsv(userInfos)                                // csv化
}

func doHttpRequest(url string) (*http.Response, error) {     // リクエストを共通化
    req, _ := http.NewRequest("GET", url, nil)

    buf, _ := ioutil.ReadFile("token.txt")
    token := string(buf)                                     // tokenを別ファイルで管理

    req.Header.Set("content-type", "application/json")       // ヘッダーにapplication/jsonを指定
    req.Header.Set("Authorization", "Bearer " + token)       // ヘッダーにtokenを指定

    client := new(http.Client)
    resp, err := client.Do(req)
    return resp, err
}

以下のAPIだけだと取得できないようで、
URLにクエリをつける必要があることに最初気づかず、取得することができていませんでした。
また、page_view_countがnull(Goでstructに入れた場合0)が返ってきてしまうため、
view数は記事ごとに取得する必要があるようです。
【Qiita API】いいね!閲覧数の自動集計の記事を参考にさせていただきました。

GET /api/v2/authenticated_user/items
認証中のユーザの記事の一覧を作成日時の降順で返します。

そこで、以下のAPIを利用しています。

GET /api/v2/items/:item_id
記事を取得します。

5. CSV出力

export.go
package exporter

import (
    "../data"
    "encoding/csv"
    "os"
    "strconv"
)

func ToCsv(userInfos []data.UserInfo) {
    file, _ := os.OpenFile("result.csv", os.O_WRONLY|os.O_CREATE, 0600)  //ファイルを開く
    defer file.Close()

    writer := csv.NewWriter(file)
    writer.Write([]string{"title", "like_count", "page_views_count"})   // ヘッダーをつける
    for _, user := range userInfos {
        likesCount := strconv.Itoa(user.Likes_count)                    // intをstringへ変換
        pageViewsCount := strconv.Itoa(user.Page_views_count)
        writer.Write([]string{user.Title, likesCount, pageViewsCount})  // 書き込み
    }
    writer.Flush()
}

最後に

ソースはここにあります。
GitHubにソースをアップする関係上、
token情報はmain.goと同一ディレクトリ内の別ファイルにて管理しています。
エラーハンドリングは一部省略している箇所があります。

参考文献

公式
【Qiita API】いいね!閲覧数の自動集計
Go言語でCSVを書き出す!エクセル用のSJIS版も!
Go の import cycle not allowed (循環参照) の対応