HTML を scraping したかったのだが、対象箇所が1箇所だと Ruby や Python を持ち出して parse するのも面倒なので bash で済ませたいなと。
しかし sed でやるのは煩雑なので、もっと手軽な方法がないものかと「bash html parse」でググってみたところ xmllint が使えそうなことが分かった。
ところが、UTF-8 で書かれたマルチバイト文字を含む HTML を xmllint に食わせて xpath を処理させてみたところ、マルチバイトコードが上手く処理出来ず、以下のように属性値は数値文字参照(numeric character reference)に、要素の内容は一応 UTF-8 っぽいのだがおかしなコードに文字化けしてしまう。
しかし sed でやるのは煩雑なので、もっと手軽な方法がないものかと「bash html parse」でググってみたところ xmllint が使えそうなことが分かった。
ところが、UTF-8 で書かれたマルチバイト文字を含む HTML を xmllint に食わせて xpath を処理させてみたところ、マルチバイトコードが上手く処理出来ず、以下のように属性値は数値文字参照(numeric character reference)に、要素の内容は一応 UTF-8 っぽいのだがおかしなコードに文字化けしてしまう。
$ read html <<<'<!DOCTYPE html><html><head><meta name="title" content="こんにちは世界"></head><body><p>こんにちは世界</p></body></html>'
$ echo $html <!DOCTYPE html><html><head><meta name="title" content="こんにちは世界"></head><body><p>こんにちは世界</p></body></html>
$ echo "$html" | xmllint --xpath '//meta' --html - <meta name="title" content="こんにちは世界"/>
$ echo こんにちは世界|xxd 00000000: e381 93e3 8293 e381 abe3 81a1 e381 afe4 ................ 00000010: b896 e795 8c0a ......
$ echo "$html" | xmllint --xpath 'string(//p)' --html - | xxd 00000000: c3a3 c281 c293 c3a3 c282 c293 c3a3 c281 ................ 00000010: c2ab c3a3 c281 c2a1 c3a3 c281 c2af c3a4 ................ 00000020: c2b8 c296 c3a7 c295 c28c 0a ...........
$ echo "$html" | xmllint --xpath 'string(//p)' --html - | nkf -g UTF-8ヘルプを見ると --encode ENCODING ってオプションがあったので、試しに --encoding utf-8 を与えてみたが効果が見られなかった。
「xmllint encoding」でググったところ以下のページを見つけた。
- teratail / 2020-12-11: xmllintのxpathでhtmlを解析しようとすると日本語が文字化けする
$ echo "$html" | sed -E 's@<head>@\0<meta charset="utf-8"/>@g' | xmllint --xpath '//meta' --html - <meta charset="utf-8"/> <meta name="title" content="こんにちは世界"/>
$ echo "$html" | sed -E 's@<head>@\0<meta charset="utf-8"/>@g' | xmllint --xpath '//meta[@name="title"]' --html - <meta name="title" content="こんにちは世界"/>
$ echo "$html" | sed -E 's@<head>@\0<meta charset="utf-8"/>@g' | xmllint --xpath '//meta[@name="title"]/@content' --html - content="こんにちは世界"
$ echo "$html" | sed -E 's@<head>@\0<meta charset="utf-8"/>@g' | xmllint --xpath 'string(//meta[@name="title"]/@content)' --html - こんにちは世界
$ echo "$html" | sed -E 's@<head>@\0<meta charset="utf-8"/>@g' | xmllint --xpath '//p' --html - <p>こんにちは世界</p>
$ echo "$html" | sed -E 's@<head>@\0<meta charset="utf-8"/>@g' | xmllint --xpath 'string(//p)' --html - こんにちは世界
$ echo "$html" | sed -E 's@<head>@\0<meta charset="utf-8"/>@g' | xmllint --xpath '//p/text()' --html - こんにちは世界
タグ
コメントをかく