Java深度网页爬虫开发问题:无法实现深度2爬取逻辑
Java深度爬虫无法完成深度2爬取的问题排查与修复
问题分析
你的代码无法完成深度2爬取的核心原因有以下几点:
- 全局链接集合混用:
urlLinks是全局集合,深度0、1的所有链接都存在这里,导致爬深度2时会重复处理低深度的链接,且无法精准获取深度1页面提取的新链接。 - 深度2爬取逻辑错误:
twoDepthCrawling只是调用oneDepthCrawling后遍历整个urlLinks下载,没有针对每个深度1的页面单独提取链接并爬取深度2的页面。 - 链接计数逻辑错误:
getUrls中counter <= amountOfUrls会提取amountOfUrls + 1个链接,不符合单页最大URL数量的要求。 - 未实现跨层级URL唯一逻辑:
isUnique参数未被使用,无法控制跨层级的URL去重。 - 方法耦合严重:各深度方法互相调用,导致低深度逻辑重复执行,流程混乱。
修复方案
重构代码,按深度分层存储链接,明确每个深度的爬取流程,同时修复计数和去重逻辑:
1. 调整成员变量
用分层集合存储各深度的待爬链接,同时维护全局去重集合(用于isUnique参数):
private String initialUrl; private int amountOfUrls; private Depth maxDepth; private boolean isUnique; // 按深度存储待爬链接,index对应深度值 private List<List<String>> depthUrlList = new ArrayList<>(); // 全局去重集合 private Set<String> uniqueUrlSet = new HashSet<>();
2. 重构爬取入口方法
public void crawlWebPages() { // 初始化深度0的链接 depthUrlList.add(new ArrayList<>()); depthUrlList.get(0).add(initialUrl); for (int currentDepth = 0; currentDepth <= maxDepth.ordinal(); currentDepth++) { List<String> currentUrls = depthUrlList.get(currentDepth); // 下载当前深度的所有页面 for (String url : currentUrls) { downloadHtml(url, Depth.values()[currentDepth]); System.out.println(url + " downloaded at depth " + currentDepth); } // 如果不是最大深度,提取下一层级的链接 if (currentDepth < maxDepth.ordinal()) { depthUrlList.add(new ArrayList<>()); for (String url : currentUrls) { List<String> nextLevelUrls = extractUrls(url); // 处理去重逻辑 for (String nextUrl : nextLevelUrls) { if (!isUnique || !uniqueUrlSet.contains(nextUrl)) { depthUrlList.get(currentDepth + 1).add(nextUrl); uniqueUrlSet.add(nextUrl); } } } } } }
3. 修复URL提取方法
private List<String> extractUrls(String url) { List<String> extractedUrls = new ArrayList<>(); int counter = 0; try { Document doc = Jsoup.connect(url).get(); Elements availableLinksOnPage = doc.select("a[href]"); for (Element element : availableLinksOnPage) { String absUrl = element.absUrl("href"); // 跳过空链接或无效链接 if (absUrl.isEmpty() || !absUrl.startsWith("http")) { continue; } // 达到单页最大数量就停止 if (counter >= amountOfUrls) { break; } extractedUrls.add(absUrl); counter++; } } catch (IOException e) { throw new RuntimeException("couldn't fetch links from " + url, e); } return extractedUrls; }
4. 调整构建器与初始化
确保构建器正确初始化成员变量:
private HtmlHandler(Builder builder) { this.initialUrl = builder.url; this.amountOfUrls = builder.amountOfUrls; this.maxDepth = builder.depth; this.isUnique = builder.isUnique; } public static Builder builder() { return new Builder(); } public static class Builder { private String url; private int amountOfUrls; private Depth depth; private boolean isUnique; public Builder url(String url) { this.url = url; return this; } public Builder amountOfUrls(int amountOfUrls) { this.amountOfUrls = amountOfUrls; return this; } public Builder depth(Depth depth) { this.depth = depth; return this; } public Builder isUnique(boolean isUnique) { this.isUnique = isUnique; return this; } public HtmlHandler build() { return new HtmlHandler(this); } }
5. 保留原有的downloadHtml方法
private void downloadHtml(String url, Depth depth) { try { FileUtils.copyURLToFile(new URL(url), new File(StringHandler.createFileName(url, depth))); } catch (IOException e) { throw new RuntimeException("error downloading html source file for " + url, e); } }
修复后的效果
- 深度0:下载初始URL,提取5个链接存入深度1集合
- 深度1:下载5个URL,每个提取5个链接,总计25个链接存入深度2集合(如果
isUnique为true会自动去重) - 深度2:下载25个URL,完成后结束程序
内容的提问来源于stack exchange,提问作者kidulf
相关产品推荐
相关产品推荐

