見出し画像

一覧、補完計画 〜作品一覧ヲ補完セヨ〜


■動機:そのnoteは読まれているか

それは2023年、カクヨムコンから流れてきた私は、noteで「創作大賞2023」なるコンテストをやっていることを知り、過去作の小説で応募することにしました。まだnoteのことも良く分かっておらず、フォローもフォロワーも少ない(ない)状態。それでも応募すれば読んでもらえるかも! と思っていたのですが、甘かった。

「全く読まれない!」

どうすれば読者を引き込めるのかも分からず、結局分からないまま創作大賞2023は終わったのでした。

そして2024年。当初は応募する予定はなかったのですが、見てるとなんか楽しそうで、やっぱり創作大賞2024に応募することにしたのです(過去作で😅)。でも、やっぱり読まれない。創作大賞の部門に応募すると、一瞬検索画面の「新着」に表示されるんですが、あれよあれよと言う間に画面外に追いやられ、再び厳しい現実に直面することに。しかし、これで手をこまねいていては去年の二の舞ではないか! と言うことで色々考えました。フォロー、フォロワーを増やすのはもちろん、「自分の作品が掲載されているnoteを常に供給し続ける手段」を考えたわけです。

「せや! 自分が応募してる部門の作品リスト作ったらいいのでは?」

うーん、安直! しかし、ここから「作者&作品一覧」の作成が始まったのでした。

◇光あれ

去年、各小説部門+オールカテゴリ部門のリストを作っていて分かったのは、「読まれないこと」に悩んでいる人がイッパイいると言うこと。最初は自分の投稿作向けに作り出した「作者&作品リスト」ですが、

可能な限り多くの作品に光✨を当てる

と言うなんか壮大な目的に変化していきました。

■noteの仕様を調査せよ

リストを作るとなると、まずはnoteの仕様を知らなければなりません。一作一作手動で情報取得して書き写すわけにも行かないので、プログラムでスクレイピングする方法を検討します。

◇タグ検索

まずはタグ検索から。noteは作品ごとにタグを付けられて、これを用いて作品の検索ができます。これが強力で、創作大賞の作品リストも基本的にはこの機能により成立しています。例えば創作大賞のミステリー小説部門に応募するのであれば「#創作大賞2025」「#ミステリー小説部門」の2つの必須タグを付けることになりますよね。

タグ検索の特徴として

  • 検索時は1つのタグしか指定できない。

  • 検索は2000 noteまで表示可能(現在は1000 noteに制限されている様です)

  • 検索結果の「新着」は投稿順(新しい順)、「人気」はPV数や❤️数、時間などのパラメータから計算して上位から表示(2ヶ月ぐらい経つと、PVや❤️数が多くてもガクっと順位が落ちる)

  • 「人気」については、編集すると一時的にリストから消える

◇API

プログラムでnoteサーバからデータを取得する上で、「APIが公開されていること」は必須なのですが、幸いにしてREST形式のAPIがあったので実施確定。ただし、公式にアナウンスされているものではないので、ここでは詳しく触れません。noteでも記事を書いておられる方がいますし、Webブラウザのデバッグモードなどを使用すればAPIを見ることができます。

今回は、

  • タグ検索の結果を取得するAPI

  • 各noteの詳細情報を取得するAPI

を使用します。

◇note情報(JSON)

各noteの情報(JSON形式)

タグの検索結果も、そこからnoteのIDを読み取って取得したnote情報も、APIで取得できる情報はJSON形式です。タグ検索について、創作大賞2024の際は1回のAPIコールで20個分のnote情報がダウンロードでき、それが100ページ分で合計2000 note分の情報を取得できたのですが、今年は50 note x 20 ページで1000 note分になりました。

十分な数字にも見えますが、オールカテゴリ部門やエッセイ部門は異常に数が多いので、例えばオールカテゴリなら1000個でカバーされるのは2025/5/30 21:00投稿された記事までです。約1週間分……それよりも古いものは「新着」では確認できません。

◇note記事の記述方法

これは日々、皆さん書いておられるので良くご存知だと思いますが、noteの記事はMarkdown形式で書くことができます。例えば

■(1009)[たおたお 様](https://note.com/taotao_marudora)
* 🎧[佐々木真里さんのことを語りたい](https://note.com/taotao_marudora/n/n5bef25028bd9)
* 📸[空と太陽と鉄塔と](https://note.com/taotao_marudora/n/ndd7fc9513988)
-----

Markdown形式

こういう感じのテキストを書いてエディタ画面にベタっと貼り付けると、

■(1009)たおたお 様


↑こんな感じで変換して表示してくれるんです。これは一覧を作った後で記事に貼り付けるときにとても助かる! つまりプログラムでMarkdown形式のテキストファイルを作っておけば、その内容を貼り付けるだけで整った記事が作成できます!

■プログラム仕様を決める

ここは本職として手を抜くわけには行かない! ……んですが、まあ製品に載せるようなプログラムを書くわけではないので、ちょっと手抜きします😎

◇プログラミング言語

本職同様、C言語でガッツリ組めば高速に動作するのかも知れませんが、C言語で文字列処理など地獄を見るのは分かっているので、ここは簡単に書けるLuaを選択します。

スクリプト言語 Lua

スクレイピング出来ればPythonでもRubyでもなんでもいいんですが、普段から使っているのでLuaでいいや。因みにLuaとはポルトガル語で月の意味。言語仕様が簡素で普段使いなら十分な機能を備えています。

◇システムの概要

システム構成

まあシステムって程ではないですが、要はnoteのサーバからガンガンJSONファイル引っ張ってきて、それをテキスト形式で保存。そこから色々やってMarkdown形式のリストを作成し、これをnote編集画面で手動でコピペする感じです。

◇処理の流れ

フロー図

なんか凄い処理!😅

  • 既存のCSVファイを読み込み

  • タグ検索を使って各部門の一覧をnoteサーバから入手

  • 入手した一覧中の各作品について、詳細をサーバから入手して「#創作大賞2025」タグが付いているかどうかを確認する

  • 「#創作大賞2025」タグが付いているnoteについて、以下の情報を取り込み保持する。

    • note記事ID

    • 投稿時間

    • URL名

    • ハンドル名

    • タイトル

    • タグ情報1,2

  • 既存データ中の最新のデータより新しいものをデータとして取り込み。

  • 全情報をCSV形式でファイルに保存

  • 今までに記録していた情報と合わせて、全noteデータをURL名ごとに分類し、その内最新のデータをMarkdownで表示する様にする

  • 全データの中からランダムにn個選択してRandom Selection様のMarkdownファイルに追記

  • 生成したMarkdownファイルは手作業でnoteの編集画面にコピペ。基本的にはそれ以上の作業は不要(あとは投稿するだけ)

タグ情報は分類のために今回決めた独自タグを検出した場合に使用します。

◇創作大賞2024からの変更点

リスト作成は創作大賞2024からやっていましたが、今年は去年の教訓を活かしてもっといい感じにしたい! と、言うことで以下の仕様を追加しました。

  • 全部門のリストを作成する! : 創作大賞2024では各小説部門だけでしたが、どうせやるなら全部門やります。

  • 過去作の取り込み方法 : 一番始めに検索したときにヒットした、過去作に創作大賞タグを付けたものは取り込めます。ただし、期間中にタグを付けた過去作は取り込めてませんでした。これに対応するために、リスト作成専用のタグを定義して、noterの皆様に使ってもらいます。

  • TALES!? : 今年は突如として小説専用のTALESサイトが立ち上がりました! しかしTALESに投稿された小説はプログラムでは取り込めません。でも、なんとかして取り込める方法を模索します。

  • オールカテゴリ部門を分類する : 真逆の方向に進んでる感じもしますが、色々なカテゴリの記事が集まるからこそ、読む人のために分類したいと思います。

こういう処理も入れたもので、「なんか凄い処理!」になってます。「凄い面倒くさい処理!」でもあります

◇TALES側小説の取り込み

TALES側の小説をnoteから見れるわけでもなく、アカウントは連携していてもコンテンツはまだ未連携。REST APIがあるかと言うとこれもまだなくて、スクレイピングして取り込むことは不可能と判断しました。でも、リストには載せたい! ってことで無理やりnote側で取り込むために、以下の仕様を決めます。

  • (リストに登録したいnoterさんに)note記事を書いてもらう

  • 記事のタイトルは[<TALES小説ID>]<TALES小説タイトル>としてもらう。

  • 「#テ25ミス」など、部門ごとのタグをnote記事につけてもらう

  • 内容は自由

例えば

これが私のTALES側小説の紹介note記事ですが、この様なタイトルと必要なタグをつけることで、プログラムでこれを拾ってリストに組み込むことにします。

■いざ、プログラミング!

◇ソート

せいぜい1000行程度のプログラムなので全部貼り付けてもいいんですが、まあ見ても大して面白くもないでしょうから、ユーザーソートの部分だけちょこっと🤏

作品のソート

データを取り込んだ直後は、Aさん、Bさん、Cさんの作品は時系列ながら結構バラバラに入ってます(左側)。これをそれぞれの作者ごとに並べ替える作業をSort(ソート)と言って、luaの場合はtable.sort()関数を使用すれば簡単に実現できます。

function t_comp(a, b)

    if a[3] ~= b[3] then

        if sort_ascend == 1 then
            return a[3] < b[3]

        else
            return a[3] > b[3]

        end
    else

        local ret = note_comp_time(a[2], b[2])

        if ret == 1 then

            return true

        else

            return false

        end

    end

end

--(3)Sort novel info by urlname
table.sort(novel_list_file, t_comp)

創作大賞2024の時は日ごとに昇順・降順を切り替えられる様にしていたのでちょっと長いですが、a[3](URL名)を比較して違うURL名だったら昇順で比較、URL名が同じなら時間で比較と言うことをやってます。

ソートはこれだけではなく、例えばRandom Selection用のファイルを作る時は「note記事ID」でソートします。noteの記事IDは「n」から始まる13桁の文字列で、「n」以降の12桁については16進数のランダムな整数値となっています。例えば上に貼った拙作のIDは「n3f302cfd1ee3」で、URLは

https://note.com/taotao_marudora/n/n3f302cfd1ee3

となっています。「3f302cfd1ee3」は16進数で、10進数に直すと69476145766115。これらの値はランダムなので、順番にソートしてやると、結果的に記事はランダムにバラけることになります(ソートしない場合、シリーズものなどの場合は同じ人の別記事が連続して投稿されていることも多いので、いくつか選んだ際に「同じストーリーの別の話」が何個も選ばれる様なことがあります)

◇CSVファイル

各部門のnote情報はCSV形式で保持しています。テキストなのでサイズ的には大したことはなく、エッセイ部門でも1.1MBぐらい(あれ、結構でかい💦 9000近くの記事があるので当然か)。しかしLuaならこれぐらいのサイズのテキストなら難なく処理可能です。

CSVファイル

CSVファイルは必要な情報のみ記録していて、URLなどはこれらの情報から作ってMarkdown記事に貼り付けます。一番上が一番新しい投稿になっているので、翌日の更新ではこの上にデータがどんどん挿入されていく感じ。

◇Markdownファイル

Markdownファイル

上のCVSのデータをユーザーごとにソートして最新のnoteを抽出し、且つ各ユーザーのプロフィールURL、note記事へのURLをリンクとして挿入してMarkdownファイルを構成します。

先頭のアイコンが🔶になっているものはTALES側の小説を取り込んだもの。ちょっと図中の文字が小さいですが、URLがちゃんとTALESのものになってます!😆 アイコンが1️⃣のものは過去作、もしくは新規のものでも「1話目」を取り込んだもの。ちゃんと過去作の救済もできてますし、1話目の固定表示もできてます。

◇オールカテゴリ部門の分類

「#〜部」と言うタグを作って、これを設定してもらえばアイコンが変わる様になっているのですが、こちらはなかなか普及せず。仕方ないので取り込んだデータのタイトルをキーワードでチェックして、該当するものがあれば(勝手に)アイコンを変更しています。

local cattags = {
    {tag = "#小説部"         ,icon = "📔", words = {"ショート", "短編", "掌編", "物語", "小説"}},             --1
    {tag = "#ポエム部"       ,icon = "🎈", words = {"詩", "ポエム"}},                                         --2
    {tag = "#詩歌部"         ,icon = "🍁", words = {"短歌", "俳句", "和歌"}},                                 --3
    {tag = "#音楽部"         ,icon = "🎧", words = {"弾き語り", "クラシック", "音楽活動", "楽曲"}},           --4
    {tag = "#動画部"         ,icon = "📹️", words = {}},                                                       --5
    {tag = "#写真部"         ,icon = "📸", words = {"写真", "撮ってきた", "スナップ", "自撮り", "フォト"}},   --6
    {tag = "#スポーツ部"     ,icon = "⚽", words = {}},                                                       --7
    {tag = "#趣味部"         ,icon = "🧸", words = {}},                                                       --8
    {tag = "#読書部"         ,icon = "📚", words = {"読書", "書評"}},                                         --9
    {tag = "#文学部"         ,icon = "✒️", words = {}},                                                       --10
    {tag = "#絵本部"         ,icon = "🐥", words = {"絵本"}},                                                 --11
    {tag = "#美容部"         ,icon = "💄", words = {}},                                                       --12
    {tag = "#映画部"         ,icon = "🎬", words = {"映画"}},                                                 --13
    {tag = "#テクノロジー部" ,icon = "🤖", words = {"AIイラスト", "生成AI", "ChatGPT"}},                      --14
    {tag = "#くらし部"       ,icon = "🏠", words = {"子育て"}},                                               --15
    {tag = "#旅行部"         ,icon = "🌏", words = {"見物記", "日帰り", "修学旅行", "個人旅行"}},             --16
    {tag = "#ファッション部" ,icon = "👠", words = {}},                                                       --17
    {tag = "#教育部"         ,icon = "📐", words = {}},                                                       --18
    {tag = "#芸能部"         ,icon = "🧑", words = {}},                                                       --19
    {tag = "#アート部"       ,icon = "🎨", words = {"絵", "イラスト"}},                                       --20
    {tag = "#コラム部"       ,icon = "🗒️", words = {}},                                                       --21
    {tag = "#デザイン部"     ,icon = "🖌️", words = {}},                                                       --22
    {tag = "#マンガ部"       ,icon = "🧚", words = {}},                                                       --23
    {tag = "#エッセイ部"     ,icon = "📝", words = {}},                                                       --24
    {tag = "#ゲーム部"       ,icon = "🕹️", words = {}},                                                       --25
    {tag = "#ハンドメイド部" ,icon = "🪡", words = {"撮影セット"}},                                           --26
    {tag = "#料理部"         ,icon = "🍳", words = {"料理", "美味"}},                                         --27
    {tag = "#仕事部"         ,icon = "💼", words = {"ビジネス"}},                                             --28
}

Luaでは上記の様なテーブルを用意してあって、例えばタグに「#小説部」があった場合、もしくはタイトルに「ショート」「短編」「掌編」「物語」「小説」のキーワードが入っていた場合にはアイコンが📔に設定される様になってます。実際にオールカテゴリ部門の一覧を見てみると

オールカテゴリ部門の一覧ページ

この辺りは割とアイコンが変わっているものが入っていて、小説部(📔)、詩歌部(🍁)、写真部(📸)があるのが分かります。作品を探す時に参考になる!(かも)

なぜ詩歌部が🍁アイコンなのか、それは……何となくです😂

■最後は手動

◇記事の更新

各部門の「作者一覧」記事は同じファイルを毎日更新する形式を取っていますが、例えばミステリー小説部門の一覧だと

https://editor.note.com/notes/nd33967e445e5/edit/

編集画面のURL

ログインしている状態なら上記でいきなり編集画面に入ることができます。メニュー(…)から編集を選んで……と最初の頃はやっていましたが、これを知ってから全部門の編集画面を全部一気にブラウザで開ける様になったので、作業効率が爆上がりしました📈。

WebDriverなど用いれば編集画面を自動的に開いて記事を自動的に貼り付けることも可能なのかも知れませんが、そこまでプログラミングすることもないので最後は手動頼みです。もう一点、Markdownで

https://note.com/taotao_marudora/n/n3f302cfd1ee3

が書いてあってこれを画像つきのリンクに変更しようと思うと、どうしても手動でEnterキーを押さなければならない。そうしないと単にURLが書いてあるだけになってしまうんですよねー。

◇Random Selection 120

ここまでで全部門リスト化したのはいいんだけど、応募数が増えてきたらリスト自体も大きくなってきて、やっぱり発見されない……と言うジレンマがあり、「Random Selection」ページを作りました。全部門、全応募作(手元のテキストファイルに保持できているもの)の中から各部門10作ずつ、合計120作をランダムに抽出してリストにしています。そして各部門の先頭に来た作品については画像つきのリンクで紹介してます。

function rnd_novel_info(index, genre, t)

    local str = ""
    local tales_id = ""
    local tales_title = ""

    if t ~= nil then

        if t[5] == nil or t[5] == "" then

            t[5] = "■"

        end

        if index == 1 then

            str = str .. "# ■" .. genre .. "\n"
            print(str)

        end


        if index == 1 then

            str = str .. "### 作者:" .. "[" .. t[4] .. " 様](https://note.com/" .. t[3] .. ") : "

            if t[6] == "2" then

                tales_id, tales_title = string.match(t[5], "%[(.*)%](.*)")

                str = str .. tales_title .. "\n"
                str = str .. "https://tales.note.com/" .. t[3] .. "/" .. tales_id .. "\n"

            else
                str = str .. t[5] .. "\n"
                str = str .. "https://note.com/" .. t[3] .. "/n/" .. t[1] .. "\n"
            end
        else

            if t[6] == "2" then

                tales_id, tales_title = string.match(t[5], "%[(.*)%](.*)")

                str = str .. "### [" .. tales_title .. "](https://tales.note.com/" .. t[3] .. "/" .. tales_id .. ")\n"

            else

                str = str .. "### [" .. t[5] .. "](https://note.com/" .. t[3] .. "/n/" .. t[1] .. ")\n"
            end

            str = str .. "作者:" .. "[" .. t[4] .. " 様](https://note.com/" .. t[3] .. ")\n"

        end

        str = str .. "\n"
        str = str .. "-----\n"
        str = str .. "\n"

    end

    return str

end

"if index == 1"の部分が先頭で、その場合はURLを直接Markdownに書き込む様にしてます。もちろん、TALESリンクの場合はTALESのURLが表示される念の入れ様😤

■完成!

◇更新報告

更新は大体夜の9時30〜10時の間。更新が完了したら

  • 更新報告のnote記事

  • Xで更新記事を宣伝

をします。

◇黄色い画像

そして一発で「作者一覧」だと分かるために用意したのがこちらの画像。

黄色い画像

「目立つ配色」でWeb検索すれば、この配色がいかに目に止まりやすいか分かって頂けるはず。目がチカチカする😵けど、そんなことは気にしない。

ミステリー小説部門の一覧画面

実際の検索画面(新着)で見てもらえれば、どれぐらい効果があるかは一目瞭然ですね! そして各部門タグ検索結果の「新着」ページを見た時、この画像で挟まれた部分が24時間で投稿されたnoteだと分かります。

副産物

なお、副産物として、自分のプロフィール画面が真っ黄色になります😂

◇成果物

創作大賞2025の作者様&作品一覧はマガジンとしてまとめてあります。是非是非、見てみてくださいね!

■まとめ

◇一覧とその効果

お陰様で一覧を作り始めた創作大賞2024の間に、多くのnoter様と交流ができフォロー、フォロワーも増え、すっかり「黄色い画像の人」が定着しました。特にRandom Selectionの画像つきリンクで選ばれると記事は❤️が増えることが多いみたいで、noter様の交流の一助にはなっている様です。

一覧記事に❤️やコメントくださる方も多く、何かしらお役に立ててることは嬉しい限りです😆。

◇続けること

なにより重要なのは最後までやり切ること、と自分の中では決めているので、最後まで「毎日更新」できるように頑張ります! ただ、そこまで必死になってる訳でもないので何かあったら休みますが、その場合は生暖かい目で見守ってください。

◇最後に

「埋もれてしまった作品に光が当たれば」との想いで一覧作りを続けておりますが、これらは皆様の創作大賞応募作があってのことです。何か不具合等ありましたら連絡頂ければ(手動で)対応致します。

また、非公式のREST API使用を許容くださっているnote公式の方々にも感謝致します。極力サーバに負荷を掛けない様にしておりますので、願わくは今後もこれらの一覧作成を許容頂ければ幸いです。

創作大賞2025もそろそろ折返し地点🏃 後半に入ると作品を読んだり感想を書き始める人も増えるので、是非リストを有効に活用頂ければ嬉しいです! 皆で創作大賞、楽しんでいきましょう♪