Websites downloaden (URLConnection etc.)

sirstefan

Mitglied
Guten Abend,

ich versuche mittels Java den Download von Webseiten zu realisieren. Hierfür bin ich auf die Klasse URLConnection gestoßen. Mit dieser Klasse habe ich auch schon eine Lösung geschrieben:
Code:
try{
	adresse = new URL(url);
	schreiben = new FileOutputStream(dateiname);
	verbindung = adresse.openConnection();
	lesen = verbindung.getInputStream();
	groesse = verbindung.getContentLength();
}
Das funktioniert auch schon ganz gut. Probleme gibt es, falls zwischen der Verbindung noch ein Proxy-Server liegt.
Code:
	catch(Exception e){
		Properties sysProps = System.getProperties();
		sysProps.put("proxyHost", "193.170.8.36");
		sysProps.put("proxyPort", "3128");
		String login = "xyz:zyx";
		verbindung.setRequestProperty("Proxy-Authorization", "Basic " + login);
		try{
			adresse = new URL(url);
			schreiben = new FileOutputStream(dateiname);
			verbindung = adresse.openConnection();
			lesen = verbindung.getInputStream();
			groesse = verbindung.getContentLength();
		}
Der Download wird mittels einer JProgressBar in einer anderen Klasse angezeigt und läuft so ab:
Code:
public void download(){
	Thread t = new Thread(new Runnable(){
		byte zeichen = 0;
		public void run(){
			try{
				while(zeichen != -1){
					zeichen = (byte)lesen.read();
					if(zeichen != -1){
						quellcode += (char)zeichen;
						schreiben.write((char)zeichen);
					}
				    progress++;
				    //System.out.println(progress + ", " + groesse);
				    Thread.sleep(1);
				}
			}	
			catch(Exception e){
				e.printStackTrace();
			}
			finally{
				try{
					lesen.close();
					schreiben.close();
				}
				catch(IOException e){
					e.printStackTrace();
				}
			}
		}
	});
	t.start();
}

Die Lösung funktioniert derweil, nur gibt es folgende Probleme:
1) Der Download ist SEHR langsam
2) Manchmal kommt über die Größe der Datei nichts brauchbares zurück (Wert = -1), daher gibt es keine Informationen über den Fortschritt. Für diesen Fall habe ich die JProgressBar auf setIndeterminate(true) gesetzt. Da aber die Downloadgeschwindigkeit klein ist, weiß der Benutzer jetzt überhaupt nichts über den Fortschritt und das will ich vermeiden.
3) Ich komme nicht durch den Proxy.

Jetzt habe ich eben Fragen, die die Probleme betreffen. Gibt es andere Möglichkeiten, den Code so ähnlich zu realisieren und falls ja, würde ich mich über Hilfe sehr freuen.

Grüße und frohe Festtage,
Stefan
 
Ich versuche mich hineinzuarbeiten, aber wenn ich den im Tutorial entstandenen Sourcecode ausführen will, kommt folgende Fehlermeldung:
Code:
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory
	at org.apache.commons.httpclient.HttpClient.<clinit>(HttpClient.java:66)
	at Test.main(Test.java:13)
Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
	at java.net.URLClassLoader$1.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClass(Unknown Source)
	at java.lang.ClassLoader.loadClassInternal(Unknown Source)
	... 2 more
...d.h. anscheindend, dass er die Klasse LogFactory nicht findet. Das ist mir ein Rätsel, weil ich mir sicher bin, das Paket richtig eingebunden zu haben. Wenn ich aber nicht einmal ein HttpClient-Objekt erstellen kann, kann ich die Sache doch gleich vergessen...
 
Zuletzt bearbeitet:
Lies doch mal bitte die Fehlermeldung genau! In welcher Bibliothek ist wohl org.apache.commons.logging enhalten? Richtig - in commons-logging. Wenn du kein vernünftiges Dependencymanagement (Maven/Ivy) verwendest musst du dich schon selbst darum kümmern, dass Abhängigkeiten in deinem Classpath aufgelöst werden können.

Eigentlich brauchen fast alle COmmons Bibliotheken mindestens noch commons-logging im Classpath.

Gruß
Ollie

Edit: Im Download liegt eine Maven Site im docs Verzeichnis. Da gibt es eine Seite Dependencies auf der du detailliert aufgeschlüsselt findest, welche Drittbibliotheken du benötigst (commons-codec brauchst du sicher nur, wenn duVerschlüsselungsoperationen benötigst, Junit ist test scope, brauchst du also nicht). In einem Maven POM reichen folende Zeilen:

XML:
<dependency>
  <groupId>commons-httpclient</groupId>
  <artifactId>commons-httpclient</artifactId>
  <version>3.1</version>
</dependency>
 
Zuletzt bearbeitet von einem Moderator:
Sorry war wohl gestern geistig etwas abwesend so spät am Abend, außerdem befinde ich mich hier auf Neuland weil ich noch nie externe Bibliotheken eingebunden habe.

Gefehlt hat übrigens neben der logging- noch die codec-Bibliothek.

Ich werd jetzt mal versuchen das ganze näher kennenzulernen und danke dir für deine Hilfe.
 
Ich habe jetzt das Herunterladen realisieren können und bin beim Update der JProgressBar. Nur habe ich wieder das Problem mit einem ungültigen Wert der Größe der Datei, das heißt GetMethod.getResponseContentLength() gibt -1 zurück und das so ziemlich immer.

Habe hier mal die relevanten Methoden herausgenommen:
Code:
public Seite(String url, String dateiname){
		this.url = url;
		client = new HttpClient();
		verbindung = new GetMethod(this.url);
		progress = 0;
		this.dateiname = dateiname;
		System.out.println(dateiname);
		verbindung.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false));
		groesse = (int)verbindung.getResponseContentLength();
		System.out.println(groesse);
		try{
			client.executeMethod(verbindung);
			lesen = verbindung.getResponseBodyAsStream();
			schreiben = new FileOutputStream(dateiname);
		}
		catch(IOException e){
			e.printStackTrace();
		}
		fertig = false;
	}
---------------------------------------------------------------------------------------
        public void download(){
		Thread t = new Thread(new Runnable(){
			byte zeichen = 0;
			public void run(){
				try{
					lesen = verbindung.getResponseBodyAsStream();
					while(zeichen != -1){
						progress++;
						zeichen = (byte)lesen.read();
						schreiben.write((char)zeichen);
						Thread.sleep(1);
			      	}
				}	
				catch(Exception e){
					e.printStackTrace();
				}
				finally{
					try{
						lesen.close();
						schreiben.close();
					}
					catch(IOException e){
						e.printStackTrace();
					}
				}
			}
		});
		t.start();
---------------------------------------------------------------------------------------
	public void createBar(JProgressBar fortschritt){
		fortschritt.setStringPainted(true);
		fortschritt.setMinimum(0);
		if(groesse == -1){
			fortschritt.setIndeterminate(true);
			fortschritt.setStringPainted(false);
			fortschritt.setMaximum(100);
		}
		else{
			fortschritt.setMaximum(groesse);
		}
	}
	public void updateBar(JProgressBar fortschritt){
		fortschritt.setValue(progress);
	}

Aufgerufen werden diese in einer anderen Klasse:

Code:
if(e.getSource() == button[3]){
	seite.createBar(fortschritt);
	seite.download();
	Thread t = new Thread(new Runnable(){
		public void run(){
			while(seite.fertig == false){
				seite.updateBar(fortschritt);
				try{
					Thread.sleep(1);
				}
				catch(Exception e){
					e.printStackTrace();
				}
				if(fortschritt.getValue() == seite.getGroesse()){
					break;
				}
			}
		}
	});
	t.start();
	if(fortschritt.isIndeterminate() == true){
		fortschritt.setIndeterminate(false);
		fortschritt.setStringPainted(true);
		fortschritt.setValue(100);
	}

Bitte sagt mir, was ich ändern soll. Bei meinem alten Code kam nicht IMMER -1 zurück sondern durchaus etwas brauchbares.
 
Da hast du als Client leider keinen Einfluss drauf. Sowas passiert, wenn der Server nicht sauber gestrickt ist. In einem meiner letzten Projekt mussten wir auf der Serverseite auch explizit die Contentlength setzen, da sonst der Client u.a. hässliche Warnings nach StdErr schreibt. Hast du die Serverseite auch unter Kontrolle?

Gruß
Ollie

PS: Arbeiten über Weihnachten is mies ;).
 
Hast du die Serverseite auch unter Kontrolle?
Nein

Na gut, dann werd ich mich ein bisschen mit setIndeterminate und der Proxykonfiguration rumspielen. Danke nochmal für die Hilfe.

PS: Arbeiten über Weihnachten is mies ;).
Ja

EDIT: Anscheinend ist der tutorials.de-Server auch nicht sauber gestrickt. Dort kommt als Wert auch -1 zurück :p

EDIT: Und weil ich so einsam bin, will ich die Lösung nicht vorenthalten:
Code:
protected Thread t;
	public void download(){
		t = new Thread(new Runnable(){
			byte zeichen = 0;
			public void run(){
				try{
					while(zeichen != -1){
						progress++;
						zeichen = (byte)lesen.read();
						schreiben.write((char)zeichen);
						Thread.sleep(1);
			      	}
				}	
				catch(Exception e){
					e.printStackTrace();
				}
				finally{
					try{
						lesen.close();
						schreiben.close();
					}
					catch(IOException e){
						e.printStackTrace();
					}
				}
			}
		});
		t.start();
		//verbindung.releaseConnection();
	}
	protected boolean threadAlive(){
		return t.isAlive();
	}
----------------------------------------------------------------------------------
public void createBar(JProgressBar fortschritt){
		fortschritt.setStringPainted(true);
		fortschritt.setMinimum(0);
		if(groesse == -1){
			groesse = 100;
			fortschritt.setIndeterminate(true);
			fortschritt.setStringPainted(false);
			fortschritt.setMaximum(100);
		}
		else{
			fortschritt.setMaximum(groesse);
		}
	}
Aufruf

Code:
if(e.getSource() == button[3]){
	download = true;
	seite = new Seite(url, dateiname(url));
	seite.createBar(fortschritt);
	seite.download();
	final Thread t = new Thread(new Runnable(){
		public void run(){
			while(seite.fertig == false){
				seite.updateBar(fortschritt);
				try{
					Thread.sleep(1);
				}
				catch(Exception e){
					e.printStackTrace();
				}
				if(fortschritt.isIndeterminate() == false){
					if(fortschritt.getValue() == seite.getGroesse()){
						break;
					}
				}
				else{
					if(seite.threadAlive() == false){
						if(fortschritt.isIndeterminate() == true){
							fortschritt.setIndeterminate(false);
							fortschritt.setStringPainted(true);
							fortschritt.setValue(100);
						}
					}
				}
			}
		}
	});
	t.start();

Frohes Fest etc.
 
Zuletzt bearbeitet:
Hallo,

bevor ich einen neuen Fred erstelle, schreibe ich lieber hier rein. Und zwar möchte ich anmerken, dass ich jetzt bemerkt habe, dass der Download doch nicht so schnell abläuft wie ich mir eigentlich gedacht (und vorgestellt habe). Nachdem ich gleich gegoogelt habe, fand ich heraus, dass eine höhere Geschwindigkeit nicht möglich sei, und genau das möchte ich hier hinterfragen. Kennt jemand eine Möglichkeit, die Geschwindigkeit hinaufschnalzen zu lassen?
Eine Geschwindigkeit von rund 1kB/s (mitgestoppt) erinnert zwar sehr an die alten Zeiten, ist aber dennoch etwas unvorteilhaft. Abgesehen davon bleibt er manchmal bei Downloads stehen ohne weiterzumachen (...und über den Proxy komm ich noch immer nicht).
 
Zurück