JavaWebページ分析jsoup研究ノート

私のニーズ:

  • JsoupとpanLNを学ぶ必要があります。

私はそれを次のように解決しました:

  • Jsoupドキュメントをもう一度読んでください。

  • ブログを整理する

  • 公式文書:https//jsoup.org/

jsoupは、HTMLのDOMツリーを解析するために使用されます。DOMツリーの場合、JavaはHTMLとXMLの解析を解決するためのノードとドキュメントを提供します。Jsoupは、URLリクエストとローカルファイルを介したHTMLの解析など、ノードとドキュメントよりも強力な機能を提供します。

jsoup:JavaHTMLパーサー

jsoupは、実際のHTMLを処理するためのJavaライブラリです。HTML5およびCSSセレクターの最高のDOMメソッドを使用して、URLを取得し、データを抽出および処理するための非常に便利なAPI提供します。

jsoupは、WHATWG HTML5仕様を実装し、HTMLを最新のブラウザーと同じDOMに解析します。

  • URL、ファイル、または文字列から HTML取得して解析します

  • DOMトラバーサルまたはCSSセレクターを使用し、データ検索および抽出します

  • プロセスの HTML要素、属性、テキスト

  • XSS攻撃を防ぐために、安全なホワイトリストに従ってユーザーから送信されたコンテンツをクリアします

  • きちんとしたHTMLを出力する

jsoupは、未加工で検証済みのタグスープから無効なタグスープまで、実際に見られるすべての種類のHTMLを処理するように設計されています。jsoupは賢明な解析ツリーを作成します。

入力値

  1. 文字列からドキュメント本文のフラグメントを解析する

     /**
         * @Author Liruilong
         * @Description 字符串解析文档
         * @Date 15:44 2020/3/24
         * 使用静态Jsoup.parse(String html)方法,
         * 或者Jsoup.parse(String html, String baseUri)如果页面来自网络,并且您想要获取绝对URL(请参见[使用URL])。
         * <p>
         * 只要传入一个非null的字符串,就可以确保您成功且明智地进行了解析,
         * 并且Document包含(至少)一个 head和一个body元素
         **/
    
        public static void test1() {
            String html = "<html><head><title>First parse</title></head>"
                    + "<body><p>Parsed HTML into a doc.</p></body></html>";
            Document doc = Jsoup.parse(html);
    
            System.out.println("获取body中的html:  " + doc.body().html());
            System.out.println("获取head中的文本:   " + doc.head().text());
        }

    Jsoup.parse(String html)方法、
    Jsoup.parse(String html、String baseUri)

  2. URLからドキュメントをロード

      /**
         * @Author Liruilong
         * @Description 从URL加载文档
         * @Date 15:50 2020/3/24
         * 使用Jsoup.connect(String url)方法:
         * 该connect(String url)方法创建一个new Connection,并get()获取并解析一个HTML文件。
         * 如果在提取网址时发生错误,则会抛出一个IOException,您应该适当地处理它。
         * 此方法仅支持Web URL(http和https协议)
         * 也可以构建一个post请求
         **/
        public static void test2() {
            Document doc = null;
            try {
                doc = Jsoup.connect("https://www.baidu.com/").get();
            } catch (IOException e) {
                e.printStackTrace();
            }
            System.out.println(doc.title());
            System.out.println(doc.body());
            System.out.println(doc.head());
        }
    
      /**
         * @return void
         * @Author Liruilong
         * @Description 构建post请求
         * @Date 16:15 2020/3/24
         * @Param []
         **/
    
        public static void test3() {
            try {
                Document doc = Jsoup.connect("http://example.com")
                        .data("query", "Java")
                        .userAgent("Mozilla")
                        .cookie("auth", "token")
                        .timeout(3000)
                        .post();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    

    doc = Jsoup.connect( "https://www.baidu.com/").get();

  3. ファイルからドキュメントをロードする

     /**
         * @Author Liruilong 
         * @Description 从文件加载文档
         * @Date 16:17 2020/3/24
         * 该parse(File in, String charsetName, String baseUri)方法加载并解析HTML文件。
         * 如果在加载文件时发生错误,它将抛出一个IOException
         * baseUri解析器使用该参数在<base href>找到元素之前解析文档中的相对URL 。
         * 如果您不需要,可以改为传递一个空字符串。
         * 姐妹方法parse(File in, String charsetName),该方法将文件的位置用作baseUri。
         * 如果您在文件系统本地站点上工作,并且它指向的相对链接也在文件系统上,则此功能很有用。
         **/
        
        public static void test4() {
            File input = new File("G:\\jsoupDemo\\tmp\\input.html");
            try {
                //parse(File in, String charsetName)
                Document doc = Jsoup.parse(input, "UTF-8", "https://www.baidu.com/");
                System.out.println(doc.head().text());
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }

    ドキュメントdoc = Jsoup.parse(File in、String charsetName);

データを抽出する

  • DOMメソッドを使用してドキュメントを参照する

       /**
         * @Author Liruilong
         * @Description 使用DOM方法浏览文档
         * @Date 16:52 2020/3/24
         * 将HTML解析为Document之后,请使用类似DOM的方法Document。
         * 寻找元素:
         * getElementById(String id)
         * getElementsByTag(String tag)
         * getElementsByClass(String className)
         * getElementsByAttribute(String key)
         * 元素的兄弟姐妹::siblingElements(),firstElementSibling(),lastElementSibling(),nextElementSibling(),previousElementSibling()
         * 获取doc:parent(),children(),child(int index)
         * 元素数据:
         * attr(String key)获取和attr(String key, String value)设置属性
         * attr(String key)获取和attr(String key, String value)设置属性
         * attributes() 获取所有属性
         * id(),className()和classNames()
         * text()获取并text(String value)设置文本内容
         * html()获取并html(String value)设置内部HTML内容
         * outerHtml() 获得外部HTML值
         * data()获取数据内容(例如script和style标签)
         * tag() 和 tagName()
         * 处理HTML和文本
         * append(String html), prepend(String html)
         * appendText(String text), prependText(String text)
         * appendElement(String tagName), prependElement(String tagName)
         * html(String value)
         **/
    
        public static void test1() throws IOException {
            File input = new File("G:\\jsoupDemo\\tmp\\input.html");
            Document doc = Jsoup.parse(input, "UTF-8");
    
            Element content = doc.getElementById("s_wrap");
            System.out.println("Iid的内容:" + content.text());
            Elements links = content.getElementsByTag("li");
            links.stream().forEach(o -> {
                System.out.println(o.attr("class").toString());
                System.out.println(o.text());
            });
    
        }
    

         getElementById(String id)
         getElementsByTag(String tag)
         getElementsByClass(String className)
         getElementsByAttribute(String key)

    ………………

  1. セレクター構文を使用して要素を検索する

     /**
         * @Author Liruilong
         * @Description 使用选择器语法查找元素
         * @Date 17:22 2020/3/24
         * Element.select(String selector)和Elements.select(String selector)方法
         * 该select方法在一个可用Document,Element或在Elements。它是上下文相关的,
         * 因此您可以通过从特定元素中进行选择或链接选择调用来进行过滤。
         * 选择器概述:
         * tagname:按标签查找元素,例如 a
         * ns|tag:通过名称空间中的标签fb|name查找<fb:name>元素,例如,查找元素
         * #id:按ID查找元素,例如 #logo
         * .class:按类名称查找元素,例如 .masthead
         * [attribute]:具有属性的元素,例如 [href]
         * [^attr]:具有属性名称前缀的[^data-]元素,例如查找具有HTML5数据集属性的元素
         * [attr=value]:具有属性值的元素,例如[width=500](也可以引用,如[data-name='launch sequence'])
         * [attr^=value],[attr$=value],[attr*=value]:与属性的元素,与开始,结束与,或包含所述的值,例如[href*=/path/]
         * [attr~=regex]:具有与正则表达式匹配的属性值的元素;例如img[src~=(?i)\.(png|jpe?g)]
         * *:所有元素,例如 *
         * 选择器组合:
         * el#id:具有ID的元素,例如 div#logo
         * el.class:具有类的元素,例如 div.masthead
         * el[attr]:具有属性的元素,例如 a[href]
         * 任何组合,例如 a[href].highlight
         * ancestor child:从祖先派生的子元素,例如在“ body”类的块下的任何位置.body p找到p元素
         * parent > child:直接从父级派生的子元素,例如div.content > pfind p元素;并body > *找到身体标签的直接子代
         * siblingA + siblingB:查找紧随同级A的同级B元素,例如 div.head + div
         * siblingA ~ siblingX:查找同级X元素后跟同级A,例如 h1 ~ p
         * el, el, el:将多个选择器组合在一起,找到与任何选择器匹配的唯一元素;例如div.masthead, div.logo
         * 伪选择器:
         * :lt(n):查找其同级索引(即,它在DOM树中相对于其父级的位置)小于的元素n;例如td:lt(3)
         * :gt(n):查找同级索引大于的元素n; 例如div p:gt(2)
         * :eq(n):查找兄弟索引等于的元素n; 例如form input:eq(1)
         * :has(selector):查找包含与选择器匹配的元素的元素;例如div:has(p)
         * :not(selector):查找与选择器不匹配的元素;例如div:not(.logo)
         * :contains(text):查找包含给定文本的元素。搜索不区分大小写;例如p:contains(jsoup)
         * :containsOwn(text):查找直接包含给定文本的元素
         * :matches(regex):查找文本与指定正则表达式匹配的元素;例如div:matches((?i)login)
         * :matchesOwn(regex):查找其自身文本与指定的正则表达式匹配的元素
         * 请注意,上面索引的伪选择器基于0,即第一个元素位于索引0,第二个元素位于1,依此类推。
         **/
    
        public static void test2() throws IOException {
            File input = new File("G:\\jsoupDemo\\tmp\\input.html");
            Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");
    
            Elements links = doc.select("a[href]"); // a with href
            Elements pngs = doc.select("img[src$=.png]");
            // img with src ending .png
    
            Element masthead = doc.select("div.masthead").first();
            // div with class=masthead
    
            Elements resultLinks = doc.select("h3.r > a"); // direct a after h
        }

    Element.select(文字列セレクター)
    Elements.select(文字列セレクター)

  2. 要素から属性、テキスト、HTMLを抽出します

      /**
         * @Author Liruilong
         * @Description 从元素中提取属性,文本和HTML
         * @Date 17:32 2020/3/24
         * 要获取属性的值,请使用Node.attr(String key)方法
         * 对于元素(及其组合的子元素)上的文本,请使用 Element.text()
         * 对于HTML,请使用Element.html(),或Node.outerHtml()酌情使用
         * Element.id()
         * Element.tagName()
         * Element.className() 和 Element.hasClass(String className)
         **/
    
    
        public static void test3() {
            String html = "<p>An <a href='http://example.com/'><b>example</b></a> link.</p>";
            Document doc = Jsoup.parse(html);
            Element link = doc.select("a").first();
    
            String text = doc.body().text(); // "An example link"
            String linkHref = link.attr("href"); // "http://example.com/"
            String linkText = link.text(); // "example""
            System.out.println(text);
            System.out.println(linkHref);
            String linkOuterH = link.outerHtml();
            // "<a href="http://example.com"><b>example</b></a>"
            String linkInnerH = link.html(); // "<b>example</b>"
        }

    Element.html()
    Node.outerHtml()

  3. URLを使用する

    /**
         * @Author Liruilong
         * @Description 使用网址
         * @Date 17:40 2020/3/24
         * 您有一个包含相对URL的HTML文档,您需要将其解析为绝对URL。
         * 确保base URI在解析文档时指定一个(从URL加载时是隐式的),并且
         * 使用abs:属性前缀可以从属性解析绝对URL:
         * 在HTML元素中,通常是相对于文档的位置写URL <a href="/download">...</a>。
         * 当您使用该Node.attr(String key)方法获取href属性时,将按源HTML中指定的方式返回该属性。
         * 如果要获取绝对URL,则有一个属性键前缀abs:,
         * 它将导致根据文档的基本URI(原始位置)解析属性值:attr("abs:href")
         **/
    
        public static void test4() throws IOException {
            Document doc = Jsoup.connect("http://jsoup.org").get();
    
            Element link = doc.select("a").first();
            String relHref = link.attr("href"); // == "/"
            String absHref = link.attr("abs:href"); // "http://jsoup.org/"
        }
    

     

  4. サンプルプログラム:リストリンク

    
        /**
         * @return
         * @Author Liruilong
         * @Description
         * @Date 17:44 2020/3/24
         * @Param
         **/
        public static void test4(String[] args) throws IOException {
            Validate.isTrue(args.length == 1, "usage: supply url to fetch");
            String url = args[0];
            print("Fetching %s...", url);
    
            Document doc = Jsoup.connect(url).get();
            Elements links = doc.select("a[href]");
            Elements media = doc.select("[src]");
            Elements imports = doc.select("link[href]");
    
            print("\nMedia: (%d)", media.size());
           for (Element src : media) {
                if (src.normalName().equals("img"))
                    print(" * %s: <%s> %sx%s (%s)",
                            src.tagName(), src.attr("abs:src"), src.attr("width"), src.attr("height"),
                            trim(src.attr("alt"), 20));
                else
                    print(" * %s: <%s>", src.tagName(), src.attr("abs:src"));
            }
    
            print("\nImports: (%d)", imports.size());
            for (Element link : imports) {
                print(" * %s <%s> (%s)", link.tagName(), link.attr("abs:href"), link.attr("rel"));
            }
    
            print("\nLinks: (%d)", links.size());
            for (Element link : links) {
                print(" * a: <%s>  (%s)", link.attr("abs:href"), trim(link.text(), 35));
            }
        }
    
        private static void print(String msg, Object... args) {
            System.out.println(String.format(msg, args));
        }
    
        private static String trim(String s, int width) {
            if (s.length() > width) {
                return s.substring(0, width - 1) + ".";
            } else {
                return s;
            }
        }

    情報を変更する

  1. 属性値を設定する
     

     /**
         * @Author Liruilong 
         * @Description 
         * @Date 18:45 2020/3/24
         * 在你解析一个Document之后可能想修改其中的某些属性值,然后再保存到磁盘或都输出到前台页面。
         * 可以使用属性设置方法 Element.attr(String key, String value), 和 Elements.attr(String key, String value).
         * 假如你需要修改一个元素的 class 属性,可以使用 Element.addClass(String className) 和 Element.removeClass(String className) 方法。
         * Elements 提供了批量操作元素属性和class的方法,比如:要为div中的每一个a元素都添加一个 rel="nofollow" 可以使用如下方法
         * 与Element中的其它方法一样,attr 方法也是返回当 Element (或在使用选择器是返回 Elements 集合)。这样能够很方便使用方法连用的书写方式。
         *
         **/
        
       public static void   test1(){
           Document doc = Jsoup.parse("");
           doc.select("div.comments a").attr("rel", "nofollow");
           doc.select("div.masthead").attr("title", "jsoup").addClass("round-box");
       }

     

  2. 要素のHTMLを設定します

    /**
        * @Author Liruilong 
        * @Description  设置一个元素的HTML内容
        * @Date 18:56 2020/3/24
        * Element.html(String html) 这个方法将先清除元素中的HTML内容,然后用传入的HTML代替。
        * Element.prepend(String first) 和 Element.append(String last) 方法用于在分别在元素内部HTML的前面和后面添加HTML内容
        * Element.wrap(String around) 对元素包裹一个外部HTML内容。
        * Element.prependElement(String tag)和Element.appendElement(String tag)
        * 方法来创建新的元素并作为文档的子元素插入其中。
        **/
       
       public static void  test2(){
           Document doc = Jsoup.parse("");
           Element div = doc.select("div").first(); // <div></div>
           div.html("<p>lorem ipsum</p>"); // <div><p>lorem ipsum</p></div>
           div.prepend("<p>First</p>");//在div前添加html内容
           div.append("<p>Last</p>");//在div之后添加html内容
    // 添完后的结果: <div><p>First</p><p>lorem ipsum</p><p>Last</p></div>
    
           Element span = doc.select("span").first(); // <span>One</span>
           span.wrap("<li><a href='http://example.com/'></a></li>");
    // 添完后的结果: <li><a href="http://example.com"><span>One</span></a></li>
       }

    Element.prependElement(String tag)
    Element.appendElement(String tag)

  3. 要素のテキストコンテンツを設定します
     

     /**
        * @Author Liruilong
        * @Description 修改一个HTML文档中的文本内容
        * @Date 19:06 2020/3/24
        * Element.text(String text) 将清除一个元素中的内部HTML内容,然后提供的文本进行代替
        * Element.prepend(String first) 和 Element.append(String last) 将分别在元素的内部html前后添加文本节点。
        * 对于传入的文本如果含有像 <, > 等这样的字符,将以文本处理,而非HTML。
        **/
    
       public static void test3(){
           Document doc = Jsoup.parse("");
           Element div = doc.select("div").first(); // <div></div>
           div.text("five > four"); // <div>five &gt; four</div>
           div.prepend("First ");
           div.append(" Last");
    // now: <div>First five &gt; four Last</div>
       }

    Element.text(文字列テキスト)

HTMLをクリーンアップする

  1. 信頼できないHTMLをクリーンアップする(XSSを防ぐため)
     

    /**
        * @Author Liruilong
        * @Description  消除不受信任的HTML (来防止XSS攻击)
        * @Date 19:16 2020/3/24
        * 使用jsoup HTML Cleaner 方法进行清除,但需要指定一个可配置的 Whitelist。
        * XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,
        * 当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,
        * 从而达到恶意攻击用户的特殊目的。XSS属于被动式的攻击,因为其被动且不好利用,
        * 所以许多人常忽略其危害性。所以我们经常只让用户输入纯文本的内容,但这样用户体验就比较差了。
        * soup的whitelist清理器能够在服务器端对用户输入的HTML进行过滤,只输出一些安全的标签和属性。
        *
        * jsoup提供了一系列的Whitelist基本配置,能够满足大多数要求;但如有必要,也可以进行修改,不过要小心。
        *
        * 这个cleaner非常好用不仅可以避免XSS攻击,还可以限制用户可以输入的标签范围。
        **/
    
       public  static  void  test4(){
           String unsafe =
                   "<p><a href='http://example.com/' onclick='stealCookies()'>Link</a></p>";
                     String safe = Jsoup.clean(unsafe, Whitelist.basic());
                // now: <p><a href="http://example.com/" rel="nofollow">Link</a></p>
       }

     

おすすめ

転載: blog.csdn.net/sanhewuyang/article/details/105079118