# 04_bilibili三国志_中国ファンの自作動画の弾幕を取得してみた | LittleVoice-g-string

LittleVoice-g-string

苦しむために生きないであなた自身を愛してくれ

04_bilibili三国志_中国ファンの自作動画の弾幕を取得してみた

弾幕を閉じる方法:メッセージボックスのようなボダンを押せば弾幕を閉じれます。

最近新解釈・三国志上映されたので、上映初日観に行きました!
福田監督の作品なので、三国時代の話を面白く語っていて、つかみ合いのシーンは個人的にとても良かったと思いました。また、城田優さんが演じた呂布はイメージ通りでしたが、岩田さんが演じた趙雲子龍のキャラはちょっと待ってって感じでした。笑

同時期に中国のbilibili動画サイト(ニコニコの中国版サイト)で中国のファンが三国をテーマに、複数のドラマ、映画から素材を集まって自作した動画を見つけました。77万回も視聴され、弾幕コメントは2000本ほどありました。とても気に入った動画なので、弾幕コメントを取得してみました。



1.動画のCIDを取得する

cid = 89046676

2.動画弾幕コメントのxmlにアクセス

Ⅰ.https://comment.bilibili.com/ + {cid}.xml
https://comment.bilibili.com/89046676.xml  
    →1000件コメントしか取得できない
    →場合によって8000件、500件だったるすて取得可能な件数が不安定らしいです。

Ⅱ.全件弾幕コメントを取得するには、
https://api.bilibili.com/x/v2/dm/history?type=1&oid={cid}&date={date} 
    →本動画は2019-04-29からアップロードされたので、date = 2019-04-29 ~ 2021-01-05の弾幕を取得していきたいと思います。

3.最新コメントを取得してみよう

requestモジュールを使って取得してみた

import requests
from bs4 import BeautifulSoup

url = 'https://comment.bilibili.com/89046676.xml'
request = requests.get(url)
request.text
#一度文字コードを設定する
request.encoding='utf-8-sig'
#取得してきたテキスト文書をBeautifulSoupで分析する
soup = BeautifulSoup(request.text,'lxml')

#テキスト文書の中身を確認すると、弾幕コメントはすべて以下のフォーマットに格納していることがわかった
#<d p="18.29700,1,25,16777215,1609775751,0,8d1aab76,43323792511467527">テキスト</d>

#したがって、<d>を抽出する
results = soup.find_all('d')
#コメント部分だけを取得
comments = [comment.text for comment in results]
len(comments)
#1000
#このやり方で1000件コメントしか取得できない。

4.古いコメントを取得してみよう

#bilibiliの古い弾幕コメントは1日分ごとにxmlに格納されている。上記リンクで日付を指定することで、該当日の弾幕コメントを取得できる。
 しかし、こちらのxmlデータをアクセスするには、ログインする必要がある。
 本記事はseleniumを使ってログインを行いたいと思う

from bs4 import BeautifulSoup as bs
import pandas as pd
from selenium import webdriver
import time, datetime

url_login = 'https://passport.bilibili.com/login'
driver = webdriver.Chrome()
driver.get(url_login)
#ここでログイン情報を入力↓↓↓
cid = 89046676
begin = '2019-04-29'
end = '2021-01-05'
fmt = '%Y-%m-%d'

#ある期間中の日付を一日単位で取得する
def day_range(bgn,end):
    fmt = '%Y-%m-%d'
    begin=datetime.datetime.strptime(bgn,fmt)
    end=datetime.datetime.strptime(end,fmt)
    delta=datetime.timedelta(days=1)
    interval=int((end-begin).days) +1

    return [begin+delta*i for i in range(0,interval,1)]

time_list = [m.strftime(fmt) for m in day_range(begin,end)]
#対象となるすべてのxmlをリストに格納
urls = ['https://api.bilibili.com/x/v2/dm/history?type=1&oid='+str(cid)+'&date='+str(i) for i in time_list]
htmls = []
for i in urls:
    driver.get(i)
    time.sleep(3)
    #get_attribute('innerHTML'):seleniumでWebElementからhtmlを取得する
    htmls.append(driver.find_element_by_tag_name('i').get_attribute('innerHTML'))

soups = [bs(h,'lxml') for h in htmls]
results = [soup.find_all('d') for soup in soups]
resultss = sum(results,[])
comments = [comment.text for comment in resultss]
len(comments)
#608931

#重複削除
commentss = list(set(comments))
len(commentss)
#1625 

5.残る課題

1_弾幕コメントだけではなく、日付情報も取得したい
2_違うユーザーは同じ弾幕コメントを出すことが可能なので、ユーザー情報取得可能か
3_短い文書の解析
4_モジュールにしたい

参考文献

[Python][Bilibili]B站历史弹幕爬虫

Welcome to my other publishing channels