Search code examples
javajsoupmediawiki-apiwiktionary

How to extract data between two nodes in a wiki page with JSoup?


Document doc = getDocumen("https://pl.wiktionary.org/wiki/set#set_.28j.C4.99zyk_angielski.29");
Elements links = doc.select("dfn[style]"); - ??
for (Element link : links)
{
  link.select("a [href]");
  String linkText = link.text()
}
  • I want to get from "set (język angielski)", all meanings (znaczenia: )
  • The result should be a pair:

      rzeczownik - (1.1) zestaw
      rzeczownik - (1.2) mat. zbiór (lub bez nawiasów)
      ...
      przymiotnik - (2.1) gotowy
      ...
    

Solution

  • Here is how I would try it:

    Document doc = getDocumen("https://pl.wiktionary.org/wiki/set#set_.28j.C4.99zyk_angielski.29");
    Elements elements = doc.select("h2:has(span#en) ~ p:not(h2:has(span#en) ~ p ~ h2 ~ p) i, h2:has(span#en) ~ p:not(h2:has(span#en) ~ p ~ h2 ~ p) + dl > dd");
    if (elements.isEmpty()) {
        throw new RuntimeException("No definitions found.");
    }
    
    String parent = null;
    for (Element element : elements) {
        switch (element.tagName().toLowerCase()) {
        case "i":
            parent = element.text();
            break;
    
        case "dd":
            System.out.println(parent + " - " + element.text());
            break;
    
        default:
            throw new RuntimeException("Unexpected element:\n" + element.outerHtml());
        }
    }
    

    OUTPUT

    rzeczownik - (1.1) zestaw
    rzeczownik - (1.2) mat. zbiór
    rzeczownik - (1.3) elektron. odbiornik, aparat odbiorczy
    rzeczownik - (1.4) film. plan zdjęciowy
    rzeczownik - (1.5) sport. set
    rzeczownik - (1.6) teatr. dekoracja
    rzeczownik - (1.7) tendencja, kierunek
    rzeczownik - (1.8) koteria
    rzeczownik - (1.9) nora borsuka
    rzeczownik - (1.10) masz. agregat
    przymiotnik - (2.1) gotowy
    przymiotnik - (2.2) stały, ustalony
    przymiotnik - (2.3) nieruchomy
    przymiotnik - (2.4) postanowiony
    przymiotnik - (2.5) określony
    czasownik - (3.1) układać, ustawiać
    czasownik - (3.2) nastawiać (kość)
    czasownik - (3.3) prostować
    czasownik - (3.4) przygotowywać
    czasownik - (3.5) powodować
    czasownik - (3.6) o słońcu: zachodzić
    czasownik - (3.7) ustalać
    

    IMO, you should try to find a wiki API. Although the data seems to share the same presentation from page to page, the html code behind it may vary.

    DISCUSSION

    The key of the above code is the CSS query.

    h2:has(span#en) ~ p:not(h2:has(span#en) ~ p ~ h2 ~ p) i, h2:has(span#en) ~ p:not(h2:has(span#en) ~ p ~ h2 ~ p) + dl > dd
    

    This query selects p nodes between two h2 nodes. In order to achieve this goal, here how to do it:

    h2:has(span#en) /* Select the h2 node having the span with id 'en' */
    ~ p /* Select all p nodes preceded by previous selected h2 node... */
    :not(h2:has(span#en) ~ p ~ h2 ~ p) /* ... but ignore any p nodes after the previously selected p nodes */
    

    Tested on JSoup 1.8.3

    EDIT: OP has suggested JWBF (Java Wiki Bot Framework) as a wiki API.