Xpathでスクレイピング : .NET

#ref(): File not found: "c-sharp-sc.jpg" at page "(wpf)Xpathでスクレイピング"

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

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

処理本体

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

なろうサイトの小説本文は、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;
           }
       }

ちょっと解説

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) ..
今回は単に結果をかき集めてるだけね。

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

参考データ

XAML

<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

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);
           }
       }
   }
}

参考ページ

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


トップ   編集 凍結解除 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-02-12 (金) 09:39:46