見出し画像

共同運営マガジンを調べるコードを生成AIに書かせてみた…の続き

じぃじの有料記事ですが、全文無料で読めます。
前回は次の記事で「プログラムが読むページ」を紹介しましたが…

このページをプログラムから頻繁にアクセスするとエラーが発生しますが、これはウェブサイトの過負荷を防止するために設けられている制限だと思います。で、NOTEのサイトに迷惑をかけないようにしながら「プログラムが読むページ」を閲覧する方法を考えていたら、ちょっと時間が経ってしましました😛 本稿ではこの制限に引っかからないようにして、共同運営マガジンの情報を集め、ランキングを作成する方法を紹介します。


迷惑をかけずに共同運営マガジンの情報をゲット

調べてみたら Chrome などのウェブブラウザでアクセスすると、この制限には引っかからないことがわかりました。前回も紹介した次のようなページですね。

クロサキナオさんのマガジンの「プログラムが読むページ」

複数の共同運営マガジンのページを順次閲覧して、ローカルファイルに保存しておいて、そのあとローカルファイルから必要な情報を抜き出すプログラムを実行すれば、制限を回避してランキングが作れそうです。
そこで次のような CSV ファイルを作って観ました。

https://note.com/api/v1/layout/magazine/m45e61de5e47c
https://note.com/api/v1/layout/magazine/ma1ce060406a2
https://note.com/api/v1/layout/magazine/mf2e12dc63c25
https://note.com/api/v1/layout/magazine/md449a82accb0
https://note.com/api/v1/layout/magazine/mc4827a8e939b
https://note.com/api/v1/layout/magazine/m4213124a68e8
https://note.com/api/v1/layout/magazine/mfb3685bde725
https://note.com/api/v1/layout/magazine/m71e28640b3b5
https://note.com/api/v1/layout/magazine/md6154ba9fd31
https://note.com/api/v1/layout/magazine/m2453b25de706

これは以前、紹介した共同運営マガジンのランキングの…

…上位10位までのページのURLをリストアップしたものです。この内容をコピーして url.csv というファイルを作って観てください。MS Office がインストールされているPCであれば、このファイルをダブルクリックすると Excel が起動して、次のウィンドウが開きます。

Excelで開いたurl.csv

この状態でA1のセルを選択して、10回リターンを叩くと…

全部青色(リンク)に変える

URLは全部青色(リンク)に変わりましたよね?
ここでウェブブラウザーを起動して新しいウィンドウを開きます。

ブラウザーの新しいウィンドウ

その後、先ほどの Excel のウィンドウに戻ってリンクを順番にクリックしていくと、ブラウザーのウィンドウのタブが順番に開いて…

10個のタブが開いたウィンドウ

10個のタブが開きました。これで10個の共同運営マガジンのページのダウンロードが完了しました。あとは、ローカルファイル(JSONファイル)に保存するだけです。タブ毎に Chrome の「ファイル」メニューを開くと「ページを別名で保存…」を選択すると…

「ファイル」「ページを別名で保存…」

ダイアログの「OK」だけ押せば(おそらくデスクトップに)10本のJSONファイルが作成されます。

生成AIにデータ集めのプログラムを書かせてみる

さて、次はダウンロードした10本のJSONファイルを全部チェックして必要な情報だけをピックアップしたいのですが…前回と同様、これは生成AIにプログラムを書かせます。まず「JSON」という新しいフォルダーを作って、その中に先ほどの10本のJSONファイルを移します。こうしておくと、生成AIに「JSONというフォルダーに入ってる全てのファイルを…」というように指示することができるので便利です。

…ということで、今回僕が書いたプロンプト(おまじない)はこちら。

次の条件でプログラムを書いて
* nodejs で実行できる javascript のプログラム
* 「JSON」フォルダーにある複数のJSONファイルを順次読み込む
* 次のプロパティをCSV形式でファイルに出力する
  + 第1カラムは'https://note.com/api/v1/layout/magazine/'をプリフィクスにしてdata.magazine_layout.keyを出力
  + 第2カラムはdata.magazine_layout.nameを出力
  + 第3カラムはdata.magazine_layout.created_at をyyyy/mm/dd 形式に変換して出力
  + 第4カラムはdata.magazine_layout.updated_at をyyyy/mm/dd 形式に変換して出力
  + 第5カラムはdata.magazine_layout.note_countを出力
  + 第5カラムはdata.magazine_layout.editors_countを出力
* 出力内容は全体をSJISに変換する
* 出力ファイルの名前は yyyymmddhhmmss.cvs 形式で現在時間から生成する

ウェブ系のプログラミングをご存知の方はピンとかもしれませんが、魔法の呪文だと考えてもらって差し支えありません。前回同様、このプロンプトをコピーして生成AIに貼り付けるとプログラムを書いてくれます。が、今回のプロンプトを貼り付けると OpenAI の ChatGPT とマイクロソフトの Copilot では正しく動くプログラムを書いてくれますが、Google の Gemini が生成したプログラムはエラーが発生して正しく動作しませんでした。(なので割愛します)

OpenAI の ChatGPT の場合はこんな感じ。

const fs = require('fs');
const path = require('path');
const { parse } = require('json2csv');
const iconv = require('iconv-lite');

// JSON フォルダーのパスを設定
const jsonFolderPath = path.join(__dirname, 'JSON');

// 出力 CSV ファイル名を生成
const now = new Date();
const formattedDate = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}`;
const outputFileName = `C${formattedDate}.csv`;

// JSON フォルダーからファイルを読み込み、CSV 形式に変換して保存する関数
async function processFiles() {
    const files = fs.readdirSync(jsonFolderPath).filter(file => file.endsWith('.json'));

    const data = [];
    
    for (const file of files) {
        const filePath = path.join(jsonFolderPath, file);
        const fileContent = fs.readFileSync(filePath, 'utf8');
        const jsonData = JSON.parse(fileContent);
        
        if (jsonData.data && jsonData.data.magazine_layout) {
            const { key, name, created_at, updated_at, note_count, editors_count } = jsonData.data.magazine_layout;
            
            data.push({
                key: `https://note.com/api/v1/layout/magazine/${key}`,
                name,
                created_at: formatDate(created_at),
                updated_at: formatDate(updated_at),
                note_count,
                editors_count
            });
        }
    }

    const csv = parse(data);
    const sjisCsv = iconv.encode(csv, 'sjis');

    fs.writeFileSync(outputFileName, sjisCsv);
    console.log(`CSV file has been saved as ${outputFileName}`);
}

// 日付を 'yyyy/mm/dd' 形式に変換する関数
function formatDate(dateString) {
    const date = new Date(dateString);
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}/${month}/${day}`;
}

// プログラムを実行
processFiles().catch(console.error);

マイクロソフトの Copilot の場合はこんな感じ。

const fs = require('fs');
const path = require('path');
const iconv = require('iconv-lite');

// JSONフォルダーのパス
const jsonFolder = './JSON';

// 出力ファイル名の生成
const now = new Date();
const outputFileName = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}.csv`;

// CSVヘッダー
const csvHeader = 'URL,Name,Created At,Updated At,Note Count,Editors Count\n';

// CSVデータを格納する配列
let csvData = [csvHeader];

// JSONファイルの読み込みとCSVデータの生成
fs.readdir(jsonFolder, (err, files) => {
  if (err) {
    console.error('Error reading JSON folder:', err);
    return;
  }

  files.forEach(file => {
    const filePath = path.join(jsonFolder, file);
    const jsonData = JSON.parse(fs.readFileSync(filePath, 'utf8'));

    const url = `https://note.com/api/v1/layout/magazine/${jsonData.data.magazine_layout.key}`;
    const name = jsonData.data.magazine_layout.name;
    const createdAt = new Date(jsonData.data.magazine_layout.created_at).toISOString().split('T')[0].replace(/-/g, '/');
    const updatedAt = new Date(jsonData.data.magazine_layout.updated_at).toISOString().split('T')[0].replace(/-/g, '/');
    const noteCount = jsonData.data.magazine_layout.note_count;
    const editorsCount = jsonData.data.magazine_layout.editors_count;

    const csvRow = `${url},${name},${createdAt},${updatedAt},${noteCount},${editorsCount}\n`;
    csvData.push(csvRow);
  });

  // CSVデータをSJISに変換してファイルに書き込む
  const sjisData = iconv.encode(csvData.join(''), 'Shift_JIS');
  fs.writeFileSync(outputFileName, sjisData);
  console.log(`CSV file has been saved as ${outputFileName}`);
});

各々、コードだけでなく使い方も解説してくれるので、気になる方は読んでみてください。勉強になります😛

コードを実行してみる

コードが生成されたら、コピーしてファイルに収めてください。
いずれのコードも nodejs で実行することができます。実行すると "20240916115846.csv" というように日付(2024/09/16)と時間(11:58.46)を組み合わせた名前のファイルが出力されます。(ファイルはシフトJISですが、ここではファイル内容を見せるために UTF-8 に変換しています)

key,name,created_at,updated_at,note_count,editors_count
https://note.com/api/v1/layout/magazine/m2453b25de706,あっとほーむ?,2024/5/13,2024/9/15,10738,200
https://note.com/api/v1/layout/magazine/m4213124a68e8,共育LIBRARY×共同運営マガジン,2023/11/30,2024/9/15,30075,308
https://note.com/api/v1/layout/magazine/m45e61de5e47c,トランスミッション,2021/8/15,2024/9/15,137375,957
https://note.com/api/v1/layout/magazine/m71e28640b3b5,トランスミッションⅡ,2023/12/20,2024/9/15,21857,218
https://note.com/api/v1/layout/magazine/ma1ce060406a2,【みんなで創る】クロサキナオの運営マガジン,2023/10/9,2024/9/15,66833,874
https://note.com/api/v1/layout/magazine/mc4827a8e939b,noteのクリエイターさんたちみんなでマガジン,2023/11/4,2024/9/15,34170,350
https://note.com/api/v1/layout/magazine/md449a82accb0,note大学共同運営マガジン,2021/10/3,2024/9/15,48488,372
https://note.com/api/v1/layout/magazine/md6154ba9fd31,【繋がろう】シロクロの共同運営マガジン,2024/2/29,2024/9/15,19292,217
https://note.com/api/v1/layout/magazine/mf2e12dc63c25,【共同運営マガジン】頑張る隊,2023/10/5,2024/9/15,29198,439
https://note.com/api/v1/layout/magazine/mfb3685bde725,レオンファミリー,2024/5/16,2024/9/15,12058,216

これは CSV フォーマットのファイルで、Excel などの表計算ソフトに取り込むことができます。

出力されたファイルの使い方

出力されたファイルをダブルクリックすると Excel が起動されます。

CSVファイル

このままでは通常の Excel の操作が記録されないのでブック形式のファイルに変換します。「ファイル」「名前をつけて保存…」をクリックすると…

「ファイル」「名前をつけて保存…」

書き込みのダイアログが表示されるので、ファイル形式を「Excel ブック」を選択して、保存を押すと…

Excel ブック」を選択して、保存

これで同名の "20240916115846.xlsx" が保存されます。

あとは通常の Excel の操作ができますが…
じぃじは YouTuber ランキングの集計法に倣って手直ししてます。

共同運営マガジンのランキング

まず「更新日」から「作成日」を引いて「運営日数」の列を作ります。
次に「投稿記事数」を「運営日数」で割って、1日あたりの「平均投稿数」の列を追加します。そして「投稿記事数」を「投稿者数」で割って「一人当たり」の記事投稿数の列も追加します。最後に「平均投稿数」をキーに降順で並び替えました。

ここで計算した「平均投稿数」と「一人当たり」の二つの指標により、どの共同運営マガジンに参加するのがお得か?ざっくりと把握することができます。「平均投稿数」が大きいほど周知効果が高いと考えられます。また「一人当たり」が少なければ、参加のランニングコストが小さい(投稿数は比較的少なくて済む)と考えられます。この10つの共同運営マガジンでの比較であれば、やはりクロサキナオさんの運営マガジンがお得?ってことになるのでしょうかねぇ?

もちろんExcel データに変換しておけば、NOTEにもペーストできます。

2024/9/15現在の共同運営マガジンのランキング

ちなみに…第1カラムの key を残しているのは、次回のランキング作成の手数を減らすためです。一般にこの種のランキングは定期的にデータ収集するのが定石なので毎週、隔週、毎月といった任意の頻度でランキング作成を続けてデータを残しておくと時系列解析にも活用できます。

まとめ

ということで、前回と今回で共同運営マガジンに関するランキングの作成を題材に、ルーチンワークに役立つプログラムを生成AIに作成させる事例を紹介してみました。

データ集計は誰がやっても同じような手順で作業するので生成AIにプログラム生成を任せても成功し易いカテゴリーです。今回は10個でしたので、手作業で解決してもそれほど負荷にはならないと思いますが、これが100個、1000個と増えてくると、手作業ではケアレスミスが発生し易い仕事になるので生成AIに手伝ってもらうのは良いアイデアだと思います。プログラミングが未経験の方には朗報となる省力化手法かと思います。

そういう意味では、Google Gemini がコード生成が上手くいかなかったのは生成AIの現在のレベルを知る良い知見になりました。ChatGPTとCopilotでは正しくコード生成できているので、僕が作成したプロンプトに間違いはないと判断しています。おそらく Gemini のチューニングのどこかに問題があるのでしょう。きっと2〜3週間後に同じプロンプトを与えると、正しいコードを生成してくれるのではないでしょうか?一般に生成 AIのチューニングは非常に人手がかかる厄介な仕事なんだそうで、Google のエンジニアがきっと解決してくれる…それが現在の生成AIサービスの問題点なんでしょうね。(つづく)

ここから先は

85字

¥ 100

この記事が参加している募集

この記事が気に入ったらチップで応援してみませんか?