jsoup爬虫教程技巧_Jsoup V的幕后秘密:优化的技巧和窍门

jsoup爬虫教程技巧

我们已经把事情做好了,现在是时候加快工作速度了。 我们会牢记Donald Knuth的警告:“大约97%的时间我们应该忘记效率低下:过早的优化是万恶之源”。

根据Jonathan Hedley的介绍,他使用YourKit Java Profiler来测量内存使用情况并找到性能热点。 使用此类工具的统计结果对于优化的成功至关重要,它将防止您花时间思考和进行无用的调优,这不会提高性能,但也会使代码不必要地变得复杂且难以维护。 乔纳森(Jonathan)在“科隆(Colophon)”中也谈到了这一点。

我们将列出Jsoup中使用的一些技巧和窍门,它们目前是随机排列的,将来会重新组织。

Jsoup的秘密

1.缩进填充

// memoised padding up to 21, from "", " ", "  " to "                   "
static final String[] padding = {......};public static String padding(int width) {if (width < 0)throw new IllegalArgumentException("width must be > 0");if (width < padding.length)return padding[width];char[] out = new char[width];for (int i = 0; i < width; i++)out[i] = ' ';return String.valueOf(out);
}protected void indent(Appendable accum, int depth, Document.OutputSettings out) throws IOException {accum.append('\n').append(StringUtil.padding(depth * out.indentAmount()));
}

很聪明吧? 它保留了不同长度的填充缓存,可以覆盖80%的情况-我认为这是基于作者的经验和统计数据。

2.是否上课?

Element#hasClass被标记为对性能敏感的 ,例如,我们要检查<div class="logged-in env-production intent-mouse">是否具有类production ,将类按空格分割为数组,然后循环并进行搜索,但深入了解这将是无效的。 Jsoup首先在这里介绍了Early Exit ,方法是将长度与目标类名进行比较,以避免不必要的扫描和搜索,这也将是有益的。 然后,它使用一个检测空白的指针并执行regionMatches-坦白地说,这是我第一次了解方法String#regionMatches &#55357;&#56904;&#55357;&#56837;。

public boolean hasClass(String className) {final String classAttr = attributes().getIgnoreCase("class");final int len = classAttr.length();final int wantLen = className.length();if (len == 0 || len < wantLen) {return false;}// if both lengths are equal, only need compare the className with the attributeif (len == wantLen) {return className.equalsIgnoreCase(classAttr);}// otherwise, scan for whitespace and compare regions (with no string or arraylist allocations)boolean inClass = false;int start = 0;for (int i = 0; i < len; i++) {if (Character.isWhitespace(classAttr.charAt(i))) {if (inClass) {// white space ends a class name, compare it with the requested one, ignore caseif (i - start == wantLen && classAttr.regionMatches(true, start, className, 0, wantLen)) {return true;}inClass = false;}} else {if (!inClass) {// we're in a class name : keep the start of the substringinClass = true;start = i;}}}// check the last entryif (inClass && len - start == wantLen) {return classAttr.regionMatches(true, start, className, 0, wantLen);}return false;
}

3.标签名称是否存在?

正如我们在之前的文章中所分析的那样, HtmlTreeBuilderState将通过检查某个集合中的标记名称是否正确来验证嵌套的正确性。 我们可以比较1.7.3之前和之后的实现以进行检查。

// 1.7.2
} else if (StringUtil.in(name, "base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title")) {return tb.process(t, InHead);
}// 1.7.3
static final String[] InBodyStartToHead = new String[]{"base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title"};
...
} else if (StringUtil.inSorted(name, Constants.InBodyStartToHead)) {return tb.process(t, InHead);
}

根据作者的评论,“这里有点难读,但与动态varargs相比,GC少。 贡献了大约10%的解析GC负载。 必须确保将它们排序,如findSorted中所使用。 简单地使用static final常数数组,也可以对其进行排序,以便二进制搜索也可以从O(n)改善为O(log(n)),在这里性价比非常好。

但是,“如果添加更多的数组,则必须更新HtmlTreebuilderStateTest”不是同步恕我直言的好方法,而不是复制和粘贴,我将使用反射来检索那些常量。 您可以在Pull Request #1157中找到我的建议:“简化状态排序状态单元测试–避免在HtmlTreeBuilderStateTest.java中重复代码” 。

4.轻量级模式

您知道Integer.valueOf(i)的技巧吗? 如果已配置( java.lang.Integer.IntegerCache.high ),它将保持-128到127或更高的IntegerCache缓存,结果,当值位于不同范围内时, == equals结果将有所不同(经典Java面试问题?)。 这实际上是一个轻量级模式的示例。 对于Jsoup,应用此模式还将减少对象创建时间,并提高性能。

/*** Caches short strings, as a flywheel pattern, to reduce GC load. Just for this doc, to prevent leaks.* <p />* Simplistic, and on hash collisions just falls back to creating a new string, vs a full HashMap with Entry list.* That saves both having to create objects as hash keys, and running through the entry list, at the expense of* some more duplicates.*/
private static String cacheString(final char[] charBuf, final String[] stringCache, final int start, final int count) {// limit (no cache):if (count > maxStringCacheLen)return new String(charBuf, start, count);if (count < 1)return "";// calculate hash:int hash = 0;int offset = start;for (int i = 0; i < count; i++) {hash = 31 * hash + charBuf[offset++];}// get from cachefinal int index = hash & stringCache.length - 1;String cached = stringCache[index];if (cached == null) { // miss, addcached = new String(charBuf, start, count);stringCache[index] = cached;} else { // hashcode hit, check equalityif (rangeEquals(charBuf, start, count, cached)) { // hitreturn cached;} else { // hashcode conflictcached = new String(charBuf, start, count);stringCache[index] = cached; // update the cache, as recently used strings are more likely to show up again}}return cached;
}

还有另一种情况,可以使用相同的想法来最小化新的StringBuilder GC。

private static final Stack<StringBuilder> builders = new Stack<>();/*** Maintains cached StringBuilders in a flyweight pattern, to minimize new StringBuilder GCs. The StringBuilder is* prevented from growing too large.* <p>* Care must be taken to release the builder once its work has been completed, with {@see #releaseBuilder}
*/
public static StringBuilder borrowBuilder() {synchronized (builders) {return builders.empty() ?new StringBuilder(MaxCachedBuilderSize) :builders.pop();}
}

实际上, CharacterReaderStringUtil值得越来越消化,因为有许多有用的提示和技巧会激发您的灵感。

5.其他改善方法

  • 使用RandomAccessFile读取文件,将文件读取时间缩短了2倍。 查看#248了解更多详情
  • 节点层次结构重构。 查看#911了解更多详细信息
  • “在很大程度上基于对各种网站的分析重新排序HtmlTreeBuilder方法而带来的改进” –我在此列出了这一点,因为它非常实用。 更深入地了解和观察代码的运行方式也将为您提供一些见解
  • 调用list.toArray(0)而不是list.toArray(list.size()) –已在某些开源项目(例如h2database)中使用 ,因此我也在另一个Pull Request #1158中提出了此要求

6.未知数

优化永无止境。 我目前还没有发现很多提示和技巧。 如果您在Jsoup中发现更多启发性的想法,请与我分享,我将不胜感激。 您可以在该网站的左侧栏中找到我的联系信息,或者直接通过ny83427 at gmail.com发送电子邮件至ny83427 at gmail.com

-未完待续-

翻译自: https://www.javacodegeeks.com/2019/02/secrets-jsoup-tricks-optimization.html

jsoup爬虫教程技巧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/332736.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DOM(document object model),文档对象模型

DOM 将标记语言文档一次性加载进内存中&#xff0c;在内存中形成一棵 DOM 数。

php 获取请求设备,php – 如何获取设备令牌

我有一个iOS应用程序,我想集成推送通知.我见过tutorial on youtube,一切都还可以,但最近我使用的是开发证书(用于测试 – 不用于AppStore),我的服务器上有PHP脚本.在这个文件中存储了deviceToken,它有我的iPhone并且用php变量$deviceToken编写.但是现在,当我想在AppStore中使用…

java项目使用junit_在Java 8之前的项目中使用JUnit 5

java项目使用junit这篇文章演示了如何在Java 8之前的项目中使用JUnit 5&#xff0c;并解释了为什么它是一个好主意。 JUnit 5至少需要Java 8作为运行时环境&#xff0c;因此您想将整个项目更新为Java8。但是有时由于某些原因&#xff0c;您无法立即将项目更新为Java8。例如&am…

set cache php,TP5之Cache的原理及使用

在当今大流量的互联网之中&#xff0c;Cache的重要性不言而喻。ThinkPhp5作为国内主流框架&#xff0c;提供了强大的Cache功能。让我们跟随本文&#xff0c;来剖析TP5 Cache的原理及使用。为什么需要Cache(缓存)?假设现在有一个小说网,有非常多的读者,有一篇新的章节更新了,那…

IntelliJ IDEA for Mac 项目窗口详解(Project Windows)

Show Members&#xff1a;显示成员&#xff0c;打勾&#xff0c;类的成员&#xff0c;例如&#xff1a;方法、字段等会显示出来&#xff0c;如下图所示&#xff1a; Show Excluded Files&#xff1a;显示排除的文件 Show Visibility Icons&#xff1a;显示可见性图标&#xff…

jdk9与jdk11哪个好_JDK 9、10和11中的安全性增强

jdk9与jdk11哪个好缩短JDK发布周期的原因之一是有可能推出更快的安全错误修复和增强功能。 在本文中&#xff0c;我们将简要回顾一下最新JDK版本中引入的主要安全增强功能。 由于这些增强功能中的大多数与TLS相关&#xff0c;因此必须了解TLS握手过程&#xff0c;如下图所示&am…

对一个java源文件进行正确编译,给定如下一个Java源文件Child.java,编译并运行Child.java,以下结果正确...

给定如下一个Java源文件Child.java&#xff0c;编译并运行Child.java&#xff0c;以下结果正确答&#xff1a;编译错误&#xff1a;没有找到构造器 Parent1()中国大学MOOC: 图像分割是基于灰度值的两个基本特性()答&#xff1a;相似性 连续性合同是平等主体之间的 法律行为。答…

多云平台_多云系统的授权

多云平台这是我目前正在使用的项目设计&#xff0c;用于消耗SPIFFE&#xff08; 受所有人保护的安全生产身份框架&#xff08; &#xff09;的信任和身份识别&#xff0c;在WSO2的Prabath Siriwardena先生的启发下&#xff0c;在Moratuwa大学的Gihan Dias教授的指导下&#xf…

XML的学习

文章目录XML 简介XML 语法XML 组成部分XML 约束DTD名称解释引用内部的 DTD引用外部的 DTDSchema语法格式详解命名空间前缀的意义XML 解析解析 XML 的方式&#xff08;思想&#xff09;解析器JSOUP 的使用JSOUP 入门快捷查询Jsoup 选择器查询XPathXML 简介 XML&#xff0c;Exte…

php 日期多余小时,在PHP中添加小时到日期时间

DateTime是PHP中的一个很棒的功能$string 1/1/2016 11.00PM;$date new DateTime($string);$interval new DateInterval(PT6H);$date->add($interval);// Now add another 6 hours while we are between 12:00 AM and 6:00 AMwhile($date->format(G) > 0 &&…

streaming api_通过Spring Integration消费Twitter Streaming API

streaming api1.概述 众所周知&#xff0c; Spring Integration具有用于与外部系统交互的大量连接器。 Twitter也不例外&#xff0c;而且很长一段时间以来&#xff0c;因为Spring Social一直是一个开箱即用的解决方案&#xff0c;Spring Integration利用该解决方案来连接到社交…

Linux命令之 mount -- 文件系统挂载

文章目录简介参考实例加载指定的分区参考简介 mount 命令用于加载文件系统到指定的加载点。此命令的最常用于挂载 cdrom&#xff0c;使我们可以访问 cdrom 中的数据&#xff0c;因为你将光盘插入 cdrom 中&#xff0c;Linux 并不会自动挂载&#xff0c;必须使用 Linux mount 命…

java 舍,java 4舍六入五成双

java 四舍六入五成双1. 小于5舍去&#xff0c;即舍去部分的数值小于保留部分的末位的半个单位&#xff0c;则末位不变&#xff1b;2. 大于5进1&#xff0c;即舍去部分的数值大于保留部分的末位的半个单位&#xff0c;则末位加1&#xff1b;3. 等于5时取偶数&#xff0c;即舍去部…

Linux命令之 umount -- 卸载文件系统

文章目录介绍参考介绍 umount 是“unmount”的缩写&#xff0c;译为“不挂载。所以它的”的作用是卸载已挂载的文件系统、目录或文件。 利用设备名或挂载点都能umount文件系统&#xff0c;不过最好还是通过挂载点卸载&#xff0c;以免使用绑定挂载&#xff08;一个设备&#x…

aws技术峰会2018_AWS re:Invent 2018的5大公告

aws技术峰会2018AWS re&#xff1a;Invent刚刚完成。 这是一个巨大的活动&#xff0c;在拉斯维加斯7家最大的酒店中&#xff0c;有50,000多名与会者&#xff0c;并发布了许多新的服务公告。 无服务器端通过新的lambda增强功能和更好的容器支持继续受到很多关注。 AWS通过新的“…

php 降低图像大小,PHP图像重新调整大小

我有一个PHP脚本,可以重新调整JPEG图像的大小.但是,由于某种原因,图像被扭曲,即使我将其编程为按比例计算x或y(取决于照片方向).质量是100,所以我不明白为什么它会使它们扭曲.我究竟做错了什么&#xff1f;编辑原始图像为3264px x 2448px谢谢代码&#xff1a;$im ImageCreateF…

Linux命令之 mke2fs -- 格式化分区(为分区写入文件系统)

文章目录简介命令选项参考实例格式化指定的分区简介 在磁盘分区上创建 ext2、ext3、ext4 等文件系统&#xff0c;默认情况下会创建 ext2。 虽然 mkfs 命令非常简单易用&#xff0c;但其不能调整分区的默认参数&#xff08;比如块大小是 4096 Bytes&#xff09;&#xff0c;这…

Linux格式化分区的命令

查看系统所有的文件系统&#xff1a; [~]$ df -ah Filesystem Size Used Avail Capacity iused ifree %iused Mounted on /dev/disk1s5s1 234Gi 15Gi 65Gi 19% 575614 682553320 0% / devfs 190Ki 190Ki 0Bi 100% 658 …

java jwt 验证_教程:用Java创建和验证JWT

java jwt 验证“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕&#xff1f; 尝试使用Okta API进行托管身份验证&#xff0c;授权和多因素身份验证。 Java对JWT&#xff08;JSON Web令牌&#xff09;的支持过去需要进行大量…