Daten von einer passwortgeschützten URL auslesen

Hallo,

anstatt Informationen von einer Website wöchentlich per Hand abzutippen, wollte ich mir ein kleines Programm schreiben, das das für mich übernimmt. Das Problem ist allerdings, dass die Website passwortgeschützt ist.
Ich scheitere nun daran, die Benutzerdaten an die URL zu übergeben.

Als Beispiel diene die Seite der abonnierten Beiträge hier in der byte-welt. (Es ist nicht diese Seite, von der ich die Daten lesen möchte, die Symptome sind hier allerdings die gleichen.)

Bisherige Suchanfragen haben mich immer wieder auf die beiden unten dargestellten Lösungsansätze geleitet, die bei mir aber nicht greifen. Anstatt, dass Benutzername und Passwort übergeben werden, werde ich immer auf die Seite weitergeleitet, bei der man die Login-Daten eingeben soll.

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;

public class TestParser {

	private final static String username = "username";
	private final static String password = "password";
	private final static String urlText = "http://forum.byte-welt.net/subscription.php?do=viewsubscription&folderid=all";

	private static void parse(URL url) {
		try {
			URLConnection uc = url.openConnection();
			setBasicAuthentication(uc);
			uc.connect();
			InputStream in = uc.getInputStream();
			read(new InputStreamReader(in, "utf8"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private static void read(InputStreamReader in) throws IOException {
		BufferedReader reader = new BufferedReader(in);
		for (String line; (line = reader.readLine()) != null;) {
			if (line.contains("Du bist nicht angemeldet"))
				System.out.println(line);
		}
		in.close();
		reader.close();
	}
	
	private static void setBasicAuthentication(URLConnection uc) {
		String userpass = username + ":" + password;
		String basicAuth = "Basic "
				+ javax.xml.bind.DatatypeConverter.printBase64Binary(userpass.getBytes());
		uc.setDoInput(true);
		uc.setRequestProperty("Authorization", basicAuth);
	}
	
	private static void setAuthenticator() {
		Authenticator.setDefault(new Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
				return new PasswordAuthentication(username, password.toCharArray());
			}
		});
	}

	public static void main(String[] args) {
		setAuthenticator();
		try {
			URL url = new URL(urlText);
			parse(url);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	}
}

Sowohl der Aufruf von setBasicAuthentication(uc) (Zeile 20) als auch der Aufruf von setAuthenticator() (Zeile 56) erreichen nicht das erwünschte Ergebnis.

Username und Passwort sind natürlich die korrekten, das habe ich mehrfach überprüft.:wink:

Ich würde mich freuen, wenn mir jemand helfen könnte, wie ich per Java Programm Benutzernamen und Passwort korrekt an eine URL übergeben kann.

LG
eitelkalk

ist das

  1. eine html-formularbasierte

oder

  1. eine über HTTP-Auth basierte

Benutzername/Passwort-Abfrage?

Erkennst du daran, ob ein kleines Pop-Up-Fenster aufgeht (2) oder ob du auf einer Webseite in ein Textfeld was eintippen musst (1).

Im Fall von 1) musst du anders arbeiten, nämlich einen POST-Request vorher an die Webseite schicken etc.

Es ist eine (1) html-formularbasierte Abfrage.

Okay, dann werde ich mich dazu mal informieren. Ich melde mich dann, wenn ich entweder nicht weiter komme oder alles funktioniert. :slight_smile:

Danke schon einmal!

[ul]
[li]Schaue Dir den Quelltext der Loginseite an, entweder mit „Quelltext anzeigen“ oder mit einem entspr. Browserplugin.[/li][li]Suche das form-Element. In dessen action-Attribut findest Du die aufzurufende URL. Im method-Attribut die HTTP-Methode (höchst wahrscheinlich POST)[/li][li]Suche die input-Elemente für Username/Passwort. Ihre namen/ids sind die Namen der Parameter. Die Werte halt Deine Logindaten.[/li][/ul]

Danke @nillehammer , gerade der Tipp, was die Namen der Parameter sind, hat mir sehr gut weitergeholfen.

So ganz bekomme ich aber noch nicht das gewünschte Ergebnis, wahrscheinlich fehlt es am Verständnis des großen Ganzen.

Ich verstehe zum Beispiel noch nicht so richtig, mit welcher URL ich arbeiten muss. Ich habe zum einen die url1, von der ich die Daten auslesen möchte. Diese leitet mich (uneingeloggt) automatisch an url2 weiter, die die Form https://blabla/login?ReturnURL=url1 hat.

Führe ich meinen Code mit url1 aus, wird mir “Object moved to <url2>” ausgegeben.
Ich habe ihn deshalb mit url2 ausgeführt und scheine mich auch einloggen zu können. Gebe ich nämlich ein falsches Passwort ein, kommt die Meldung, dass das Passwort falsch ist und in der Textbox des Benutzernamens steht noch der Name. Das Posten scheint also zu funktionieren.
Gebe ich allerdings die richtige Benutzername/Passwort Kombination ein, wird mir wieder die url2-Seite ausgegeben, ich werde nicht zur url1 weitergeleitet.

Wie kann ich erreichen, dass ich zu url1 weitergeleitet werde?

	private static void parse(URL url) throws IOException {
		String charset = "UTF-8";
		String paramUsername = "userTextBox";
		String paramPassword = "passwortTextBox";

		String query = paramUsername + "=" + URLEncoder.encode(username, charset) + "&"
				+ paramPassword + "=" + URLEncoder.encode(password, charset);

		URLConnection connection = url.openConnection();
		connection.setDoInput(true);
		connection.setDoOutput(true);
		connection.setRequestProperty("Accept-Charset", charset);
		connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset="
				+ charset);

		OutputStream output = connection.getOutputStream();
		output.write(query.getBytes(charset));
		output.close();

		read(new InputStreamReader(connection.getInputStream(), charset)); //Ausgabe
	}

Vielen Dank nochmal an euch beide!

LG
eitelkalk

Verwende lieber eine Bibliothek für so was, das kann schnell ziemlich kompliziert werden:

das Mistvieh am anderen Ende merkt sich nämlich, dass du “identifiziert” bis (also richtige user/pass-Kombination per POST geschickt hast)

aber dann?

dann setzt er einen Cookie

oder

leitet dich an eine andere Seite weiter und behält das geheimnis in der url (z.B. seiteblabla.php?sid=adf3q2345aa)

oder

per url-rewriting (/supersex/adf3q2345aa/start)

oder oder…

Das “merken” der Client-Authentifizierung kann auf vielerlei Arten geschehen, das kannst du wahrscheinlich nicht so ohne weiteres ausprogrammieren.

http://hc.apache.org/httpcomponents-client-4.3.x/index.html

Mach den Vorgang, der nachher von Deinem Programm automatisch ausgeführt werden soll einmal manuell. Schaue Dir dabei an, welche URLs in der Adressleiste des Browsers auftauchen. Oder noch besser, beobachte die Requests/Respones mit einem Tool wie Wireshark oder einem entspr. Browserplugin. Voraussichtlich wird es in etwa so aussehen:
[ol]
[li]Aufruf der URL Loginseite → GET. Dieser Schritt kann evtl. beim Programm entfallen, wenn Du direkt den Login (2.) machen kannst.[/li][li]Senden der Logindaten an die Login-URL → POST. Oft ist dies die gleiche wie die URL zum Aufruf der Loginseite, hängt davon ab, wie die Betreiber es programmiert haben.[/li][li]Bei korrekter Eingabe der Logindaten bekommst Du i.d.R. als Response einen sog. Redirect. Dort steht die URL drinnen, die einen Browser-Nutzer auf den geschützten Bereich weiterleitet (redirectet). Die kannst du i.d.R. auch ignorieren, denn hier kannst Du direkt die URL aufrufen, die die Daten liefert, die Du auslesen möchtest.[/li][li]Aufruf zur URL der Seite mit den Daten, die Du auslesen möchtest[/li][/ol]
Bei dem ganzen Flow der Aufrufe muss der Server sich merken, dass du bereits eingeloggt bist. Dafür hält der Server für Dich eine sog. Session. Diese hat eine ID, die der Server Dir nach erfolgreichem Login einmal schickt. Danach muss sie vom Client (also Deinem Programm) bei jedem Request mitgesendet werden. Einige Details dazu hat Bleiglanz ja schon geschrieben.

Genau das macht er bei mir.

Per CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL)); am Anfang des Programms konnte ich die Cookies zulassen und nach erfolgreichem Login kann ich jetzt jede beliebige geschützte Unterseite aufrufen. Zum Glück war’s so einfach :slight_smile:

Nochmals einen ganz herzlichen Dank an euch beide, ihr habt mir sehr geholfen! Ich denke, ich habe jetzt eine ganze Menge mehr verstanden.
::manklatsch

LG
eitelkalk