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行目&lt;br /&gt;2行目&lt;br /&gt;\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();
                
                //

            
            }
        }
    }
}