pythonで模写してみた

Pythonならyoutubeアーカイブのチャット欄からコメントを取得できると思い、手を付けてみた。(実際はLIVEチャットの取得のみでアーカイブからではなかった)

 

どこをどう持っていけばよいのか参考にした動画を見ながら、Youtube DATA API のリファレンスで試していった。

正直いきなりやるものではないと思った笑

ただ、需要があるおかげでコードはyoutubeにあったので2日かけて少しずつ理解しながらなんとか模写。

(ちなみにここにコピーしたコードのインデントはスペースを開けてもブログのブラウザに反映されてないかも…) 

 

こちらが模写したコード。

import json
import time
import re
import datetime as dt
import matplotlib.pyplot as plt

from googleapiclient.discovery import build


class YouTubeLiveChat:
   # コンストラクタ…インスタンスに実体を持たせるための特殊メソッド(データの初期化も行っている?)
   def __init__(self, _video_id):
   _json_open = open('config.json', 'r')
   _api_key = json.load(_json_open)['api_key']
   _youtube = build('youtube', 'v3', developerKey=_api_key)
   self.video_id = _video_id
   # execute is used for connecting database
   _res = _youtube.videos().list(
   part='liveStreamingDetails', id=_video_id).execute()
   self.liveChat_id = _res['items'][0]['liveStreamingDetails']['activeLiveChatId']
  _publishedAt = _res['items'][0]['liveStreamingDetails']['actualStartTime']
   # youtubeライブラリをこれで使えるようになる
   self.youtube = _youtube
   self.pattern = '[T0-9-:]+'
   self.publishedAt = self.set_publishedAt_format(_publishedAt)
 
   def get_liveChat(self, _next_page_token):
     #get_liveChatにアクセスするためだけにこの関数があるのでとりあえずreturnで返している
     return self.youtube.liveChatMessages().list(
       liveChatId=self.liveChat_id,
       part='snippet',
       maxResults=2000,
       pageToken=_next_page_token  
     ).execute()

   def get_liveChat_all(self, _access_counts=2):
     _next_page_token = None
     _liveChats =
     _access_count = 0
     while 1:
       _res = self.get_liveChat(_next_page_token)
       # scope秒にコメントが0件の場合はリストを飛ばしている
      if len(_res['items']) > 0:
         _liveChats.append(_res['items'])
      _access_count += 1
     print("コメントを" + str(len(_res['items'])) + "件取得")
     _next_page_token = _res['nextPageToken']

     if _access_count == _access_counts:
       break

     print(str(
       self.convert_milisec_to_seconds(
       _res['pollingIntervalMillis'])
       ) + "秒後にアクセス")
     # timeのsleep関数で次のコメント取得まで待機させている
     time.sleep(self.convert_milisec_to_seconds(_res['pollingIntervalMillis']))
     return _liveChats
 
   def assemble_page(self, _liveChats, _scope): # _scope=何秒のスパンでデータ取得するか
     _datas =

     for _items in _liveChats:
       for _item in _items:
         # 正規表現で時間を計算できる値にする(情報を型落ちさせる)
         _dt = self.set_publishedAt_format(_item['snippet']['publishedAt'])
         # 今の時間 - 開始した時間 = 動画のコメント取得している時間(秒)を割り出している
         _dt = int*1
          # _scope秒で合計時間(秒)を割ることで時間をまとめている
         _datas.append(_dt - (_dt % _scope))
     return _datas
 
   # 同じ時間のコメントをまとめるための辞書
   def createDict(self, _datas):
     _dct = {}  
     for _data in _datas:
       _dct.setdefault(_data, 0)  
       _dct[_data] += 1
     return _dct

  def pyplot_show_liveChat(self, _liveChats, _scope):
    _datas = self.assemble_page(_liveChats, _scope=_scope)  
    _dct = self.createDict(_datas)
    _ls = []
    # はdefで関数を作らなくても引数を使うことができる
    _ls = sorted(_dct.items(), key=lambda x: x[0])
 
    #オブジェクトはintではなくstrでないと使えない
    _x = [str(dt.timedelta(hours=e[0]/3600)) for e in _ls]
    _y = [int(e[1]) for e in _ls]

    plt.plot(_x, _y)
     plt.show()
 
    _d = {}
    _d.update(zip(_x, _y))

  def set_publishedAt_format(self, _publishedAt):
    # 正規表現で必要な情報だけ取得
    return dt.datetime.strptime(re.findall(self.pattern, _publishedAt)[0],
        '%Y-%m-%dT%H:%M:%S')

  def convert_milisec_to_seconds(self, _milisec):
      return (_milisec/1000)
 
   # これを適用することで定義された戻り値をオブジェクトに付与できる。
   def __str__(self):
     return f'{self.video_id}, {self.liveChat_id}, {self.publishedAt}'
 
# モジュールを直接実行したときにだけ、実行したいコード
if __name__ == '__main__':
   _video_id = '動画のid'
   ylc = YouTubeLiveChat(_video_id)
   datas = ylc.get_liveChat_all(60) # 引数は_access_counts
   ylc.pyplot_show_liveChat(datas, _scope=60)
 
 

 

APIのKeyはconfig.json の中。

 

なんとかyoutubeの生放送のチャット欄のコメントは拾えるようになったのではなかろうか。さすがにまだここまで複雑なのはむりだけど、Youtube DATA API のリファレンスも使い方がわかってきたし学んでよかった。

 

参考にさせていただいたのはこちらの動画。

https://www.youtube.com/watch?v=_hxJlL6uVvg

 

本当にありがとうございました。

次はチャット欄からコメント拾って感情分析したり、アーカイブからコメント取得なんかもしてみたいができればRailsでやってみたいなぁ。



*1:_dt - self.publishedAt).total_seconds(