jsoup爬虫教程技巧_Jsoup V的幕后秘密:优化的技巧和窍门
jsoup爬蟲教程技巧
我們已經把事情做好了,現在是時候加快工作速度了。 我們會牢記Donald Knuth的警告:“大約97%的時間我們應該忘記效率低下:過早的優化是萬惡之源”。
根據Jonathan Hedley的介紹,他使用YourKit Java Profiler來測量內存使用情況并找到性能熱點。 使用此類工具的統計結果對于優化的成功至關重要,它將防止您花時間思考和進行無用的調優,這不會提高性能,但也會使代碼不必要地變得復雜且難以維護。 喬納森(Jonathan)在“科隆(Colophon)”中也談到了這一點。
我們將列出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();} }實際上, CharacterReader和StringUtil值得越來越消化,因為有許多有用的提示和技巧會激發您的靈感。
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爬蟲教程技巧
總結
以上是生活随笔為你收集整理的jsoup爬虫教程技巧_Jsoup V的幕后秘密:优化的技巧和窍门的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 收款小精灵电脑版(下载收款小精灵)
- 下一篇: 雅马哈电子琴快捷键(雅马哈电子琴快捷键怎