HTMLParserを使ってみる(CyberNekoHTML)*1
URLを指定してHTMLを読み込みドキュメントツリーを見るテスト
package jp.seraphyware.htmlparsertest; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import org.cyberneko.html.parsers.DOMParser; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; public class NekoHTMLTest { public static void main(final String[] args) throws Exception { final URL url = new URL("http://java.sun.com/"); final URLConnection urlConnection = url.openConnection(); final DOMParser parser = new DOMParser(); final InputStream is = urlConnection.getInputStream(); try { parser.parse(new InputSource(is)); } finally { is.close(); } final Document doc = parser.getDocument(); final Element root = doc.getDocumentElement(); walkTree("", root); } private static void walkTree(final String level, final Element elm) throws Exception { System.out.println(level + "<" + elm.getTagName() + ">"); final NodeList children = elm.getChildNodes(); if (children != null) { final int len = children.getLength(); for (int idx = 0; idx < len; idx++) { final Node child = (Node) children.item(idx); if (child.getNodeType() == Node.ELEMENT_NODE) { walkTree(level + " ", (Element) child); } else if (child.getNodeType() == Node.TEXT_NODE) { final String txt = child.getNodeValue(); if (txt.trim().length() > 0) { System.out.println(level + txt); } } } } } }
HTMLParserを使ってみる(HTMLParser)*2
用意するもの
- HTML Parser
- htmllexer.jar
- htmlparser.jar
URLを指定してHTMLを読み込みドキュメントツリーを見るテスト
package jp.seraphyware.htmlparsertest; import java.net.URL; import java.net.URLConnection; import org.htmlparser.Node; import org.htmlparser.Parser; import org.htmlparser.Tag; import org.htmlparser.Text; import org.htmlparser.util.NodeList; public class HTMLParserTest { public static void main(final String[] args) throws Exception { final URL url = new URL("http://java.sun.com/"); final URLConnection urlConnection = url.openConnection(); final Parser parser = new Parser(urlConnection); final NodeList lst = parser.parse(null); walkTree("", lst); } private static void walkTree(final String level, final NodeList lst) throws Exception { if (lst == null) { return; } final int cnt = lst.size(); for (int idx = 0; idx < cnt; idx++) { final Node node = lst.elementAt(idx); if (node instanceof Tag) { final String tagName = ((Tag) node).getTagName(); System.out.println(level + "<" + tagName + ">"); walkTree(level + " ", node.getChildren()); } else if (node instanceof Text) { final String txt = node.getText(); if (txt.trim().length() > 0) { System.out.println(level + txt); } } } } }
MSHTMLを使ってHTMLを解析してみる*3
URLを指定してHTMLを読み込みドキュメントツリーを見るテスト
#include "stdafx.h" #include <mshtml.h> class CMSHTMLParserTest : public CAtlExeModuleT<CMSHTMLParserTest> { public: HRESULT PreMessageLoop(int nShowCmd) throw() { HRESULT hr = CAtlExeModuleT<CMSHTMLParserTest>::PreMessageLoop(nShowCmd); if (FAILED(hr)) { return hr; } hr = pHTMLDocument_.CoCreateInstance(__uuidof(HTMLDocument)); ATLASSERT(SUCCEEDED(hr)); return hr; } void RunMessageLoop( ) throw() { HRESULT hr; CComPtr<IMoniker> pMoniker; hr = CreateURLMoniker(NULL, L"http://www.microsoft.com/japan/msdn/", &pMoniker); ATLASSERT(SUCCEEDED(hr)); CComPtr<IBindCtx> pBindCtx; hr = CreateBindCtx(0, &pBindCtx); ATLASSERT(SUCCEEDED(hr)); CComQIPtr<IPersistMoniker> pPersistMoniker(pHTMLDocument_); hr = pPersistMoniker->Load(FALSE, pMoniker, pBindCtx, STGM_READ); ATLASSERT(SUCCEEDED(hr)); hr = WaitForComplite(); ATLASSERT(SUCCEEDED(hr)); CComQIPtr<IHTMLDocument3> pDoc(pHTMLDocument_); CComPtr<IHTMLElement> pDocElement; hr = pDoc->get_documentElement(&pDocElement); ATLASSERT(SUCCEEDED(hr)); hr = WalkTree(pDocElement); ATLASSERT(SUCCEEDED(hr)); } private: HRESULT WalkTree(IHTMLElement* pElm) throw() { HRESULT hr; try { CComBSTR tagName; hr = pElm->get_tagName(&tagName); ATLASSERT(SUCCEEDED(hr)); OutputDebugStringW(tagName); OutputDebugStringW(L"\n"); CComPtr<IDispatch> pChildrenDisp; hr = pElm->get_children(&pChildrenDisp); ATLASSERT(SUCCEEDED(hr)); CComQIPtr<IHTMLElementCollection> pChildren(pChildrenDisp); long cnt; hr = pChildren->get_length(&cnt); ATLASSERT(SUCCEEDED(hr)); for (long idx = 0; idx < cnt; idx++) { CComVariant name(idx); CComVariant dmy; CComPtr<IDispatch> pChildDisp; hr = pChildren->item(name, dmy, &pChildDisp); ATLASSERT(SUCCEEDED(hr)); CComQIPtr<IHTMLElement> pChild(pChildDisp); hr = WalkTree(pChild); if (FAILED(hr)) { break; } } } catch (...) { return E_FAIL; } return hr; } HRESULT WaitForComplite() throw() { try { HRESULT hr = E_FAIL; int loop = 0; for (;;) { CComBSTR state; hr = pHTMLDocument_->get_readyState(&state); ATLASSERT(SUCCEEDED(hr)); if (FAILED(hr)) { break; } OutputDebugStringW(state); OutputDebugStringW(L"\n"); if (state != L"uninitialized" && state != L"loading") { hr = S_OK; } else { if (loop < 1000) { Sleep(50); continue; } } break; } return hr; } catch (...) { return E_FAIL; } } private: CComPtr<IHTMLDocument2> pHTMLDocument_; }; CMSHTMLParserTest _atlModule; int _tmain(int argc, _TCHAR* argv[]) { return _atlModule.WinMain(SW_SHOWNORMAL); }
所感
上記コードに自信はないが、とりあえず、動いた。その程度のレベル。
モニカの仕組みが分かっていないのだが、CreateURLMonikerでURLを指定することはできても、CreateFileMonikerでファイルを指定しても正しく読んでくれなかったのだ。
どうやら、IPersistMonikerではなく、IPersistFileを使ってロードしなければダメらしい。
なんで、そんなことになっているのかはわからない。
また非同期的にHTMLを読み込んでくれるので、完了したかどうかをチェックしなければならないのは、単純なシングルスレッドなバッチツールのような用途では、めんどくさいような気がする。(もちろん、コールバックを登録できるようであるが。)
それに、ステートを文字列で比較する以外に方法はないのだろうか?
しかし、この方法を使えばWebBrowserコントロールなどを使わずとも、GUIなしでHTMLを読ませて解析することができるので、覚えておくと重宝するのかもしれない。
使い方は奥が深いというか、調べないと分からないことは多すぎる気がする。