- unibon
- ぬし
- 会議室デビュー日: 2002/08/22
- 投稿数: 1532
- お住まい・勤務地: 美人谷 良回答(20pt)
|
投稿日時: 2008-05-31 12:37
私は以前から WebBrowser コントロールを使って、Webの自動巡回ツールのようなアプリケーションを開発しています。
たとえば、
http://www.atmarkit.co.jp/fdotnet/dotnettips/687nondispbrowser/nondispbrowser.html
のような感じで WebBrowser と HtmlDocument を使って HTML を解析できています。
今回、軽さを求めて WebClient クラスも使いたいと思って、
http://www.atmarkit.co.jp/fdotnet/dotnettips/302wcget/wcget.html
などを参考にして HTML を取得することはできたのですが、取得した HTML を解析する方法が分かりません。文字列を IndexOf や Regex で解析することはできるのですが、できれば WebBrowser で HtmlDocument が使えたように、WebClient でも HtmlDocument を使いたいのですが、どうすればできるでしょうか?
ちなみに、試行錯誤して、つぎのようなやりかたはできたのですが、WebBrowser を使っているので、根本的な解決にはなっていません。
コード: |
|
using System;
using System.IO;
using System.Net;
using System.Windows.Forms;
using System.Text;
namespace Hoge
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
WebClient wc = new WebClient();
Stream st = wc.OpenRead("http://www.example.com/");
Encoding enc = Encoding.GetEncoding("Shift_JIS");
StreamReader sr = new StreamReader(st, enc);
string html = sr.ReadToEnd();
sr.Close();
st.Close();
WebBrowser wb = new WebBrowser();
wb.Navigate("about:blank"); // 良く分からん。
HtmlDocument hd = wb.Document;
hd.OpenNew(false); // 良く分からん。
hd.Write(html);
// たとえばリンク(a href)を抽出する。
foreach (HtmlElement link in hd.Links)
{
Console.WriteLine(link.GetAttribute("href"));
}
}
}
}
|
|
- ちゃっぴ
- ぬし
- 会議室デビュー日: 2004/12/10
- 投稿数: 873
|
投稿日時: 2008-05-31 13:16
HtmlDocument って確か COM MSHTML の wrapper じゃなかったかな?
だとすると、body porperty に放り込んでごにょごにょすればいけるんじゃないでしょうか?
たしかに DOM 使って parse できたら便利だと思うんですが、MSHTML って ActiveX とか JavaScript とかが browser の設定にしたがって利用されちゃうのがいまいちなんですよね。個別に on, off できる property あればいいのに。。。
|
- unibon
- ぬし
- 会議室デビュー日: 2002/08/22
- 投稿数: 1532
- お住まい・勤務地: 美人谷 良回答(20pt)
|
投稿日時: 2008-05-31 20:06
引用: |
|
ちゃっぴさんの書き込み (2008-05-31 13:16) より:
HtmlDocument って確か COM MSHTML の wrapper じゃなかったかな?
だとすると、body porperty に放り込んでごにょごにょすればいけるんじゃないでしょうか?
|
ありがとうございます。
たしかにそんな感じでごにょごにょしたいのですが、たとえば、MSHTML.TLB を参照設定して、
コード: |
|
private void button1_Click(object sender, EventArgs e)
{
WebBrowser wb = new WebBrowser();
HtmlDocument hd = wb.Document;
hd.Body = null; // とりあえず null を set してみたいが、ここでコンパイルエラーになる。
mshtml.HTMLDocument mshtmlHd = (mshtml.HTMLDocument)hd.DomDocument;
mshtmlHd.body = null; // とりあえず null を set してみたいが、ここでコンパイルエラーになる。
}
|
のようなことをしようとしても、System.Windows.Forms.HtmlDocument クラスの Body プロパティーも、mshtml.HTMLDocument クラスの body プロパティーも、読み取り専用なので、この時点でもう行き詰ってしまっています。ほかにもなにか面白そうなプロパティーがあっても「読み取り専用」ということが多く、どうも外からいじることが難しそうに感じます。
しかし、System.Windows.Forms.HtmlDocument クラスは new できませんが、mshtml.HTMLDocument クラスは new できますね。
|
- Hongliang
- ぬし
- 会議室デビュー日: 2004/12/25
- 投稿数: 576
|
投稿日時: 2008-05-31 22:01
HTMLDocument(ちなみにこれ new できるけど interface)のインスタンスを作って、write を呼び出す(IHTMLDocument2 にキャストしないと駄目だったかな)ことで任意の html を読み込ませることが可能です。
HtmlDocument の方が欲しいなら internal なコンストラクタをリフレクションで呼び出すことになります(第一引数は null で良い模様)。internal なんで動作の保証はできませんが。
|
- unibon
- ぬし
- 会議室デビュー日: 2002/08/22
- 投稿数: 1532
- お住まい・勤務地: 美人谷 良回答(20pt)
|
投稿日時: 2008-06-03 20:50
引用: |
|
Hongliangさんの書き込み (2008-05-31 22:01) より:
HTMLDocument(ちなみにこれ new できるけど interface)のインスタンスを作って、write を呼び出す(IHTMLDocument2 にキャストしないと駄目だったかな)ことで任意の html を読み込ませることが可能です。
|
ありがとうございます。
遅くなりましたが、教えていただいたやりかたそのままでできました。
以下、リンク(a href)を抽出する例のコードです。
「参照の追加」で COM の MSHTML.TLB を追加しています。
なお、インスタンスの解放などが要るのかもしれませんが、今のところ省いています。
コード: |
|
using System;
using System.Windows.Forms;
namespace Hoge
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string html = "<html><body><a href='http://www.example.com/'>example</a></body></html>";
mshtml.HTMLDocument hd = new mshtml.HTMLDocument();
mshtml.IHTMLDocument2 ihd2 = (mshtml.IHTMLDocument2)hd;
// hd.write(new object[] { html }); // これだと COMException (-2147352571(== 0x80020005)) が起こる。
ihd2.write(new object[] { html });
foreach (mshtml.IHTMLElement link in hd.links)
{
Console.WriteLine((string)link.getAttribute("href", 0));
}
}
}
}
|
引用: |
|
Hongliangさんの書き込み (2008-05-31 22:01) より:
HtmlDocument の方が欲しいなら internal なコンストラクタをリフレクションで呼び出すことになります(第一引数は null で良い模様)。internal なんで動作の保証はできませんが。
|
できれば WebBrowser コントロールと WebClient 等を併用したいので、こっちのやりかた(小文字の HtmlDocument のやりかた)にしたいのですが、難しそうで分かりません。
(私としては、HTMLDocument(mshtml の大文字のほう)で、今のところやりたいことはできそうなので、ここで完了を報告させていただきます。)
|
- burton999
- ぬし
- 会議室デビュー日: 2003/10/06
- 投稿数: 898
- お住まい・勤務地: 東京
|
投稿日時: 2008-06-04 11:11
私も以前、WebClientで取得したhtmlをDOMで解析したくて悩んだ結果
以下のライブラリを使用しました。参考までに。
Html Agility Pack - Home
http://www.codeplex.com/htmlagilitypack
|