スナックelve 本店

バツイチ40代女の日記です

No.1214 完成ソース 突っ込み歓迎(2017.05.06 更新)

移動前ブクマページ: https://b.hatena.ne.jp/entry/s/elve.hateblo.jp/entry/2017/04/23/235454

結局RSSの読み込み解析とJSONの読み込み解析

RSSRSS1.0, RSS2.0読み込み処理 - ヴェナレス/ボンボの語りえぬ日記の1.0部分を
JSONneue cc - DynamicJson - C# 4.0のdynamicでスムーズにJSONを扱うライブラリ
を使わせていただきました。
ほかにも検索してコピペさせていただいたサイトがもう認識しきれていません。ほんとすみません。
ありがとうございます。

完成品

三日はてブ.exe - Google ドライブ(2017.05.06修正)

追記

二重起動禁止にした
通信できないときエラー吐いて死ぬの直した

そーっす

メイン画面

using System;
using System.Windows.Forms;
using System.Diagnostics;

namespace 三日はてブ
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            //ItemActivateイベントハンドラの追加
            listView1.ItemActivate += new EventHandler(listView1_ItemActivate);
        }
    

        private void Form1_Load(object sender, EventArgs e)
        {
            //初期設定
            textBox1.Text = Properties.Settings.Default.hatenaId;


        }
        private http_main htp;
        private BookMarks bookMarks;
        private xml_reader xmlReader;
        private async void button1_Click(object sender, EventArgs e)
        {
            
            //カーソルの待機状態をトグルで変更する
            Application.UseWaitCursor = !Application.UseWaitCursor;
            //待機中無効
            listView1.Enabled = false;
            button1.Enabled = false;
            
            //初期化
            htp = new http_main();
            bookMarks = new BookMarks();
            xmlReader = new xml_reader();
            listView1.Clear();

            //テキストボックス 空 空白のみ
            if (textBox1.Text.Trim() == "")
            {
                listView1.Enabled = true;
                button1.Enabled = true;

                //カーソルの待機状態をトグルで変更する
                Application.UseWaitCursor = !Application.UseWaitCursor;

                MessageBox.Show("何も入力されてないよ~");
                return;
            }
            try
            {

                //xml読み出し結果
                var xml = await htp.GetHatenaBookmarks(textBox1.Text.Trim());
                //解析
                var tmp = xmlReader.ReadBookmark(xml);
                //ブックマーク情報設定
                await bookMarks.SetBookmarkList(tmp);

                //カラムの設定(5列)
                listView1.Columns.Add("★", 36);
                listView1.Columns.Add("url");
                listView1.Columns.Add("タイトル");
                listView1.Columns.Add("日付");
                listView1.Columns.Add("ユーザー");
                listView1.Columns.Add("コメント");
                listView1_Resize((object)this.listView1, null);

                //ブックマーク数
                var c = bookMarks.GetItemsCount();

                //リスト項目の設定
                for (var i = 0; i < c; i++)
                {
                    //取得
                    string[] row_1 = bookMarks.OutputRow(i);
                    //画像のインデックス取得
                    var index = row_1[0];
                    row_1[0] = "";
                    //設定
                    var line = listView1.Items.Add(new ListViewItem(row_1));
                    listView1.Items[i].ImageIndex = int.Parse(index);

                }

                //ボタン有効
                listView1.Enabled = true;
                button1.Enabled = true;


                MessageBox.Show(c + "件 解析終了!");

                //検索ボタンにフォーカス
                button1.Focus();

                //カーソルの待機状態をトグルで変更する
                Application.UseWaitCursor = !Application.UseWaitCursor;
            }
            catch
            {
                //ボタン有効
                listView1.Enabled = true;
                button1.Enabled = true;


                //検索ボタンにフォーカス
                button1.Focus();

                //カーソルの待機状態をトグルで変更する
                Application.UseWaitCursor = !Application.UseWaitCursor;
                MessageBox.Show("通信できなかった(´・ω・`)");
            }

        }

        private void listView1_Resize(object sender, EventArgs e)
        {
            //リサイズしたら★の列はそのままで他を等分で表示

            ListView f = (ListView)sender;
            //リストビューの内側の幅
            var w = f.ClientRectangle.Width;
            //カラムの設定(6列)
            if (listView1.Columns.Count == 6)
            {
                listView1.Columns[1].Width = (int)((w - 36) / 5);
                listView1.Columns[2].Width = (int)((w - 36) / 5);
                listView1.Columns[3].Width = (int)((w - 36) / 5);
                listView1.Columns[4].Width = (int)((w - 36) / 5);
                listView1.Columns[5].Width = (int)((w - 36) / 5);
            }

        }
        private void listView1_ItemActivate(object sender, EventArgs e)
        {
            //項目が1つも選択されていない場合
            if (listView1.SelectedItems.Count == 0)
                //処理を抜ける
                return;

            ListViewItem itemx = new ListViewItem();

            //1番目に選択されれいるアイテムをitemxに格納
            itemx = listView1.SelectedItems[0];

            //リンクを開く
            string url = itemx.SubItems[1].Text;
            url = url.Replace("http://", "");
            url = url.Replace("https://", "s/");
            //url= Uri.EscapeDataString(url);
            System.Diagnostics.Process.Start("http://b.hatena.ne.jp/entry/" + url);

        }

        private void button2_Click(object sender, EventArgs e)
        {
            //ID設定画面表示
            Form2 f = new Form2();
            this.Visible = false;

            f.ShowDialog(this);

            //終わったらフォーム1表示
            this.Visible = true;

            //フォームが必要なくなったところで、Disposeを呼び出す
            f.Dispose();

            //テキストボックスにID表示
            textBox1.Text = Properties.Settings.Default.hatenaId;

            //検索ボタンにフォーカス
            button1.Focus();

        }
    }
}

通信管理

using System;
using System.Threading.Tasks;
using System.Net.Http;

namespace 三日はてブ
{
    class http_main
    {
        public async Task<string> GetHatenaStar(DateTime time,double eid,string user)
        {
            //エントリーのブクマに対するスター情報
            var client = new HttpClient();
            //ブラウザ情報設定
            client.DefaultRequestHeaders.Add("User-Agent", "MikkaHatebu");

            //URL作成
            var url = "http://b.hatena.ne.jp/" + user + "/";
            url = url + time.ToString("yyyyMMdd") + "#bookmark-" + eid;
            url = Uri.EscapeDataString(url);

            //はてなスター情報取得
            var json = await client.GetStringAsync("http://s.hatena.com/entry.json?uri=" + url);
            return json;
        }
        public async Task<string> GetHatenaBookmarks(string str)
        {
            //新着はてなブックマークから検索結果取得
            var client = new HttpClient();
            
            //ブラウザ情報設定
            client.DefaultRequestHeaders.Add("User-Agent", "MikkaHatebu");
            
            //ブクマ検索結果取得
            str = Uri.EscapeDataString(str);
            var xml = await client.GetStringAsync("http://b.hatena.ne.jp/search/text?safe=off&q=" + str + "&users=1&mode=rss");
            return xml;
        }
        public async Task<string> GetHatenaBookmarksInfo(string url)
        {
            //エントリのブックマーク情報取得
            var client = new HttpClient();
            
            //ブラウザ情報設定
            client.DefaultRequestHeaders.Add("User-Agent", "MikkaHatebu");
            
            //ブクマ情報取得
            var u = Uri.EscapeDataString(url);
            var json = await client.GetStringAsync("http://b.hatena.ne.jp/entry/jsonlite/?url=" + u);
            return json;
        }
    }
}

xml解析

using System;
using System.Xml;
using System.Collections.Generic;

namespace 三日はてブ
{
    public class xml_reader
    {


        public RssInfo rssInfo;
        public  xml_reader()
        {
            rssInfo =new RssInfo();
        }
        public RssInfo ReadBookmark(string xml)
        {
            XmlDocument document = new XmlDocument();

            // ファイルから読み込む
            document.LoadXml(xml);
            rssInfo = Getresults(document);
            return rssInfo;
        }
        ///     RSS1.0のXMLを解析し、RssInfoオブジェクトで返却する。
        private RssInfo Getresults(XmlDocument xmlDoc)
        {

            List<RssItem> ret = new List<RssItem>();
            //RSS XMLNS マネージャ設定
            XmlNamespaceManager nsmgr = new XmlNamespaceManager(xmlDoc.NameTable);
            nsmgr.AddNamespace("rss", "http://purl.org/rss/1.0/");
            nsmgr.AddNamespace("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
            nsmgr.AddNamespace("dc", "http://purl.org/dc/elements/1.1/");

            //rdf:li コレクション作成
            XmlNodeList linodes = xmlDoc.SelectNodes("/rdf:RDF/rss:channel/rss:items/rdf:Seq/rdf:li", nsmgr);

            //items取得
            foreach (XmlNode node in linodes)
            {
                //resource属性がマッチするitemノード取得
                string strResource = node.Attributes["resource", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"].Value;

                XmlNode aboutItem = xmlDoc.SelectSingleNode("/rdf:RDF/rss:item[@rdf:about='" + strResource + "']", nsmgr);

                //item 項目取得
                if (aboutItem != null)
                {
                    XmlNode titleNode = aboutItem.SelectSingleNode("rss:title", nsmgr);
                    XmlNode linkUrkNode = aboutItem.SelectSingleNode("rss:link", nsmgr);
                    XmlNode dateNode = aboutItem.SelectSingleNode("dc:date", nsmgr);

                    string title = string.Empty;
                    string link = string.Empty;
                    string date = string.Empty;

                    if (titleNode != null)
                    {
                        title = titleNode.InnerText;
                    }
                    if (linkUrkNode != null)
                    {
                        link = linkUrkNode.InnerText;
                    }
                    if (dateNode != null)
                    {
                        date = dateNode.InnerText;
                    }
                    RssItem rssItem = new RssItem();
                    rssItem.Title = title;
                    rssItem.Date = stringToDateTime(date);
                    rssItem.Link = new Uri(link);
                    ret.Add(rssItem);
                }
            }
            rssInfo.items = ret.ToArray();
            rssInfo.itemCount = ret.Count;
            rssInfo.Title = xmlDoc.SelectSingleNode("/rdf:RDF/rss:channel/rss:title", nsmgr).InnerText;
            return rssInfo;
        }

        /// <summary>
        ///     string型の日付文字列からDateTimeオブジェクトを生成する。
        /// </summary>
        /// <param name="datestr"></param>
        /// <returns></returns>
        private static DateTime stringToDateTime(string datestr)
        {
            char[] sep = new char[2];
            sep[0] = 'T';
            sep[1] = '+';
            string newdatestr = datestr.Split(sep)[0].Replace('-', '/');
            string newtimestr = datestr.Split(sep)[1];
            return Convert.ToDateTime(newdatestr + " " + newtimestr);
        }
    }
}

ブックマーク情報管理

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Codeplex.Data;
using System.Windows.Forms;

namespace 三日はてブ
{
    class BookMarks
    {
        //ブックマーク情報リスト
        public List<BookMarkLists> myBkm;

        public async Task<int> GetImgIndex(DateTime tmpdate, double eid,string user)
        {
            //登録IDでスターをつけていたら1
            //つけていなかったら0を返す

            //通信用
            var htn = new http_main();
            //はてなスター情報取得
            var testjson2 = await htn.GetHatenaStar(tmpdate, eid, user);

            //登録はてなIDでスターをつけたかチェック
            var json2 = DynamicJson.Parse(testjson2.ToString());
            var id = Properties.Settings.Default.hatenaId;
            foreach (var ent in json2.entries)
            {
                foreach (var st in ent.stars)
                {
                    if (id == st.name)
                    {
                        return 1;
                    }
                }
                
            }
            return 0;

        }

        //xmlの解析結果をもらってそれぞれのエントリのブックマーク情報を取得する
        public async Task SetBookmarkList(RssInfo rssInfo)
        {
            //xmlの解析結果がない
            if (rssInfo == null) {
                MessageBox.Show("情報解析に失敗しました。もう一度検索してみてください。");
                return;
            }
            //通信用
            var htn = new http_main();
            //結果を入れるリスト
            myBkm = new List<BookMarkLists>();
            //見つかったサイトの数だけループ
            for (var i = 0; i < rssInfo.itemCount; i++)
            {
                //そのサイトのブックマーク情報取得
                var testjaon = await htn.GetHatenaBookmarksInfo(rssInfo.items[i].Link.ToString());
                //ブックマーク情報解析
                var json = DynamicJson.Parse(testjaon.ToString());
                if (json != null)
                {
                    //ブクマ情報が空じゃなかったら
                    foreach (var bookmarks in json.bookmarks)
                    {
                        //ブクマした時間文字からタイムスタンプ
                        var t = bookmarks.timestamp;
                        var tmpdate = DateTime.Parse(t);
                        //3日以内にブクマしたモノならリストに追加
                        if (tmpdate > DateTime.Today.AddDays(-3))
                        {
                            var item = new BookMarkLists();
                            //ブクマurl
                            item.bkmUrl = json.url;
                            //ブクマしたユーザー
                            item.bkmUser = bookmarks.user;
                            //ブクマした日時
                            item.timestmp = tmpdate;
                            //ブクマしたサイトのタイトル
                            item.bkmTitle = json.title;
                            //ブクマコメント
                            item.bkmComment = bookmarks.comment;
                            //                            item.imgIndex = json.eid;
                            if (Properties.Settings.Default.hatenaId != "")
                            {
                                //はてなIDが登録されていたらスター情報取得
                                item.imgIndex = await GetImgIndex(tmpdate, json.eid, bookmarks.user);

                            }
                            myBkm.Add(item);

                        }
                    }

                }
            }
            myBkm.Sort((x, y) => y.timestmp.CompareTo(x.timestmp));

        }
        public int GetItemsCount()
        {
            //ブクマの数を返す
            if (myBkm == null) return 0;
            return myBkm.Count;
        }
        public string[] OutputRow(int i)
        {
            //listview 1行分の文字列配列
            string[] tmp = { myBkm[i].imgIndex.ToString(), myBkm[i].bkmUrl, myBkm[i].bkmTitle, myBkm[i].timestmp.ToString(), myBkm[i].bkmUser, myBkm[i].bkmComment };
            return tmp;
        }
    }
}

構造体的クラス

using System;
namespace 三日はてブ
{
    public class BookMarkLists
    {
        public Double imgIndex { get; set; } 
        public string bkmUser { get; set; }
        public DateTime timestmp { get; set; }
        public string bkmUrl { get; set; }
        public string bkmTitle { get; set; }
        public string bkmComment { get; set; }
    }
    public class RssInfo
    {

        /// <summary>
        ///     RSSタイトル
        /// </summary>
        private string title;

        /// <summary>
        ///     URI
        /// </summary>
        private Uri rssUrl;

        /// <summary>
        ///     RssItem配列
        /// </summary>
        public RssItem[] items;
        public int itemCount { get; set; }

        /// <summary>
        ///     RSSタイトルプロパティ
        /// </summary>
        public string Title
        {
            set
            {
                this.title = value;
            }
            get
            {
                return this.title;
            }
        }

    }
    public class RssItem
    {
        /// <summary>
        ///     RSSの日付
        /// </summary>
        private DateTime date;

        /// <summary>
        ///     RSSのニュースタイトル
        /// </summary>
        private string title;

        /// <summary>
        ///     RSSのリンク
        /// </summary>
        private Uri link;

        /// <summary>
        ///     Dateプロパティ
        /// </summary>
        public DateTime Date
        {
            set
            {
                this.date = value;
            }
            get
            {
                return this.date;
            }
        }

        /// <summary>
        ///     Titleプロパティ
        /// </summary>
        public string Title
        {
            set
            {
                this.title = value;
            }
            get
            {
                return this.title;
            }
        }

        /// <summary>
        ///     Linkプロパティ
        /// </summary>
        public Uri Link
        {
            set
            {
                this.link = value;
            }
            get
            {
                return this.link;
            }
        }
    }
}