Как мне создать 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) {
    }
}
Другие вопросы по тегам