#freeze
[[Xpathでスクレイピング]] : [[.NET]]

#ref(c-sharp-sc.jpg)

[[Xpathでスクレイピング]]の記事はForm用だから、WPFと組み合わせてみたわ。

とりこみデータサンプルには、投稿小説サイト『小説家になろう』のページを使ってみたわ。実はここのユーザーで投稿者だっていうのもあるんだけど、実は ''ここの小説本文は、divの特定クラスでXpathを書くと簡単に本文が得られる'' のよね。


* 処理本体 [#d7bd8904]

入力は、取り込んだHTMLソースね。詳しくは[[こっち>WpfでWebBrowserを使ってみた]]を見てくれるかしら?ここの末尾にも全ソースを書いておくけど。

なろうサイトの小説本文は、class="novel_view" つきの divで囲まれているの。だからXpathの書き方は「 //div[@class='novel_view'] 」でいいってわけ。ね、テキスト的に簡単でしょう?

        private void getXpathProc(string x)
        {
            HtmlAgilityPack.HtmlDocument html = new HtmlAgilityPack.HtmlDocument();
            html.LoadHtml(x);
            var articles = html.DocumentNode.SelectNodes(@"//div[@class='novel_view']")
                .Select(a => new {
                    Html = a.InnerHtml
                });
            tb3.Text = "";
            foreach (var a in articles)
            {
                string kg = "\r\n";
                string x1 = a.Html + kg;
                tb3.Text += x1;
            }
        }

** ちょっと解説 [#bdf89f84]

: HtmlAgilityPack.HtmlDocument html = new HtmlAgilityPack.HtmlDocument() | まず、htmlって名前でオブジェクトを作る。

: html.LoadHtml(x) | データロードする。入力はHTMLソーステキスト。

: var articles ... | articlesって名前でデータ塊を作る。中身は divのInnerHtml、つまりHTMLソース。(SelectNodesとSelectの使い方がミソ。Xpathをあてはめ、抜き出したデータを塊として配列のようにしてるってわけね)

: foreach (var a in articles) .. | 今回は単に結果をかき集めてるだけね。

以下には、参考にプログラム全文を入れておくわね。

* 参考データ [#a9bfacab]

** XAML [#z26daa88]

 <Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApplication1"
        mc:Ignorable="d"
        Title="MainWindow" Height="800" Width="800" WindowStyle="ThreeDBorderWindow">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="25" />
            <RowDefinition Height="250" />
            <RowDefinition Height="200" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="25" />
            </Grid.ColumnDefinitions>
            <TextBox Name="tb1" Grid.Column="0" />
            <Button Name="b1" Content="GO" Grid.Column="1" Click="b1_Click" />
        </Grid>
        <WebBrowser Name="web1" Grid.Row="1" LoadCompleted="web1_LoadCompleted" />
        <TextBox Name="tb2" Grid.Row="2" VerticalScrollBarVisibility="Visible" TextWrapping="Wrap" />
        <TextBox Name="tb3" Grid.Row="3" VerticalScrollBarVisibility="Visible" TextWrapping="Wrap" />
    </Grid>
 </Window>

** MainWindow.xaml.cs [#ca37e233]

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 using System.Reflection;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Documents;
 using System.Windows.Input;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
 
 namespace WpfApplication1
 {
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            webinit();
        }
 
        private void webinit()
        {
            // IWebBrowser2 の取得 プロパティから
            var axIWebBrowser2 = typeof(WebBrowser).GetProperty("AxIWebBrowser2", BindingFlags.Instance | BindingFlags.NonPublic);
            var comObj = axIWebBrowser2.GetValue(web1, null);

            // 値の設定
            comObj.GetType()
                  .InvokeMember
                  (
                     "Silent",
                     BindingFlags.SetProperty,
                     null,
                     comObj,
                    new object[] { true }
                  );
        }
 
        private void web1_LoadCompleted(object sender, NavigationEventArgs e)
        {
            this.Title = ((dynamic)web1.Document).Title;
            tb2.Text = ((dynamic)web1.Document).documentElement.InnerHtml;
            getXpathProc(tb2.Text);
        }
 
        private void getXpathProc(string x)
        {
            HtmlAgilityPack.HtmlDocument html = new HtmlAgilityPack.HtmlDocument();
            //html.LoadHtml(((dynamic)web1.Document).Body.InnerHtml);
            html.LoadHtml(x);
            var articles = html.DocumentNode.SelectNodes(@"//div[@class='novel_view']")
                .Select(a => new {
                    Html = a.InnerHtml
                });
            tb3.Text = "";
            foreach (var a in articles)
            {
                string kg = "\r\n";
                string x1 = a.Html + kg;
                tb3.Text += x1;
            }
        }
 
        /// <summary>
        /// Web Access
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void b1_Click(object sender, RoutedEventArgs e)
        {
            if (Regex.IsMatch(tb1.Text, @"^http", RegexOptions.IgnoreCase) == true)
            {
                web1.Navigate(tb1.Text);
            }
        }
    }
 }


* 参考ページ [#e24a3b14]

- [[サンプルにしたのはここです>http://ncode.syosetu.com/n3170ch/104/]] http://ncode.syosetu.com/n3170ch/104/

※ああ、リンク先の権利上の問題は現状ありません。だって自分の書いた三文小説ですもの(汗)

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS