夜が静寂を取り戻す頃

日記 << 考えや感情. 外に発散する場として. たまに備忘録

ニコニコ生放送情報取得

ニコ生アラート(本家)の仕様とは (ニコナマアラートホンケノシヨウとは) [単語記事] - ニコニコ大百科 に情報がまとめられてる。 XMLRequest とかいうよくわからんことを要求されたが、pythonでXMLSocket - たいしょー(miettal)の日記 をみつつ適当に書いたら動いた(適当)。以下コード

#!/usr/bin/env ruby

require "net/http"
require 'uri'
require 'pp'
require "rexml/document"
require 'socket'
require 'pry'

def login_free()
  uri = URI.parse('http://live.nicovideo.jp/api/getalertinfo')
  res = Net::HTTP.start(uri.host, uri.port) {|http|
    http.get( uri.path )
  }

  xml = REXML::Document.new(res.body)

  raise "returned status: not ok" unless xml.elements["getalertstatus"].attribute("status").value == "ok"
  addr = xml.elements["getalertstatus/ms/addr"].text
  port = xml.elements["getalertstatus/ms/port"].text
  thread = xml.elements["getalertstatus/ms/thread"].text
  return addr,port,thread
end

def login(mail, password)
  uri1 = URI.parse('https://secure.nicovideo.jp')
  https = Net::HTTP.new(uri1.host, uri1.port )
  https.use_ssl = true
  res = https.start {|http|
    http.post( "/secure/login?site=nicolive_antenna" ,"mail=#{mail}&password=#{password}")
  }
  raise "login err" unless res.code == "200"
  xml = REXML::Document.new(res.body)

  resp = xml.elements["nicovideo_user_response"]
  raise "unexpected responce" unless resp.attribute("status").value == "ok"
  ticket = resp.elements["ticket"].text
  puts "ticket=#{ticket}"

  uri2 = URI.parse('http://live.nicovideo.jp/api/getalertstatus')
  res = Net::HTTP.start(uri2.host, uri2.port) {|http|
    http.get( uri2.path + "?" + "ticket=#{ticket}")
  }
  xml =   xml = REXML::Document.new(res.body)
  raise "returned status: not ok" unless xml.elements["getalertstatus"].attribute("status").value == "ok"

  puts "communities = " ,xml.get_elements("getalertstatus/communities/community_id").map {|e| e.text}.join(";")

  puts "user_id = ", xml.elements["getalertstatus/user_id"].text
  puts "user_name = ", xml.elements["getalertstatus/user_name"].text

  addr = xml.elements["getalertstatus/ms/addr"].text
  port = xml.elements["getalertstatus/ms/port"].text
  thread = xml.elements["getalertstatus/ms/thread"].text
  return addr,port,thread
end

addr, port, thread = login(ARGV[0],ARGV[1])
p addr,port,thread

s = TCPSocket.open(addr, port)
s.write("<thread thread=\"#{thread}\" version=\"20061206\" res_from=\"-1\"/>")
s.write(0.chr)

r = ""
while true
  r += s.recv(100000).to_s
  while i = r.index( 0.chr )
    thread = r[0, i]
    r = r[i+1, (r.size() -1)] # if i+1 == r.size, then r would be ""

    puts thread
    puts ""    
    
  end
  #sleep 1
end

これ、ログインしてからコメントサーバに接続しても、すべての放送が push されるわけだけど、それは良いのかな。 server 側は一回 push して各クライアントが勝手にもらってく、って形だから大丈夫っぽい?(情弱)。
ニコ生アラート(偽)をつくるなら、参加コミュニティをまず取得しておいて、すべての新着放送から該当する放送のみをフィルタリングする感じだと思う。


それともうひとつ、mechanize で マイページにアクセス、リダイレクトされるのでログイン、再びアクセス、の流れ。本当は web-client(mechanize)使わずに net/http だけでやりたかった。しかしニコニコ動画はログイン管理に cookie 使っているらしくて、その cookie の扱いが ローレベルの net/http だけでやろうとすると、 cookie の仕様やら何やらも考慮する必要があってよくわからなくなってしまった。結果、妥協して mechanize を使った。

# -*- coding: utf-8 -*-
require 'mechanize'
require 'uri'
require 'pry'

agent = Mechanize.new
agent.user_agent = 'Mozilla/7.0'

top = URI.parse 'http://www.nicovideo.jp/my/top'

agent.redirect_ok = false
r = agent.get(top)

raise "err" unless r.code =~ /30[12]/
login_page = r.header["location"]

r = agent.get(login_page)
#agent.verify_mode = OpenSSL::SSL::VERIFY_NONE

next_page = r.form_with(:id => 'login_form') do |form|
  raise "no such form" if form.nil?
  form.mail_tel = ARGV[0]
  form.password = ARGV[1]
end.submit

p next_page.code, next_page.uri, next_page.header["location"] #> loc = /my/top

r = agent.get(top)
p r.at("html/body").text

File.open("tmp.html", "w") {|f|
  f.write( r.body )
}

ニコニコ動画ログイン, cookie & session with ruby

Rubyとnet/httpsライブラリを使用してニコニコ動画にログインする - Qiita
2007-02-16 - みずぴー日記
How to implement cookie support in ruby net/http? - Stack Overflow

Cookieとセッションをちゃんと理解する - Qiita <- ちゃんと読んでない

WebサーバーからWebブラウザへHTTPレスポンスのヘッダを利用して小さな情報を送る。 この情報は「名前=値」の組み合わせで表される。
Webアプリケーション側では、リクエスト•ヘッダに入っているCookieを調べることで、アクセスしてきた相手がどのような相手なのかを知ることができる
Cookieは、サーバアクセスするたびに自動送信される http://www.htmq.com/webstorage/
Cookieを受け取ったあとでも、Cookieを受け取ったサーバとは異なるWebサーバに対しては>Cookieを送らない。(意図しない情報がほかのWebサーバーに送られるのを防ぐ) https://secure.php.net/manual/ja/features.cookies.php

cookie は 同じ名前のを遅れたり expire を設定したりと自力でやるのはつらい。というか、それ自力でつくたっら、ブラウザのサブセットを作っていることになって無為Rubyのnet/httpでGoogleにログイン - 瓶詰堂日記


mechanize, 自動化

Mechanize について - 君の瞳はまるでルビー - Ruby 関連まとめサイト
楽々スクレイピング! Ruby Mechanizeの使い方 -- ぺけみさお
Mechanize::Form - Ruby Mechanize wiki (ja)
Mechanizeの使い方(CookiesはRedisサーバへ保存) - 別館 子子子子子子(ねこのここねこ) <- pry で ls <obj> するとメソッド列挙してくれるのはじめって知ったけど、めちゃ便利そう
Webブラウザの自動操作 (Selenium with Rubyの実例集) - Qoosky


まとめ

時間だけかけて結局何もしてないやつやめたい