jsoup は、実際の HTML を処理するための Java ライブラリです。データの抽出と操作のための非常に便利な API を提供し、最良の DOM、CSS、jQuery に似た方法を使用します。
目次#
- jsoup の概要
- 使用シーン
- DOM 解析
- CSS セレクタ
- HTML フィルタリング
- 論理分析
- まとめ
jsoup の概要#
公式の説明:
jsoup は、実際の HTML を処理するための Java ライブラリです。データの抽出と操作のための非常に便利な API を提供し、最良の DOM、CSS、jQuery に似た方法を使用します。
私が Jsoup に触れたのは、Java でクローラーを書くときで、正規表現を大量に使用することがコードの可読性を低下させ、相対的に時間と労力がかかることに悩んでいました。その時、突然目に入ったのが jsoup というクローリングフレームワークです。
軽量で機能強力なクローリングフレームワークとして、jsoup は簡単にウェブページ情報を取得することを優雅で便利にします。 Java ライブラリであるにもかかわらず、その使用ロジックは jQuery に非常に近く、jQuery に慣れている人は簡単にこのフレームワークを使いこなすことができます。
使用シーン#
DOM 解析#
jsoup の DOM 解析は非常に簡単で、ただ新しい Document オブジェクトを作成するだけで、そのウェブページの要素を取得できます。次に、ウェブページを解析する例を示します。ウェブページを Document クラスに変換すると、その後の Element クラスおよびそのサブクラスはそれぞれノードとして扱うことができ、関連するメソッドを呼び出すことでファイルノード全体を遍歴できます。同時に、Element クラスの getElementByTag は JS の関連メソッドを連想させるため、JS と Java の基礎が少しでもある人はこのコードを見ても不思議に思わないでしょう。ここでは学生の成績情報を取得する例を示します:
public class jsoupTest {
public String getGrade(String stu_num, String id_num) throws IOException {
String testURL = "http://jwc.cqupt.edu.cn/showStuQmcj.php"; //対象ウェブページ
Connection con = Jsoup.connect(testURL); //接続を取得
con.data("xh", stu_num); //パラメータを入力
con.data("sfzh", id_num);
Document document = con.post(); //送信方法を選択し、ウェブページ情報全体を取得し、Documentクラスに保存
Element pTable = document.body().getElementsByClass("pTable").get(0); //class属性を通じて、サブクラス要素を取得
Elements trs = pTable.getElementsByTag("tbody").get(0).children();
trs.forEach(tr -> { //<tr>タグを遍歴
if (!tr.children().isEmpty()) {
Element element = tr.getElementsByTag("td").get(0);
if (!element.text().equals("课程类型")) {
GradeInfo gradeInfo = new GradeInfo();
gradeInfo.setProperty(tr.getElementsByTag("td").get(0).text());
String term = tr.getElementsByTag("td").get(1).text();
System.out.println(term);
System.out.println(tr.getElementsByTag("td").get(2).text());
System.out.println(tr.getElementsByTag("td").get(5).text());
System.out.println(tr.getElementsByTag("td").get(6).text());
System.out.println(tr.getElementsByTag("td").get(7).text());
}
}
});
return "";
}
}
結果:
数行で HTML の基本解析を完了でき、すべての操作は JS のロジックで説明できます。原生の正規表現よりも実用的です。
CSS セレクタ#
jsoup はフロントエンドに近づこうとしています。基本的な DOM 解析操作に加えて、CSS セレクタも追加されました。この操作は一見役に立たないように思えますが、実際に使い方を学ぶと非常に便利であることがわかります。複雑な文のマッチングに対して、セレクタを使用することで、簡単に必要な要素をフィルタリングでき、大量のコードを節約できます。 使用方法:Element.select (String selector) を使用して実現できます。
public void getBySelect() throws IOException {
String testURL = "<html>" +
"<head></head>"+
"<body>"+"<span id=\"grade\">成績</span>"+"<span id = \"subject\">科目</span>"+"<span id = \"name\">名前</span>"+"<span id = \"stunum\">学号</span>"+
"<span class = \"score\">85</span >"+"<span class = \"class\">国語</span>"+"<span class = \"stuname\">小明</span class = \"number\">"+"<span>201721001</span>"+
"<span id=\"grade\">80</span>"+"<span id = \"subject\">数学</span>"+"<span id = \"name\">小明</span>"+"<span id = \"stunum\">2017210001</span>"+
"</body></html>"; //文字列を使ってHTMLタグを生成
//接続を取得
Document document = Jsoup.parse(testURL); //HTMLを可遍歴のDocumentクラスに変換
Elements elements = document.select("span:matchesOwn(^8)");
for (Element element:
elements) {
System.out.println(elements.text());
}
}
結果:
CSS セレクタは、jQuery や CSS で使用されるセレクタに似ており、特定のセレクタ構文を使用して指定された要素をフィルタリングできます。セレクタのフィルタリングに関しては、こちらの記事をお勧めします:JSOUP の Select セレクタ構文の詳細解説
HTML フィルタリング#
この機能も偶然見つけたもので、今考えると当然のことですが、ウェブページ情報のフィルタリングは jsoup の仕事です。当時、XSS 攻撃に関する知識を見ていると、突然 jsoup がセキュリティ面で早くから考慮されていることに気付きました。優れた HTML 解析を基に、XSS 攻撃を防ぐことも非常に優れています。
XSS 注入の本質は、HTML に特定のタグを挿入して元のタグの意味を変更することです。したがって、XSS 攻撃を防ぐ本質は、余分または無効な HTML タグを識別し、迅速にフィルタリングすることです。これに対して、jsoup にはホワイトリストメカニズムがあり、clean メソッドを通じてホワイトリストで設定されたフィルタリングルールを一度に適用し、適切なタグを保持し、画像表示を禁止する機能も提供します。
/**
* xssフィルタリング
*
*/
public class JsoupUtil {
/**
* 自身のbasicWithImagesホワイトリストを使用
* 許可されるタグはa,b,blockquote,br,cite,code,dd,dl,dt,em,i,li,ol,p,pre,q,small,span,
* strike,strong,sub,sup,u,ul,img
* 及びaタグのhref,imgタグのsrc,align,alt,height,width,title属性
*/
private static final Whitelist whitelist = Whitelist.basicWithImages();
/** フィルタリングパラメータを設定し、コードのフォーマットを行わない */
private static final Document.OutputSettings outputSettings = new Document.OutputSettings().prettyPrint(false);
static {
// リッチテキストエディタでは、いくつかのスタイルがstyleを使用して実現されます
// 例えば、赤いフォント style="color:red;"
// したがって、すべてのタグにstyle属性を追加する必要があります
whitelist.addAttributes(":all", "style");
}
public static String clean(String content) {
return Jsoup.clean(content, "", whitelist, outputSettings);
}
public static void main(String[] args) throws FileNotFoundException, IOException {
String text = "<a href=\"http://www.baidu.com/a\" onclick=\"alert(1);\">sss</a><script>alert(0);</script>sss";
System.out.println(clean(text));
}
}
jsoup の論理分析#
軽量なクローリングフレームワークとして、すべて Jonathan Hedley によって独立して書かれているため、他のいくつかの重いフレームワークに比べてコードは非常にシンプルです。私はオンラインでいくつかの jsoup ソースコードを解析するブログを通じて、jsoup の理解を深めました。余計なことは言わず、jsoup の魅力を見てみましょう!
他のブログで整理された画像を借りると、Java が JS のようにタグのようなネストされたストレージ方法を使用できるようにするのは、ここでカスタムのノード抽象クラスを利用し、属性を木構造のように保存することです。これにより、後の DOM ツリー解析が容易になり、遍歴が容易になり、パフォーマンスの向上にも寄与します。次に、CSS セレクタの実装ロジックを見てみましょう。これはセレクタのソースコードリストです。
jsoup のセレクタの実装は、主に Evaluator 抽象クラスを利用しており、Selector が選択する式は最終的に QueryParser を通じて対応する Evaluator クラスにコンパイルされます。このクラスには多くの派生サブクラスがあり、それぞれ異なる機能を実現します。論理的な思考は比較的シンプルですが、具体的なコードはまだ詳しく読んでいないため、ここでは詳しく述べません。ただし、ネストされた実装オブジェクトの考え方は参考にする価値があります。
HTML フィルタリングに関して、jsoup が XSS 攻撃を防ぐための大まかな戦略は以下の通りです。
- HTML 文字列を Document オブジェクトに解析し、無駄なスクリプトや文字列の注入によってウェブページの機能が変更されることを防ぎます。
- 高頻度で出現する危険度の高いタグをホワイトリストに追加して事前にフィルタリングします。
まとめ#
jsoup は操作の便利さにおいてその実力を示していますが、パフォーマンスに関しては、底層が正規表現によるマッチングを通じて行われているため、単純な HTML 解析には正規表現が最も速いかもしれません。しかし、HTML ページが比較的複雑な場合、jsoup がその力を発揮する時です。
ただし、jsoup には多くの欠点があります。例えば、
- 静的ページしか処理できず、動的表示やバックエンドレンダリング後のページは正常にクローリングできません。この場合、httpunit などの他のツールを使用して Ajax リクエストをシミュレートする必要があります。
- jsoup は結局のところ個人プロジェクトであり、将来的なメンテナンスに関しては一定の不確実性があります。大規模で長期的なプロジェクトに使用する場合は、慎重に考える必要があります。
- jsoup の底層実装は依然として正規表現によるマッチングであり、jsoup 自体は軽量ですが、HTML 全体を解析してからさらに検索を行う必要があるため、単純なウェブページ解析では正規表現の方が直接的で便利です。しかし、ウェブページの構造が十分に複雑であれば、正規表現のコード量が膨大になるため、jsoup は良い選択肢となります。
要するに、jsoup は軽量なクローリングフレームワークとして、HTML 解析において非常に優れたパフォーマンスを示しています。普段から少し手を抜いて時間とコード量を節約したい場合は、ぜひ皆さんに使用をお勧めします。