# Mehrere html seiten einer Homepage einlesen und als Textdatei ausgeben



## stylegangsta (23. Aug 2015)

Guten Morgen zusammen,
habe folgendes Problem bzw. Probleme.

Ich möchte die Suchergebnisse, welche über mehere Seiten gehen, aus einer Homepage einlesen und die Daten an der Stelle, wo ich es benötige mit einem ";" trennen. Dies soll dann als Textdatei gespeichert werden, damit ich später in Excel einlesen kann.

Habe den FileWriter an verschieden Stellen im Code ausprobiert, immer nur leere Datei erhalten.

Der Aufbau der Seiten ist so, immer 10 Einträge auf einer Seite:

*Anrede
Titel Name
Arbeitsstätte
Abteilung
Sonderabteilung
Straße
PLZ Ort



 Anfahrt mit Bus und Bahn



 Anfahrt mit dem Auto*

Das Einlesen mit der Jsoup Bibliothek funktioniert auch auf Anhieb, aber nur mit einer einzelnen Seite. Es sind aber insgesamt in diesem Fall 532 Seiten

Der Link sieht so aus:
*https://www.domain.de/xxx/yyyyy/zzzzz.asp?nav=&page=1&ihresuche=*

Es ändert sich nur der Wert hinter page= (Dieser fängt bei 1 an und Endet bei 532)

Und leider werden auch die Zeilen *


 Anfahrt mit Bus und Bahn 


 Anfahrt mit dem Auto *eingelesen und ausgegeben. Wie kann ich es vermeiden, dass diese eingelesen werden oder schaffe ich es, dass die beiden Zeilen durch ein ";" ersetzt werden bei der Ausgabe?

Alle Probleme im Überblick:
Die Suchergebnisseiten von 1 -532 automatisiert einlesen? (Einzeln klappt ja)
An der Stelle, wo ich will ";" einsetzen als Trennzeichen?
Zeilen mit Anfahrt nicht einlesen oder als ";" ausgeben?
In Textdatei speichern?

Vielen Dank im Voraus, Code ist unten

Das ist der Code: Hab den FileWriter wieder entfernt, weil es nicht klappte

```
import java.io.File;
import java.io.IOException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class DatenBankZusammenStellung {

    public static void main(String[] args) {
 
        try {
            // Seite laden
            Document doc = Jsoup.connect("https://xxxxxx/yyyyy/zzzzzz/treffer.asp?nav=&page=1&ihresuche=").get();

            // Alle Listenelemente über den entsprechenden Selektor markieren
            // Ein Leerzeichen initiert ein Kindelement des Elternelementes (links)
            // div#hauptseite-ergeignisse  => Der DIV mit der ID hauptseite-ereignisse (# => id)
            // div.inhalt => Der DIV mit der Klasse inhalt (. => class)
            Elements ereignisse = doc.select("#col1 table:nth-child(4) font");

            // Selektierte Elemente ausgeben ohne HTML-Tags
            for (Element e : ereignisse) {
                System.out.println(e.text());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
```


----------



## Saheeda (24. Aug 2015)

Suchergebnisse automatisiert einlesen:
In einer Schleife den Link zusammenbasteln:


```
for(int i = 1; i<= 532; i++){
    String url = "https://www.domain.de/xxx/yyyyy/zzzzz.asp?nav=&page=" + i + "&ihresuche=";
}
```


Werte ignorieren / ";" setzen:
Eine Möglichkeit wäre Regex. Eine andere, mit string.replaceAll zu arbeiten. Für eine konkretere Aussage wäre es hilfreich, wenn du eine Beispiel-HTML-Datei posten könntest.

Textdatei erstellen:
http://stackoverflow.com/questions/2885173/how-to-create-a-file-and-write-to-a-file-in-java


----------



## stylegangsta (24. Aug 2015)

Saheeda hat gesagt.:


> Werte ignorieren / ";" setzen:
> Eine Möglichkeit wäre Regex. Eine andere, mit string.replaceAll zu arbeiten. Für eine konkretere Aussage wäre es hilfreich, wenn du eine Beispiel-HTML-Datei posten könntest.
> 
> Textdatei erstellen:
> http://stackoverflow.com/questions/2885173/how-to-create-a-file-and-write-to-a-file-in-java



Vielen Dank für deine Antwort. Also, dass mit der Seite automatisch hochblättern hat sich heute im Laufe des Tages erledigt, da die Homepage anscheinend einen Fehler aufweist (Aber auf jeden Fall großen Dank für den Snippet). Denn, egal auf welche Seite man blättert, man hat immer aktuell 337 Suchergebnisse und kann weder vor noch zurück Blättern über Buttons. Sprich die exakte html Seite, die eingelesen werden soll sieht so aus:
https://www.aekno.de/arztsuche/wbbefugteneu/treffer.asp


----------



## stylegangsta (24. Aug 2015)

Saheeda hat gesagt.:


> Textdatei erstellen:
> http://stackoverflow.com/questions/2885173/how-to-create-a-file-and-write-to-a-file-in-java



Einfach nur gepennt, hatte die ganze Zeit Buchstaben verdreht gehabt.


----------



## Saheeda (24. Aug 2015)

EDIT: Nö, geht doch nicht...


----------



## stylegangsta (24. Aug 2015)

Vielen vielen Dank, werde das gleich mal ausprobieren, aber mit den paar JAVA Kenntnissen, die unser möchtegern Dozent (Überschriften vorlesen ohne konkrete Beispiele und Erklärungen ist schon Bitter, und dann das Thema als Erledigt betrachten) uns gezeigt hat, hätte ich das nicht alleine hinbekommen.


----------



## stylegangsta (24. Aug 2015)

Saheeda hat gesagt.:


> EDIT: Nö, geht doch nicht...


Exakt die gleiche Ausgabe wie vorher


----------



## Saheeda (24. Aug 2015)

So, zweiter Versuch.

Ich bin mit der Lösung nicht wirklich glücklich, aber die Seite ist meiner Meinung nach auch nicht so toll aufgebaut:


```
package de.saheeda.siteparser.SiteParser;
package de.saheeda.siteparser.SiteParser;

import java.util.ArrayList;
import java.util.List;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class App {
    public static void main(String[] args) {
        try {
            Document doc = Jsoup.connect(
                    "https://www.aekno.de/arztsuche/wbbefugteneu/treffer.asp")
                    .get();

            Elements table = doc.select("#col1 table:nth-child(4) font");
            List<Address> addresses = new ArrayList<Address>();
            for (int i = 2; i < table.size(); i = i + 3) {

                Element e = table.get(i);
                String text = e.toString();
                String[] data = text.split("\\<.+?\\>");

                addresses.add(new Address(data));
            }

            for (Address a : addresses) {
                System.out.println(a + "\n");
            }

        } catch (Exception e) {

        }
    }

}



public class Address {

    public String salutation;
    public String title;
    public String name;
    public String workPlace;
    public String department;
    public String extraDepartment;
    public String street;
    public String zip;
    public String place;

    public Address(String[] data) {
        this.setSalutation(data);
        this.setTitleAndName(data);
        this.setWorkplace(data);
        this.setDepartment(data);
        this.setStreet(data);
        this.setZipAndPlace(data);
    }

    private void setSalutation(String[] data) {
        this.salutation = data[1].trim();
    }

    private void setTitleAndName(String[] data) {
        String completeName = data[2].trim();
        this.name = completeName
                .split("(Prof. Dr. med.)|(Dr. med.)|(Dr. \\(B\\).)")[1].trim();
        this.title = completeName.replace(this.name, "").trim();
    }

    private void setWorkplace(String[] data) {
        this.workPlace = data[3].trim();
    }

    private void setDepartment(String[] data) {
        this.department = data[4].trim();

        if (data[5].equals("") || data[5].equals(" ")) {
            this.extraDepartment = "";
        } else if (data[6].equals("") || data[6].equals(" ")) {
            this.extraDepartment = "";
        } else {
            this.extraDepartment = data[5].trim();
        }
    }

    private void setStreet(String[] data) {
        if (data[5].equals("") || data[5].equals(" ")) {
            this.street = data[4].trim();

        } else if (data[6].equals("") || data[6].equals(" ")) {
            this.street = data[5].trim();

        } else {
            this.street = data[6].trim();
        }
    }

    private void setZipAndPlace(String[] data) {
        String completePlace = "";
        if (data[5].equals("") || data[5].equals(" ")) {
            completePlace = data[7].trim();

        } else if (data[6].equals("") || data[6].equals(" ")) {
            completePlace = data[8].trim();

        } else {
            completePlace = data[9].trim();
        }
        this.zip = completePlace.split("([A-Z])\\w+")[0];
        this.place = completePlace.split("\\d{5}")[1].trim();
    }

    @Override
    public String toString() {
        return "Address [salutation=" + this.salutation + ", title="
                + this.title + ", name=" + this.name + ", workPlace="
                + this.workPlace + ", department=" + this.department
                + ", extraDepartment=" + this.extraDepartment + ", street="
                + this.street + ", zip=" + this.zip + ", place=" + this.place
                + "]";
    }
}
```


----------



## stylegangsta (28. Aug 2015)

Saheeda hat gesagt.:


> So, zweiter Versuch.
> 
> Ich bin mit der Lösung nicht wirklich glücklich, aber die Seite ist meiner Meinung nach auch nicht so toll aufgebaut:


Hi, vielen Dank für deine Hilfe. Habe leider nur am WE Zeit mich mit dem Code zu beschäftigen. Habe in der class Address diesen Teil geändert

```
@Override
    public String toString() {
        return "Address [salutation=" + this.salutation + ", title="
                + this.title + ", name=" + this.name + ", workPlace="
                + this.workPlace + ", department=" + this.department
                + ", extraDepartment=" + this.extraDepartment + ", street="
                + this.street + ", zip=" + this.zip + ", place=" + this.place
                + "]";
```
in diesen hier

```
public String toString() {
        return this.salutation + ";" + this.title + ";" + this.name + ";"
                + this.workPlace + ";" + this.department
                + ";" + this.extraDepartment + ";"
                + this.street + ";" + this.zip + ";" + this.place + ";";
```
und genau die Ausgabe erreicht, die ich wollte.
Allerdings wird sie nicht als Datei ausgegeben, code kommt gleich nach einem kleinen Einschnitt jetzt

Wie du ja auch schon festgestellt hattest, scheint die Homepage eine Macke zu haben. Und ja die hat sie, denn anstatt errechneten 5.300 und paar gequetschten Einträgen, sind nur 337 im Moment vorhanden. Und diese werden direkt alle mit mit diesem Link angezeigt, habe ich in den Code eingefügt, eingelesen, werden aber dennoch nur die ersten 10 oder vielleicht auch 15 Datensätze
https://www.aekno.de/arztsuche/wbbefugteneu/treffer.asp?nav=

Lange Rede, kurzer Sinn mit nachfolgendem Code sind aktuell zwei Probleme vorhanden:
Es werden nicht alle Datensätze ausgelesen;
Es wird keine Datei angelegt
Code:

```
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class DatenBankZusammenStellung {

    public static void Ausgabe (Elements ereig) throws Exception {

        try (BufferedWriter bw = new BufferedWriter (new FileWriter ("arzt.txt"))) {
            for (Element e : ereig) {
                bw.write(e.text());
            }
        }
    }

         public static void main(String[] args) {
        try {
            Document doc = Jsoup.connect(
                    "https://www.aekno.de/arztsuche/wbbefugteneu/treffer.asp?nav=")
                    .get();

            Elements table = doc.select("#col1 table:nth-child(4) font");
            List<Address> addresses = new ArrayList<Address>();
            for (int i = 2; i < table.size(); i = i + 3) {

                Element e = table.get(i);
                String text = e.toString();
                String[] data = text.split("\\<.+?\\>");

                addresses.add(new Address(data));
            }

            for (Address a : addresses) {
                System.out.println(a + "\n");
            }

        } catch (Exception e) {

        }
    }
}



public class Address {

    public String salutation;
    public String title;
    public String name;
    public String workPlace;
    public String department;
    public String extraDepartment;
    public String street;
    public String zip;
    public String place;

    public Address(String[] data) {
        this.setSalutation(data);
        this.setTitleAndName(data);
        this.setWorkplace(data);
        this.setDepartment(data);
        this.setStreet(data);
        this.setZipAndPlace(data);
    }

    private void setSalutation(String[] data) {
        this.salutation = data[1].trim();
    }

    private void setTitleAndName(String[] data) {
        String completeName = data[2].trim();
        this.name = completeName
                .split("(Prof. Dr. med.)|(Dr. med.)|(Dr. \\(B\\).)")[1].trim();
        this.title = completeName.replace(this.name, "").trim();
    }

    private void setWorkplace(String[] data) {
        this.workPlace = data[3].trim();
    }

    private void setDepartment(String[] data) {
        this.department = data[4].trim();

        if (data[5].equals("") || data[5].equals(" ")) {
            this.extraDepartment = "";
        } else if (data[6].equals("") || data[6].equals(" ")) {
            this.extraDepartment = "";
        } else {
            this.extraDepartment = data[5].trim();
        }
    }

    private void setStreet(String[] data) {
        if (data[5].equals("") || data[5].equals(" ")) {
            this.street = data[4].trim();

        } else if (data[6].equals("") || data[6].equals(" ")) {
            this.street = data[5].trim();

        } else {
            this.street = data[6].trim();
        }
    }

    private void setZipAndPlace(String[] data) {
        String completePlace = "";
        if (data[5].equals("") || data[5].equals(" ")) {
            completePlace = data[7].trim();

        } else if (data[6].equals("") || data[6].equals(" ")) {
            completePlace = data[8].trim();

        } else {
            completePlace = data[9].trim();
        }
        this.zip = completePlace.split("([A-Z])\\w+")[0];
        this.place = completePlace.split("\\d{5}")[1].trim();
    }

    @Override
    public String toString() {
        return this.salutation + ";" + this.title + ";" + this.name + ";"
                + this.workPlace + ";" + this.department
                + ";" + this.extraDepartment + ";"
                + this.street + ";" + this.zip + ";" + this.place + ";";
    }
}
```


----------



## Saheeda (28. Aug 2015)

Hm, ich denke, die Seite wird gerade überarbeitet. Dass alle Einträge auf einer Seite angezeigt werden, fiel mir auch beim ersten Versuch auf. Als ich es gerade eben probierte, funktionierte das Paging im Ansatz: Die Buttons verschwinden, aber über die URL lassen sich mehr Einträge finden.

Wie sieht denn dein Ansatz zum Erstellen der Datei aus?


----------



## stylegangsta (28. Aug 2015)

Dass mit dem Paging ist mir auch aufgefallen, aber wenn ich page 40 oder so eingebe, erscheinen wieder alle 337.
Der Dateiansatz ist in dem code im vorheirgen Beitrag über der Main


----------



## Saheeda (31. Aug 2015)

Mal doof gesagt: Wenn die Seite rumzickt bzw. die Datenbereitstellung nicht funktioniert, lässt sich nicht viel machen.
Ich habe gerade bis Seite 55 probiert und bekomme > 500 Ergebnisse angezeigt:
https://www.aekno.de/arztsuche/wbbefugteneu/treffer.asp?nav=&page=55&ihresuche=


Auch das Problem mit dem Schreiben kann ich leider nicht nachvollziehen. Mir fällt höchstens auf, dass du die Methode überhaupt nicht aufrufst und auch nicht mit den geparsten Address-Objekten arbeitest, sondern mit den Jsoup-Elementen.
Ansonsten: Methode aufrufen und es wird eine Datei erstellt und befüllt.


----------



## stylegangsta (31. Aug 2015)

Saheeda hat gesagt.:


> Mal doof gesagt: Wenn die Seite rumzickt bzw. die Datenbereitstellung nicht funktioniert, lässt sich nicht viel machen.
> Ich habe gerade bis Seite 55 probiert und bekomme > 500 Ergebnisse angezeigt:
> https://www.aekno.de/arztsuche/wbbefugteneu/treffer.asp?nav=&page=55&ihresuche=


Was mich betrifft habe ich es gestern 1 x und dann nie wieder geschafft wirklich 5300 und paar gequetschte Ergebnisse anzuzeigen.



Saheeda hat gesagt.:


> Auch das Problem mit dem Schreiben kann ich leider nicht nachvollziehen. Mir fällt höchstens auf, dass du die Methode überhaupt nicht aufrufst und auch nicht mit den geparsten Address-Objekten arbeitest, sondern mit den Jsoup-Elementen.
> Ansonsten: Methode aufrufen und es wird eine Datei erstellt und befüllt.



Doch die geparsten Address Objekte sind alle unverändert außer den Eckigen Klammern mit den Wörtern drin. Die habe ich entfernt und genau die Ausgabe bekommen, die für Excel notwendig ist. Der Buffered Writer war die ganze Zeit schon da oben und hat immer funktioniert, aber ein Kollege meinte, dass es sein kann, dass der evtl. versucht die Datei schneller zu schreiben, als wie die Daten eingelesen werden können und ich solle einen Timer oder so einsetzen. Als ob ich so ein Profi bin???

Ende vom Lied ist, dass es für jedes Bundesland eine eigene Ärztekammer gibt und ich mich, so lange die Seite von der NRW Ärztekammer nicht vernünftig läuft, ab morgen mit den anderen beschäftigen werde. Die Aufgabe die Daten auszulesen hat meine aktuelle Doku Aufgabe ersetzt. Also bin ich jetzt auch in der Woche da dran. Aber ich kann mich nur immer wieder bei dir bedanken, für deine Mühe und auch Zeit, die du investiert hast.

P.S.: Die Aufgabe, die NRW Seite irgendwie auszulesen hat auch mittlerweile das Interesse meiner Kollegen geweckt. Scheint ansteckend zu sein.


----------



## Saheeda (31. Aug 2015)

Hi,

zur Dateigröße habe ich das hier gefunden:
http://jmchung.github.io/blog/2013/10/25/how-to-solve-jsoup-does-not-get-complete-html-document/

Asynchronität ist ein häufiges Problem bei Webseiten.
Wenn du Bedenken hast, dass die Daten eventuell nicht vollständig geladen werden, kannst du auch vorm Bearbeiten  ein Thread.sleep($Zeitspanne) einbauen. Damit wartest du einen kleinen Moment, bevor die Seite ausgelesen wird. Ich würde es danach einbauen und sehen, ob es eine Verbesserung ist, oder nur unnötig Zeit kostet: 
Document doc = Jsoup
                    .connect(
                            "https://www.aekno.de/arztsuche/wbbefugteneu/treffer.asp?nav=")
                    .get();

Im Beitrag #9 oben sind übrigens Einlesen und Schreiben getrennt. IMHO ist es besser, erstmal alle Daten zu sammeln und zu verarbeiten, bevor geschrieben wird.
Vorteil: Die Verbindung bleibt nur so lange offen, wie unbedingt notwendig.
Bei größeren Datensätzen könnte man auch überlegen, gestaffelt zu arbeiten, z.B. alle 1000 Einträge die Verbindung schließen, alles, was bisher gelesen wurde verarbeiten, schreiben und von vorn. So landet nicht so viel im Zwischenspeicher.


----------



## stylegangsta (31. Aug 2015)

Hi Saheeda,

ich habe zwar von der Logik her verstanden, was da passieren soll, aber zwecks der Umsetzung in den Programmcode übersteigt es bei Weitem was wir gelernt haben. (Ich sage immer:"Das Einzige was wir bei Dozenten richtig gelernt haben und Blind schreiben können ist die Hello World Ausgabe über sysout.")
Ich werde mich aber morgen mal in Ruhe mit deinem Geschriebenen auseinandersetzen. Würde ich am liebsten jetzt schon, bin aber seit gestern 09:30 mit 2 Stunden Schlaf ohne kaum was gegessen zu haben auf den Beinen.
Ich werde dich aber hier über das Thema auf dem laufenden halten bzw. zeigen was ich hinbekommen habe oder auch nicht.

Wünsche dir für Heute jedenfalls noch einen angenehmen Abend.


----------

