2
2

Qiita API と Google Apps Script を使って投稿データのリストを作成する

Last updated at Posted at 2024-07-20

Qiita API と Google Apps Script を使って投稿データのリストを作成する

こんにちは、@studio_meowtoon です。今回は、Qiita API と Google Apps Script を使って投稿データのリストを作成する方法を紹介します。
qiita-api_with_google-apps-script.png

目的

Qiita の投稿データを効率的に管理することを目的とします。

実現すること

Qiita API を使って、自分の投稿データ (タイトル、閲覧数、いいね数、保存数など) を取得します。取得したデータを Google スプレッドシートに保存します。

必要な準備

Qiita API トークンの取得

アクセストークンの発行
image.png

Qiita の 設定ページ で新しいアクセストークンを作成し、トークンをメモしておきます。
image.png

Google スプレッドシートの作成

新しいスプレッドシートを作成し、「list」という名前のシートを追加します。
image.png

手順

Google Apps Script プロジェクトの作成

Google スプレッドシートを開きます。
メニューから [拡張機能] > [Apps Script] を選択します。
image.png

新しいプロジェクトを作成します。
image.png

スクリプトの記述

以下のスクリプトを Code.gs ファイルに貼り付けます。
image.png

コード.gs
// Qiita API のトークンを設定
const QIITA_API_TOKEN = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // 自分のQiita APIトークンに置き換えてください
const QIITA_API_URL = 'https://qiita.com/api/v2/authenticated_user/items';

// Qiita API から投稿データをページネーションを使って取得する関数
function fetch_all_qiita_posts() {
  let page = 1; // 初回ページ
  const per_page = 100; // 1リクエストあたりの最大取得件数
  let all_posts = []; // すべての投稿を格納する配列
  
  while (true) {
    const url = `${QIITA_API_URL}?page=${page}&per_page=${per_page}`; // APIのリクエストURL
    const options = {
      method: 'get',
      headers: {
        'Authorization': 'Bearer ' + QIITA_API_TOKEN, // APIトークンをヘッダーに設定
      }
    };
    
    try {
      // Qiita API からデータを取得
      const response = UrlFetchApp.fetch(url, options);
      const posts = JSON.parse(response.getContentText()); // レスポンスをJSONとしてパース
      
      if (posts.length === 0) {
        break; // 投稿が0件ならループを終了
      }
      
      // プライベートが false の投稿のみフィルタリング
      const public_posts = posts.filter(post => !post.private);
      all_posts = all_posts.concat(public_posts); // 取得した投稿をすべての投稿に追加
      Logger.log(`Fetched page ${page}: ${public_posts.length} public posts`); // ログに取得件数を出力
      page++; // 次のページへ
    } catch (error) {
      // エラーが発生した場合の処理
      Logger.log('Error fetching posts: ' + error); // エラーログを出力
      break; // ループを終了
    }
  }
  
  Logger.log('Total posts fetched: ' + all_posts.length); // 総取得件数をログに出力
  return all_posts; // すべての投稿を返す
}

// 取得したデータをスプレッドシートに書き込む関数
function save_posts_to_sheet() {
  try {
    // スプレッドシートからシートを取得
    const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('list');
    if (!sheet) {
      Logger.log('Sheet "list" not found.'); // シートが見つからない場合の処理
      return;
    }
    Logger.log('Sheet "list" found.'); // シートが見つかった場合の処理
    
    const posts = fetch_all_qiita_posts(); // 投稿データを取得
    
    if (posts.length === 0) {
      Logger.log('No posts to write to the sheet.'); // 投稿がない場合の処理
      return;
    }
    
    // シートをクリア
    Logger.log('Clearing sheet.');
    sheet.clear();
    
    // ヘッダー行を設定
    const headers = [
        'id', // 投稿ID
        'title', // 投稿タイトル
        'tags', // タグ
        'created_at', // 作成日時
        'updated_at', // 更新日時
        'views', // 閲覧数
        'likes', // いいね数
        'stocks', // 保存数
        'url' // 投稿URL
    ];
    sheet.appendRow(headers); // ヘッダーをシートに追加
    Logger.log('Headers written to the sheet.'); // ヘッダー書き込み完了のログ
    
    // 投稿データを配列に変換
    const rows = posts.map(post => {
      const id = post.id; // 投稿ID
      const title = post.title; // 投稿タイトル
      const tags = post.tags.map(tag => tag.name).join(', '); // タグをカンマ区切りで連結
      const created_at = Utilities.formatDate(new Date(post.created_at), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm'); // 作成日時をフォーマット
      const updated_at = Utilities.formatDate(new Date(post.updated_at), 'Asia/Tokyo', 'yyyy-MM-dd HH:mm'); // 更新日時をフォーマット
      const views = post.page_views_count || '0'; // 閲覧数(存在しない場合は0)
      const likes = post.likes_count || '0'; // いいね数(存在しない場合は0)
      const stocks = post.stocks_count || '0'; // 保存数(存在しない場合は0)
      const url = post.url; // 投稿URL
      return [id, title, tags, created_at, updated_at, views, likes, stocks, url]; // 配列として返す
    });
    
    // データ行を一括でシートに追加
    sheet.getRange(2, 1, rows.length, rows[0].length).setValues(rows);
    Logger.log('All posts written to the sheet.'); // すべての投稿が書き込まれたログ
  } catch (error) {
    // エラーが発生した場合の処理
    Logger.log('Error in save_posts_to_sheet: ' + error); // エラーログを出力
  }
}

スクリプトの実行

スクリプトエディタのツールバーから関数を選択し、 [save_posts_to_sheet] を選択します。実行ボタンをクリックしてスクリプトを実行します。
image.png

初回実行時には、スクリプトが必要な権限を要求するので、指示に従って許可します。

結果の確認

スクリプトが正常に実行されると、スプレッドシートの [list] シートに Qiita の投稿データが書き込まれます。
image.png

まとめ

Google Apps Script を使用して Qiita API から投稿データを取得し、Google スプレッドシートに保存する方法がわかりました。

おまけ:Google Apps Script を VSCode で編集する

VSCode のインストール

npm のインストール

Google Apps Script API をオンにする

Apps Script 設定

image.png

clasp のインストール

WSL の Ubunts に npm で clasp をインストールします。

$ sudo npm install -g @google/clasp
$ clasp -version
2.4.2

Google アカウントでログイン

Google アカウントで clasp にログインします。

$ clasp login

GAS プロジェクトのクローン

既存のプロジェクトを編集する場合、[プロジェクトのスクリプトID] を使用してクローンします。
image.png

ファイルの名前を [Program.gs] に変更しています。
image.png

$ mkdir ~/qiita-posts
$ cd ~/qiita-posts
$ clasp clone {スクリプトID}
Warning: files in subfolder are not accounted for unless you set a '/home/$USER/qiita-posts/.claspignore' file.
Cloned 2 files.
└─ /home/$USER/qiita-posts/appsscript.json
└─ /home/$USER/qiita-posts/Program.js
Not ignored files:
└─ /home/$USER/qiita-posts/appsscript.json
└─ /home/$USER/qiita-posts/Program.js

Ignored files:
└─ /home/$USER/qiita-posts/.clasp.json

VSCode で編集

スクリプトファイルを VSCode で開いて編集します。

$ ls -la
合計 24
drwxr-xr-x  2 $USER $USER 4096  7月 20 22:49 .
drwxr-x--- 13 $USER $USER 4096  7月 20 22:51 ..
-rw-------  1 $USER $USER  113  7月 20 22:49 .clasp.json
-rw-r--r--  1 $USER $USER 4593  7月 20 22:55 Program.js
-rw-r--r--  1 $USER $USER  118  7月 20 22:49 appsscript.json
$ code .

image.png

変更のプッシュ

以下のコマンドでリモートにプッシュします。

$ clasp push

Git 管理されている状況ではありません!

まとめ2

VSCode から Google Apps Script のコードを編集してリモートにプッシュすることが出来ました。 これにより、VSCode の豊富な機能を使用して GAS の開発が可能となります。また、別途 Git で編集の履歴を管理することもできます。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2