h_nari @ 熊本市のブログ。電子工作、プログラミング、ゲーム、TV、 政治、インターネットなどに日々の思い付きを、 うだうだ~と書いていきたい。
このブログにはコメント欄を設けておりません。 記事への御意見、ご質問はtwitter @h_nari宛に お願い致します。


アーカイブ

メタ情報
RSS
Login

vtuberチャンネル登録者数取得プログラム

昨日 サメちゃんこと Hololive-ENのGawr Guraが チャンネル登録者数200万人を達成した。 V-tuberではKizuna Aiに次ぐ2番目だそうだ。 Hololiveの100万人超えメンバーは 戌神ころね126万、 白上フブキ119万、 兎田ペコラ117万で つい先日、湊あくあが100万を達成、 宝生マリンも99.4万人なので 数日中に100万人を突破するだろう。 チャンネル登録者100万人を越える日 の予想グラフと比べてみると興味深い。

ということで チャンネル登録者数の動向が気になるので 登録者数自動取得のプログラムを作成した。 1日1回起動し、データベースにデータを記録、 あとでグラフ化して眺める感じ。

ScialBladeのデータ

データの取得先だが、 まずは おあさんの記事を参考に SocialBlade を調べる。トップページで検索すると 各チャンネル等のデータを見ることができる。 例えば サメちゃんのデータとか。 大して面白くは無い。 むしろチャンネル登録者が200万いるのに subscriber rankが10,824位であることに驚く。

データは Bussiness APIで取得できるようだ。 但し使用するにはcreditを購入する必要がある。 creditの値段は最低単位だと100creditで$50。 但し今は新年割引で$26.55で購入可能。 user statisticsは1creditで30日間参照可能。 top listは24時間可能だそうだ。 最初に$50払うのは痛いし、 データを取得し続け、お金を払い続けるのも 嫌なので他を当たることにする。

Youtube Data API

youtubeというかgoogle自体も データをAPIで提供している。 YouTube Data API の概要 という文書がある。 Googleにアプリケーションを登録すれば データが取得できるらしい。 過剰なアクセスを避けるため クォータの制限はあるようだが とりあえず無料で使用できるようだ。

欲しい情報は channelsのlistにある。 下のurlにアクセスするとyoutubeのチャンネルの 統計情報(動画数、再生回数、登録者数)を取得できる。

https://www.googleapis.com/youtube/v3/videos?id=channelのID
  &key=ApplicationのKey&part=id,statistics

登録者数取得プログラム

あとはチャンネルIDのリストがあれば 各チャンネルの登録者数のデータを取得できる。 これもデータベース上に置くことを考えたが 管理プログラムを作るのが面倒なので Excelシートで管理することにした。 登録者数取得プログラムで読み込んで処理する。

プログラムはpythonで書いた。 ライブラリは webの読み書きに requests, Excelの読み出しに openpyxlfを使用した。 データベースへの書き込みは fluentd(td-agent)を使用しているので requestsで行っている。

プログラムを示す。

#!/usr/local/bin/python3
import openpyxl
import pprint
import requests
import json
def read_member_list( file ):
    wb = openpyxl.load_workbook(file)
    sheet = wb['List']
    for row in range(1,10):
        for col in range(1,5):
            cell = sheet.cell(row=row, column=col)
            if cell.value == 'member_id':
                break
        else:
            continue
        break
    else:
        raise Error('"member_id" not found')
    cTitle = row
    cId = col
    cGroup = cName = cChannel = None
    for col in range(col+1, col+10):
        cell = sheet.cell(row=row, column = col)
        if cell.value == 'group':
            cGroup= col
        elif cell.value == 'name':
            cName = col
        elif cell.value == 'channel_id':
            cChannel = col
    if cGroup == None:
        raise Error('"group" not found')
    if cName == None:
        raise Error('"name" not found')
    if cChannel == None:
        raise Error('"channel_id" not found')
    row = cTitle + 1
    data = {}
    while True:
        id = sheet.cell(row=row, column = cId).value
        if not id:
            break
        name = sheet.cell(row=row, column = cName).value
        group = sheet.cell(row=row, column = cGroup).value
        channel = sheet.cell(row=row, column = cChannel).value
        data[id] = {'name' : name, 'group': group, 'channel_id': channel}
        row = row + 1
    return data
def get_subs_data( app_key, channel_list ):
    url = 'https://www.googleapis.com/youtube/v3/channels'
    r = requests.get(url, params = {'key': app_key,
                                    'id': ','.join(channel_list),
                                    'part': 'id,statistics'})
    return r.json()
def put_data( members, data_list):
    url = 'http://fuent_dのホスト/データのid'
    channel2id = {}
    for id in members:
        ch = members[id]['channel_id']
        channel2id[ch] = id
    send_data = []
    for d in data_list:
        channel_id = d['id']
        id = channel2id[channel_id]
        if id:
            s = d['statistics']
            cSubs = s['subscriberCount']
            cVideo = s['videoCount']
            cView = s['viewCount']
            send_data.append({ 'member_id' : id,
                               'view_count': cView,
                               'subscriber_count': cSubs,
                               'video_count' : cVideo})
        else:
            print('channel %s not defined' % channel_id)
    if len(send_data) > 0:
        s = json.dumps(send_data)
        requests.post(url, data = s)
        print('%d data sent' % len(send_data))
    else:
        print('no data sent')
if __name__ == '__main__':
    app_key = 'アプリケーションのID'
    m = read_member_list('エクセルファイルのパス')
    channels = []
    for id in m:
        channels.append(m[id]['channel_id'])
    json_data = get_subs_data(app_key, channels)
    put_data(m, json_data['items'])

このプログラムをcronで1日1回動かし、 データの取得が始まった。

グラフ化

集めたデータをグラフで見たい。 とりあえず grafanaでグラフ化してみるが、 たくさんのチャンネルを表示する設定を 1つづつ手作業で行うのは大変だ。 何か方法はないかと調べたところ、 grafanaではグラフ表示の設定を json形式でexportしたりimportしたり することができる。 手作業で1つのチャンネルを表示する設定を作り、 json形式でexport。 それをベースにプログラムで 全てのチャンネルのグラフ設定を生成し、 grafanaでimportしてやれば良い。

以下のプログラムを作成した。 ちなみにimportしている read_member_list.pyは 前の登録者数取得プログラム。 この中のexcel読込み関数を使用している。

#!/usr/local/bin/python3
import json
from pprint import pprint
from get_data import read_member_list
member_list = 'チャンネルのリストのエクセルファイルのパス';
template_file = 'grafanaでexportしたjsonファイルのパス'
output_file = '出力するjsonファイルのパス'
sql_template = ("SELECT\n"
                + "  UNIX_TIMESTAMP(date) as time_sec,\n"
                + "  subscriber_count as value,\n"
                + "  \"{1}\" as metric\n"
                + "FROM data\n"
                + "WHERE $__timeFilter(date) and member_id = \"{0}\"\n"
                + "ORDER BY date ASC\n")
m = read_member_list(member_list)
targets = []
for id in m:
    name = m[id]['name']
    t = { "alias" : "",
          "format" : "time_series",
          "rawSql" : sql_template.format(id,name),
          "refId"  : name}
    targets.append(t)
f = open(template_file, 'r')
t = json.load(f)
for p in t["panels"]:
    p["targets"] = targets
with open(output_file, 'w') as f:
    json.dump(t, f, indent=2, ensure_ascii=False)

grafanaの表示例を下に示す。

今後

データを取り始めて、まだ2週間ほどだから仕方ないのだが グラフ化したものの、ほとんど水平の線ばかりで面白くない。 1年も経てば面白くなるかもしれない。 過去のデータも欲しいので、SocialBladeにお金を払って 取得しようかとも思うが1人あたり1credit, 25円とかかかるのは ちょっと考えてしまう。

カーソルを合わせれば数値は表示されるので 登録者数を調べるのは早くなった。 微妙なところを拡大とかはgrafanaで出来ないので そういう表示プログラムを自作しても良いかも知れない。

それにしても jsonは便利だ。 任意のデータ構造を表現できる man readableなテキスト形式で 様々な言語のライブラリが提供されている。 昔こういうものを夢想していたことを思い出した。 こういうものを楽に扱えるマシン環境、 スクリプト言語等が揃ったおかげで 普及したわけだが、 なんかソフトウェアの進歩を実感する。