我几乎是一个编程初学者,目前正在尝试使用 JSoup 构建我的第一个网络抓取工具。到目前为止,我能够从目标网站的单个页面获取所需的数据,但我自然希望以某种方式迭代整个网站。
JSoup 似乎为此提供了某种遍历器/访问器(有什么区别?),但我完全不知道如何实现这一点。我知道什么是树和节点,并且知道我的目标站点的结构,但我不知道如何创建(?)一个遍历器/访问者对象(?)并让它在我的站点上运行。难道是有一些我不知道的高级 Java/oo 魔法在起作用?
不幸的是,Jsoup 食谱和其他线程似乎都没有真正涵盖细节,因此,如果有人能够将我推向正确的方向,我将非常感激。
最佳答案
JSoup seems to offer some kind of traverser/visitor (what's the difference?)
NodeTraversor
将有效地迭代指定根节点下并包括指定根节点的所有节点。它不使用递归,因此大的 DOM 不会创建 stackoverflow。
NodeVisitor
(NV) 是 NodeTraversor
的同伴(新界)。 NT 每次进入节点时都会调用 NV 的 head 方法。 NT每次离开节点时,都会调用NV的tail
方法。
NT 已准备好并由 Jsoup API 提供给您。您所要做的就是为 NT 提供 NV 实现。
这是 NodeVisitor 的实际实现,取自 ElasticSearch source code :
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) {
}
}
关于java - 如何使用 JSoup 构建 NodeTraversor/NodeVisitor?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37210487/