Как мне создать NodeTraversor/NodeVisitor с помощью JSoup?
Я в значительной степени новичок в программировании, в настоящее время пытаюсь построить свой первый веб-скребок, используя JSoup. Пока что я могу получить нужные данные с одной страницы моего целевого сайта, но, естественно, я бы хотел как-то перебрать весь сайт.
JSoup, кажется, предлагает для этого своего рода посетителя / посетителя (какая разница?), Но я абсолютно не знаю, как заставить это работать. Я знаю, что такое деревья и узлы, и знаю структуру моего целевого сайта, но я не знаю, как создать (?) Объект traverser/visitor-(()) и позволить ему работать над моим сайтом. Может быть, в работе есть какая-то продвинутая магия Java / oo, о которой я не знаю?
К сожалению, ни кулинарная книга Jsoup, ни другие темы, кажется, действительно не охватывают детали, поэтому, если кто-то сможет подтолкнуть меня в правильном направлении, я буду очень благодарен.
1 ответ
JSoup, кажется, предлагает своего рода traverser/ посетителя (какая разница?)
NodeTraversor
будет эффективно перебирать все узлы под указанным корневым узлом и включая его. Он не использует рекурсию, поэтому большой DOM не будет создавать переполнение стека.
NodeVisitor
(NV) является спутником NodeTraversor
(НТ). Каждый раз, когда NT входит в узел, он вызывает head
метод НВ. Каждый раз, когда NT покидает узел, он вызывает tail
метод НВ.
NT уже готова и предоставлена вам с помощью Jsoup API. Все, что вам нужно сделать, это предоставить NT реализацию NV.
Вот реальная реализация NodeVisitor, взятая из исходного кода ElasticSearch:
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) {
}
}