せっかくだから俺は衆院選のニコ生の党首討論のコメントを解析するぜ

Table of Content

背景

ネット選挙が解禁され、インターネットを活用した選挙情報の提供が盛んになると思いきや、ダメな方向の活用が目立つ、昨今皆様、いかがお過ごしでしょうか。

2014年11月29日、衆院選を控えてニコ生で党首討論がおこなわれました。安住先生がおしゃる「偏った動画サイト」に登場して討論を繰り広げた党首の皆様に敬意を表すると共に、実際のところ偏っているのかどうか調べてみました。

ソースコード
https://github.com/mima3/analyze_election

解析結果

【衆院選2014】ネット党首討論

http://needtec.sakura.ne.jp/analyze_election/page/nicolive/lv200730443

結論からいうと、新聞の世論調査では影の薄い「次世代」が注目されていたり、ひとりで数百のコメントをする猛者がおったり、社民党の吉田党首のほうが野党一党の海江田党首より多く抽出されたり、正直、バグでもあるような結果になりました。

党首討論会 in 日本記者クラブ(時事通信チャンネル)

http://needtec.sakura.ne.jp/analyze_election/page/nicolive/lv201303080

さすがに、コメント数は土曜の夜より少なめ。だけど、一人で200程度はコメントする方はいる。仕事or学校いry。

やはり、「安倍」とか「次世代」という単語がおおく抽出される。
ただ、ニコ生主催のときより「海江田」とか「民主」の存在感がある。

あと、なんで、党首討論に椿事件の「椿」とか「朝日」とかいう単語が大量にでてくんですかー(棒)

Pythonでニコニコ生放送のコメントを取得する方法

ニコニコ生放送のコメントを取得するには、まず、プレミアム会員でなければなりません。
通常の会員では、1000件程度が上限となります。

その上で、以下の手順で取得できます。

  1. メールアドレスとパスワードを用いて、ログインページにてログインして、user_sessionを取得する
  2. http://watch.live.nicovideo.jp/api/getplayerstatus にアクセスしてメッセージサーバのIPとポート、そしてユーザIDを取得する。
  3. http://watch.live.nicovideo.jp/api/getwaybackkey にアクセスしてwaybackkeyを取得する。このキーとユーザIDを組み合わせて過去のコメントが取得できます。
  4. メッセージサーバに接続してコメントを取得します。この際、HTTP通信かSOCKET通信のどちらかで接続できます。HTTP通信の際はポート番号から2725を引いたポートに接続する必要があります。
  5. 一回のGETで1000件しか取得できないので、whenを適切に設定しつつ全てのコメントを取得します。

具体的なコードは次のようになります。

niconico.py

# coding: utf-8
import sys
import cookielib
import cgi
import urllib
import urllib2
from lxml import etree
import socket
import datetime
import time
import json

class NicoCtrl():
    def __init__(self, nicovideo_id, nicovideo_pw):
        self.nicovideo_id = nicovideo_id
        self.nicovideo_pw = nicovideo_pw
        # ログイン
        cj = cookielib.CookieJar()
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
        req = urllib2.Request("https://secure.nicovideo.jp/secure/login")
        req.add_data( urllib.urlencode( {"mail": self.nicovideo_id, "password":self.nicovideo_pw} ))
        res = self.opener.open(req).read()
        if not 'user_session' in cj._cookies['.nicovideo.jp']['/']:
            raise Exception('PermissionError')

    def _getjson(self, url, errorcnt):
        # 途中でJSONが切れて帰ってくる場合があるので、リトライ処理
        try:
            res = self.opener.open(url, timeout=100).read()
            return json.loads(res)
        except ValueError:
            if errorcnt < 3:
                errorcnt = errorcnt + 1
                return self._getjson(url, errorcnt)
            else:
               raise

    def get_live_comment(self, movie_id):
        self.movie_id = movie_id

        # 動画配信場所取得(getflv)
        res = self.opener.open("http://watch.live.nicovideo.jp/api/getplayerstatus?v="+self.movie_id).read()
        root = etree.fromstring(res)
        messageServers = root.xpath('//ms')
        if len(messageServers) == 0:
            raise Exception('UnexpectedXML')

        user_ids = root.xpath('//user_id')
        if len(user_ids) == 0:
            raise Exception('NotfoundUserId')
        user_id = user_ids[0].text

        thread_id = messageServers[0].find('thread').text
        addr = messageServers[0].find('addr').text
        port = int(messageServers[0].find('port').text) - 2725

        # waybackkey の取得
        waybackkeyUrl = ('http://watch.live.nicovideo.jp/api/getwaybackkey?thread=%s' % thread_id)
        req = urllib2.Request(waybackkeyUrl)
        res = self.opener.open(waybackkeyUrl).read()
        waybackkey = cgi.parse_qs(res)['waybackkey'][0]

        msUrl = 'http://%s:%d/api.json/thread?' % (addr, port)
        chats = []
        req = urllib2.Request(msUrl)
        when = '4294967295'
        while True:
            data = {
                'thread' : thread_id, 
                'version' : "20061206",
                'res_from' : '-1000',
                'waybackkey' : waybackkey,
                'user_id' : user_id,
                'when': when,
                'scores' : '1'
            }
            list = self._getjson(msUrl+urllib.urlencode(data), 0)
            chatcnt = 0
            insertdata = []
            for l in list:
                if 'chat' in l:
                    if chatcnt == 0:
                        when = int(l['chat']['date']) - 1
                    if l['chat']['content'] != '/disconnect':
                        insertdata.append(l['chat'])
                    chatcnt += 1
            chats = insertdata + chats
            if chatcnt == 0:
                break
        return chats

nicolive.py

# coding: utf-8
import sys
from niconico_ctrl import NicoCtrl
import json

def main(argvs, argc):
    if len(argvs) != 4:
        print ('python nicolive.py email pass lv142315925')
        return 1
    nicovideo_id = argvs[1]
    nicovideo_pw = argvs[2]
    move_id = argvs[3]

    t = NicoCtrl(nicovideo_id, nicovideo_pw)
    chats = t.get_live_comment(move_id)
    f = open(move_id + '.json', 'w')
    f.write(json.dumps(chats))
    f.close()
    return 0

if __name__ == '__main__':
    argvs = sys.argv
    argc = len(argvs)
    sys.exit(main(argvs, argc))

このスクリプトは以下のように実行することで、コメント情報が格納されたJSONファイルを生成します。

 python nicolive.py   メールアドレス パスワード lv200730443

あとは作成されたJSONファイルのコメントを形態素解析して単語を抽出したり、ユーザ毎に集計したりなんやかんやを行えば、ニコ生のコメントが解析できるよ、やったね、たえちゃん。

参考

niconicoのメッセージ(コメント)サーバーのタグや送り方の説明
http://blog.goo.ne.jp/hocomodashi/e/3ef374ad09e79ed5c50f3584b3712d61

ニコニコ動画のコメントを取得する
http://d.hatena.ne.jp/MOOOVe/20120229/1330512626

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です