#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/
※ああ、リンク先の権利上の問題は現状ありません。だって自分の書いた三文小説ですもの(汗)