我几乎是编程的初学者,目前正在尝试使用JSoup构建我的第一个Web scraper。到目前为止,我能够从目标网站的单个页面获取我想要的数据,但我自然希望以某种方式遍历整个网站。
JSoup似乎提供了某种遍历/访问者(这有什么不同?),但我完全不知道如何做到这一点。我知道树和节点是什么,并知道我的目标网站的结构,但我不知道如何创建(?)traverser / visitor-object(?)并让它在我的网站上运行。在工作中是否有一些先进的Java / oo魔法,我不知道?
不幸的是,Jsoup食谱和其他线程似乎都没有真正涵盖细节,所以如果有人能够朝着正确的方向推动我,我会非常感激。
答案 0 :(得分:2)
JSoup似乎提供某种遍历/访问者(差异是什么?)
NodeTraversor
将有效地遍历指定根节点下的所有节点。它没有使用递归,因此大型DOM不会创建堆栈溢出。
NodeVisitor
(NV)是NodeTraversor
(NT)的伴侣。每次NT进入节点时,它都会调用NV的head
方法。每次NT离开节点时,它都会调用NV的tail
方法。
NT已准备好并由Jsoup API提供给您。您所要做的就是为NT提供NV实现。
以下是从ElasticSearch source code获取的NodeVisitor的实际实现:
protected static String convertElementsToText(Elements elements) {
if (elements == null || elements.isEmpty())
return "";
StringBuilder buffer = new StringBuilder();
NodeTraversor nt = new NodeTraversor(new ToTextNodeVisitor(buffer));
for (Element element : elements) {
nt.traverse(element);
}
return buffer.toString().trim();
}
private static final class ToTextNodeVisitor implements NodeVisitor {
final StringBuilder buffer;
ToTextNodeVisitor(StringBuilder buffer) {
this.buffer = buffer;
}
@Override
public void head(Node node, int depth) {
if (node instanceof TextNode) {
TextNode textNode = (TextNode) node;
String text = textNode.text().replace('\u00A0', ' ').trim(); // non breaking space
if (!text.isEmpty()) {
buffer.append(text);
if (!text.endsWith(" ")) {
buffer.append(" ");
}
}
}
}
@Override
public void tail(Node node, int depth) {
}
}