DOMの扱い方はよく忘れそうになるので、備忘録がてら書いてみる。MDNから引用するようにしているが、もしかしたら理解が間違っているかもしれない。 DenoでHTMLドキュメントをパースするには、deno-dom-wasmを使う。
deno-dom-wasmはDenoのためのDOMおよびHTML parserの実装。Rust (WASMコンパイル)とTypeScriptで書かれている。
parseFromStringメソッドを使ってHTMLドキュメントをパースする。
第1引数はパースしたいHTML文字列。第2引数はMIMEタイプとして text/html を指定する。
戻り値の型は null または NodeList となっている。
parseFromString(source:string, mimeType:DOMParserMimeType) : NodeList | nullNodeListは、Nodeの集合体を表す。NodeはHTMLドキュメントのそれぞれの節(ノード)を表す抽象クラスで、Document, Element, DocumentFragmentなどのサブクラスを持つ。 つまり、ElementはNodeのふるまいを持っていると言える。
EventTarget ◁- Node ◁- Element
NodeListは、そのままではNodeの配列として扱うことができないため関数型プログラミングで多用される map()、 filter() のような便利なメソッドを直接呼び出すことができない。MDNにはこう書かれている。
メモ: NodeList は Array とは異なりますが、forEach() メソッドで処理を反復適用することは可能です。Array.from() を使うことで Array に変換することができます。
Array.from() を使うとNodeListをNodeの配列として扱うことができる。
配列のプロトタイプ関数 map() を使ってそれぞれの要素(Node)に関数を適用し、新しく作る配列にマップする。
NodeからquerySelector()メソッドを呼び出したいが、Nodeはそのメソッドを持っていないため一旦Elementに変換する。
あまりしっくりこない方法だと感じるのでもっと良い方法があれば知りたい
Array.from(nodeList).map((node: Node) => {
const el = node as Element;
// TODO: Do something with `el`
return {
// ...
}
});Elementはセレクタから子ノードを取得する querySelector()、 querySelectorAll()、属性を取得する getAttribute()、中身のテキストを取得するtextContentそれぞれのメンバーを持っている。
Element.querySelector(selectors:string) : Element | nullElement.querySelectorAll(selectors:string) : NodeListElement.getAttribute(name:string) : string | nullNode.textContent : string
map() 関数内でElementから取得した属性やテキストをオブジェクトに詰め込み、パース結果の入ったオブジェクトの配列を作ることができる。
return {
title: el.querySelector(".result__title")?.textContent.trim(),
link: extractSearchParam(
`https:${el.querySelector("a.result__url")?.getAttribute("href")!}`,
"uddg",
),
snippet: el.querySelector(".result__snippet")?.textContent.trim(),
};オブジェクトに詰め込んでしまえばあとは.filter()でフィルタリングしたりJSON.stringify()でJSONに変換したり好きなように取り回せる。
解説おわり。
Usage