CookieGetterSharp.dllを使ってニコニコ生放送の枠取りを半自動化してみた
まず、halxxxxさんの、CookieGetterSharp.dll + SourceCode + SampleCodeを
http://d.hatena.ne.jp/halxxxx/20091212/1260649353
から取得します。
これを利用するにあたっては、私は、解凍したものを自プロジェクトのディレクトリ配下に置いて参照設定しました。解凍すればそのまま、
CookieGetterSharp.dll
CookieGetterSharp.xml
System.Data.SQLite.DLL
が同じディレクトリに置かれているので。。
VC#のIDEで自プロジェクトを作成後、「プロジェクト」->「参照の追加」で、CookieGetterSharp.dllへの参照を追加して利用しました。
あとSgmlReaderDll.dllという別のライブラリも利用させてもらったのですが、ググればわかると思うので、足りなそうだったら後日補足します(というか覚えてない)。。
以下ソース
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Web; // form post using Hal.CookieGetterSharp; // cookie get using System.Net; // cookie using System.Xml; // xml using System.Xml.Linq; // linq namespace NicoWaku { public partial class Form1 : Form { string editstreamurl = "http://live.nicovideo.jp/editstream"; System.Text.Encoding enc = System.Text.Encoding.GetEncoding("utf-8"); //Encoding.UTF8 string boundary = System.Environment.TickCount.ToString(); // 区切り文字 public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { //ICookieGetter cookieGetter = CookieGetter.CreateInstance(BrowserType.Firefox3); //System.Net.CookieCollection collection = cookieGetter.GetCookieCollection(new Uri("http://live.nicovideo.jp/")); //System.Net.Cookie userSession = collection["user_session"]; BrowserType type; type = BrowserType.IE; ICookieGetter cookieGetter = CookieGetter.CreateInstance(type); Uri uri; if (cookieGetter.Status.IsAvailable && Uri.TryCreate("http://live.nicovideo.jp/", UriKind.Absolute, out uri)) { System.Net.Cookie cookie; try { cookie = cookieGetter.GetCookie(uri, "user_session"); } catch (Hal.CookieGetterSharp.CookieGetterException) { //MessageBox.Show(ex.Message); //label7.Text = "取得失敗!エラーが発生しました。"; Console.WriteLine("取得失敗!エラーが発生しました。"); return; } Console.WriteLine(cookie.Name); Console.WriteLine(cookie.Value); //ここ以降から、 http://live.nicovideo.jp/editstream にプログラムでアクセスして、 //枠をとりたい //リクエストを投げる // <form action="editstream" method="post" accept-charset="UTF-8" enctype="multipart/form-data" onSubmit="return disableButtons(event);" id="esf"> // http://live.nicovideo.jp/editstream //System.Net.CookieCollection ccollection = new CookieCollection(); //ccollection.Add(cookie); System.Net.CookieContainer cc = new CookieContainer(); cc.Add(cookie); System.Net.HttpWebRequest req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(editstreamurl); req.Method = "POST"; req.ContentType = "multipart/form-data; boundary=" + boundary; req.CookieContainer = cc; string postData = "", postDataStep2 = "", postDataStep1 = "", postDataStep2b = ""; //StringBuilder sb = new StringBuilder(); postData = "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"is_wait\"\r\n\r\n" + "\r\n" + "--" + boundary + "\r\n" + ""; postDataStep1 = "" + "Content-Disposition: form-data; name=\"usecoupon\"\r\n\r\n" + "\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"title\"\r\n\r\n" + "【プログラミングで】VC#の舞【取りました】 \r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"description\"\r\n\r\n" + "詳細1行目<br />2行目<br />\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"default_community\"\r\n\r\n" + "co378536\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"tags[]\"\r\n\r\n" + "一般(その他)\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"livetags1\"\r\n\r\n" + "雑談\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"taglock1\"\r\n\r\n" + "ロックする\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"livetags2\"\r\n\r\n" + "雑談2\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"taglock2\"\r\n\r\n" + "ロックする\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"livetags3\"\r\n\r\n" + "雑談3\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"taglock3\"\r\n\r\n" + "ロックする\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"livetags4\"\r\n\r\n" + "雑談4\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"taglock4\"\r\n\r\n" + "ロックする\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"livetags5\"\r\n\r\n" + "雑談5\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"taglock5\"\r\n\r\n" + "ロックする\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"livetags6\"\r\n\r\n" + "雑談6\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"taglock6\"\r\n\r\n" + "ロックする\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"livetags7\"\r\n\r\n" + "雑談7\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"taglock7\"\r\n\r\n" + "ロックする\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"livetags8\"\r\n\r\n" + "雑談8\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"taglock8\"\r\n\r\n" + "ロックする\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"livetags9\"\r\n\r\n" + "雑談9\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"taglock9\"\r\n\r\n" + "ロックする\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"livetags10\"\r\n\r\n" + "雑談10\r\n" + "--" + boundary + "\r\n" + //"Content-Disposition: form-data; name=\"taglock10\"\r\n\r\n" + //"ロックする\r\n" + //"--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"all_remain_point\"\r\n\r\n" + "off\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"reserve_start_ymd\"\r\n\r\n" + "off\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"reserve_start_h\"\r\n\r\n" + "off\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"reserve_start_i\"\r\n\r\n" + "off\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"reserve_stream_time\"\r\n\r\n" + "off\r\n" + "--" + boundary + "\r\n" + //"Content-Disposition: form-data; name=\"face\"\r\n\r\n" + //"off\r\n" + //"--" + boundary + "\r\n" + //"Content-Disposition: form-data; name=\"totue\"\r\n\r\n" + //"off\r\n" + //"--" + boundary + "\r\n" + //"Content-Disposition: form-data; name=\"reserved\"\r\n\r\n" + //"\r\n" + //"--" + boundary + "\r\n" + //"Content-Disposition: form-data; name=\"community_only\"\r\n\r\n" + //"\r\n" + //"--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"timeshift_enabled\"\r\n\r\n" + "1\r\n" + "--" + boundary + "\r\n" + //"name=\"timeshift_disabled\"\r\n\r\n" + //"\r\n" + //"--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"twitter_disabled\"\r\n\r\n" + "0\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"input_twitter_tag\"\r\n\r\n" + "\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"twitter_tag\"\r\n\r\n" + //"#co378536\r\n" + "\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"ad_enable\"\r\n\r\n" + "0\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"rights[0][code]\"\r\n\r\n" + "0\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"rights[0][title]\"\r\n\r\n" + "0\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"rights[0][artist]\"\r\n\r\n" + "0\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"rights[0][lyric]\"\r\n\r\n" + "0\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"rights[0][composer]\"\r\n\r\n" + "0\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"rights[0][time]\"\r\n\r\n" + "0\r\n" + "--" + boundary + "\r\n" + ""; postDataStep2b = "" + "Content-Disposition: form-data; name=\"public_status\"\r\n\r\n" + "0\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"kiyaku\"\r\n\r\n" + "true\r\n" + "--" + boundary + "\r\n" + ""; Console.WriteLine(postData + postDataStep1); byte[] startData = enc.GetBytes(postData + postDataStep1); string postDataStep0 = "\r\n--" + boundary + "--\r\n"; byte[] endData = enc.GetBytes(postDataStep0); System.IO.Stream reqStream = req.GetRequestStream(); reqStream.Write(startData, 0, startData.Length); reqStream.Write(endData, 0, endData.Length); reqStream.Close(); System.Net.HttpWebResponse res = (System.Net.HttpWebResponse)req.GetResponse(); System.IO.Stream resStream = res.GetResponseStream(); //System.IO.StreamReader sr = new System.IO.StreamReader(resStream, enc); //Console.WriteLine(sr.ReadToEnd()); //sr.Close(); try { //XDocument xml; using (var sgmlReader = new Sgml.SgmlReader { DocType = "HTML", CaseFolding = Sgml.CaseFolding.ToLower }) { System.IO.StreamReader sr = new System.IO.StreamReader(resStream, enc); sgmlReader.InputStream = sr; var xml = XDocument.Load(sgmlReader); //XNamespace ns = "http://www.w3.org/1999/xhtml"; //var ns = //XNamespace ns = "http://www.w3.org/1999/xhtml"; XNamespace ns = xml.Root.Name.Namespace; var query = xml.Descendants(ns + "input") .Where(el => el.Attribute("name") != null && el.Attribute("name").Value == "confirm") .Select(es => new { Value = es.Attribute("value") }); foreach (var item in query) { Console.WriteLine(item.Value.Value); // response から linqを検索した結果のタイトルを列挙 postDataStep2 = "" + //Content-Disposition: form-data; name="confirm" //ulck_759107906 //-----------------------------7db5d34804e4 //Content-Disposition: form-data; name="back" //false "Content-Disposition: form-data; name=\"confirm\"\r\n\r\n" + //"\r\n" + //"ulck_759107906--" + boundary + "\r\n" + item.Value.Value + "\r\n" + "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"back\"\r\n\r\n" + "false\r\n" + "--" + boundary + "\r\n" + //"Content-Disposition: form-data; name=\"back\"\r\n\r\n" + //"\r\n" + //"false--" + boundary + "\r\n" + ""; } //foreach (var item in xml.Descendants(ns + "input")) //{ // Console.WriteLine(item.Value); // response から linqを検索した結果のタイトルを列挙 //} } } catch (Exception ex) { Console.WriteLine(ex.ToString()); throw ; } try { //HtmlDocument hdoc = new HtmlDocument(); // XMLのオープン、データ読み込み /* XmlDocument doc = new XmlDocument(); doc.Load(resStream); Console.WriteLine(doc.ToString()); XmlElement root = doc.DocumentElement; // <input type="hidden" name="confirm" value="ulck_292405270"> // //a[@href='help.php'] XmlNodeList nodeList = root.SelectNodes("//input[@name='confirm']/@value"); // XPath式 Console.WriteLine(nodeList.Count); Console.WriteLine(nodeList.ToString()); // 最初に見つけたノードの内容を取得して返します。 foreach (XmlNode nd in nodeList) { if (nd.InnerXml != "") { postDataStep2 = "" + //Content-Disposition: form-data; name="confirm" //ulck_759107906 //-----------------------------7db5d34804e4 //Content-Disposition: form-data; name="back" //false "Content-Disposition: form-data; name=\"confirm\"\r\n\r\n" + "\r\n" + //"ulck_759107906--" + boundary + "\r\n" + nd.InnerText + boundary + "\r\n" + "Content-Disposition: form-data; name=\"back\"\r\n\r\n" + "\r\n" + "false--" + boundary + "\r\n" + ""; //return nd.InnerXml; } }*/ } catch (Exception excp) { Console.WriteLine(excp.ToString()); } //Console.WriteLine(postData + postDataStep2 + postDataStep1 + postDataStep2b); // startData = enc.GetBytes(postData + postDataStep2 + postDataStep1 + postDataStep2b); //string postDataStep0 = "\r\n--" + boundary + "--\r\n"; //byte[] endData = enc.GetBytes(postDataStep0); req = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(editstreamurl); req.Method = "POST"; req.ContentType = "multipart/form-data; boundary=" + boundary; req.CookieContainer = cc; reqStream = req.GetRequestStream(); reqStream.Write(startData, 0, startData.Length); reqStream.Write(endData, 0, endData.Length); reqStream.Close(); res = (System.Net.HttpWebResponse)req.GetResponse(); resStream = res.GetResponseStream(); //System.IO.StreamReader sr = new System.IO.StreamReader(resStream, enc); //Console.WriteLine(sr.ReadToEnd()); //sr.Close(); // } } } }