Java web page analysis jsoup study notes

My needs:

  • I need to learn some Jsoup and panLN,

I solved it like this:

jsoup is used to parse the DOM tree in HTML. For the DOM tree, Java provides Node and Document to resolve HTML and XML parsing. Jsoup provides more powerful functions than Node and Document, including parsing HTML through URL requests and local files.

jsoup: Java HTML parser

jsoup is a Java library for processing actual HTML. It uses the best DOM method of HTML5 and CSS selectors to provide a very convenient API for obtaining URLs and extracting and processing data.

jsoup implements the WHATWG HTML5 specification and parses HTML into the same DOM as modern browsers.

  • Grab and parse  HTML from URL, file or string

  • Use DOM traversal or CSS selectors to find and extract data

  • Process  HTML elements, attributes and text

  • Clear the content submitted by users according to the secure whitelist to prevent XSS attacks

  • Output neat HTML

jsoup is designed to handle all kinds of HTML found in the wild; from raw and verified to invalid tag soup; jsoup will create a wise parse tree.

input value

  1. Parse documents and body fragments from strings

     /**
         * @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. Load document from 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. Load document from file

     /**
         * @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();
            }
    
        }

    Document doc = Jsoup.parse(File in, String charsetName);

Extract data

  • Use the DOM method to browse documents

       /**
         * @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. Use selector syntax to find elements

     /**
         * @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(String selector)
    Elements.select(String selector)

  2. Extract attributes, text and HTML from elements

      /**
         * @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. Use 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. Sample program: List links

    
        /**
         * @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;
            }
        }

    Modify information

  1. Set attribute value
     

     /**
         * @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. Set the HTML of the element

    /**
        * @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. Set the text content of the element
     

     /**
        * @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(String text)

Clean up HTML

  1. Clean up untrusted HTML (to prevent 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>
       }

     

Guess you like

Origin blog.csdn.net/sanhewuyang/article/details/105079118