Html Code einlesen, Speicherüberlauf? Zuviel Code?

Kumaro

Mitglied
Guten Abend :),

ich habe ein kleines Problem und trotz intensiver Suche und probierens finde ich keine Lösung daher hoffe ich auf eure hilfe:

Ich bin dabei ein tool zu schreiben was einen link bekommt und dann die daten der website als String
einliest. Das klappt alles auch soweit ganz gut.

Jetzt ist es aber so dass mehrere Seiten (links) direkt hintereinander in einer schleife eingelesen werden müssen und genau DA ist das Problem.

Lass ich nur einen Link einlesen klappt alles wie es soll. Lass ich zwei links einlesen macht er mit dem ersten was er soll und dann steht das Programm....entweder dauert es seeeeehr lange oder es tut sich nichts mehr (was es genau ist kann ich leider nicht sagen) :(.

Das ist der CodeAusschnitt

Java:
/**Scanning First SensorSites to get HTML Format**/

WebsiteScanner sensorScanner = new WebsiteScanner(htmlCodeSensor, linkAfterString);

//anzahl der links
arrayLength = sensorScanner.getHtmlFormat().length;
			
	String[] htmlSensorLinks = new String[arrayLength];
	      for(int i=0; i < arrayLength ; i++){
		
                       //holt sich von einer anderen Seite die links die er durchsuchen soll
                        htmlSensorLinks[i] = sensorScanner.getHtmlFormat()[i];
				}



/**Scanning SensorSites with Data**/
	
//startet die instanz des Readers der die Methode enthält die den html code einliest
WebsiteReader dataSite = new WebsiteReader();

//String Array welches die html Codes die eingelesen wurden aufnehmen soll 	
String[] htmlCodeDataSite = new String[arrayLength];
	
             //durchläuft die anzahl der vorhandenen links die eingelesen werden sollen
	for(int i=0; i < arrayLength; i++){
	               
                             //liest die seiten hinter den links ein
                             htmlCodeDataSite[i] = dataSite.getStrFromUrl(htmlSensorLinks[i]);
		
                   //durchsucht den html code nach den wichtigen daten...			
                   WebsiteScanner sensorDataScanner = new WebsiteScanner(htmlCodeDataSite[i], dataStartTag, dataEndTag, timeStartTag, timeEndTag);
	    
                    //...und erzeugt eine arrayList mit den wichtigen daten in dieser Methode
                    sensorDataScanner.scanForSensorData();
				}

Wenn ich den unteren Teil, also die schleife nur bis 1 laufen lasse klappt alles super, sobald er das für mehrere nacheinander machen soll ist es vorbei und ersteht ...

Woran kann das liegen? Zwar sind es jeweils immer mehr als 120.000 Zeilen aber der Speicher kann ja wohl kaum voll sein oder?

Was kann ich machen?

Sorry, ich hoffe ich konnte mich verständlich genug ausdrücken ^^...

Ich hoffe sehr auf eure Hilfe.

vielen Dank im voraus
 
Gibt es Fehlermeldungen? Schau mal in deinen Prozess-Manager/Task-Manager, ob dein Programm sehr viel Speicher oder Rechenlast frisst. Wenn ja, kannst du mit Hilfe von VisualVM herausfinden, warum das so ist. Dein Code-Ausschnitt ist leider sehr kurz, so dass man darin kaum Fehler finden kann.
Eine HTML-Datei mit 120.000 Zeilen (sic!) habe ich noch nicht gesehen – die wäre ja wahrscheinlich mehrere (zig) MB groß. wenn du diese tatsächlich in String-Objekte zerlegst, dürftest du schon einige hundert MB Speicherauslastung ansammeln.
 
Hunterte ist vllt. etwas zu viel, aber unabhängig vom RAM hat die VM ja auch ihre eigene Speichergrenze. Da müsste aber eine Meldung kommen...

Aber 120000 HTML-Zeilen würden mich auch interessieren :D
 
Gut ... selbst wenn wir eine Link-Liste mit durchschnittlich 30 bis 50 Zeichen pro Zeile annehmen wird das Ding größer als 5MB *wobei das für eine HTML-Page schon echt finster ist ... ich könnte mir hier nur ne Script-Ausgabe vorstellen bei der jemand z.B. n Limit oder Splitting vergessen hat* ... aber 120k Zeilen ... das ist schon finster.

Aber nehmen wir mal 120k Zeilen und 50 Zeichen / Zeile an ... das in ein String zu pressen ist schon echt am Limit.
Ein String speichert intern seinen Inhalt in einem Char-Array ... und da ein Char nun mal 2 Byte groß ist kommt man auf 120k x 50 x 2 = 12mio Byte = ca. 10MB zzgl. Speicher für das String-Objekt selbst. Das noch in nem großen String-Array ... also ordentlich Overhead ... macht sich bei einer Seite ja schon bemerkbar *alleine das man schon mal ein paar Sekunden an so nem großen File sitzen kann wenn der Server wenig UpStream hat* ... und wenn man das jetzt noch zerlegen will ... da kommen *je nach komplexizität* schon mal so die Sekunden zusammen. Wenn du das ganze jetzt noch mit mehreren Seiten machst du vielleicht noch gegenseitig auf ein ander verweisen hast du ruck zuck eine OutOfMemoryException oder HeapError und die VM schmiert ab.
Auch hast du in dem bisschen Code was du da gepostet hast ne Mischung aus Rekursion und Iteration ... also ein sehr instabiles Konstukt.

Alles in allem würde ich sagen das du irgendwo eine Endlosschleife gebaut hast aber das OutOfMemory schluckst und damit in nem Deadlock endest.

Leider ist das nicht der komplette relevante Code da daraus der Fehler nicht ersichtlich wird.

Ich denke um ausführliches DeBugging und Profiling wirst du hier nicht herum kommen ... da können wir dir aber schlecht bei helfen wenn wir weder einen compilbaren Code noch die Seiten selbst haben um es zu testen.
 
Hi danke das ihr mir helfen wollt.

Also das die html seiten so groß sind liegt daran dass da Sensormessungen aufgelistet sind und das sind jede menge ^^.... Und mir geht es darum diese messungen einzulesen und auszuwerten.

Es ist sicherlich ne menge aber was ich komisch finde ist , wenn ich es nur mit einem link mache funktioniert alles super und dauert keine 20 sec, sobald ich es aber in der schleife mache so dass zb zwei links hintereinander eingelesen´werden sollen ist er bei 20 min immer noch nicht fertig?

Ich bekomme leider ja keinen fehler... zumindest nicht innerhalb der ersten 20 min (länger habe ich ihn noch nicht rödeln lassen)....
Wenn ich mir meine speicherauslastung ansehe bin ich gerade mal bei 2 GB von 8 GB und der prozessor ist fast bei 0%....

Hier noch etwas code viel ist es dann offensichtlicher für euch:

so sieht der htmlcode aus (ein kleiner ausschnitt)

Code:
<table id="information">
            <thead>
            <tr>
            <th>Timestamp</th>
            <th>Readings(13827)</th>
            </thead>
            <tbody>
            
                <tr>
                    <td>
                        2011-09-27 15:37:05.0
                    </td>
                    <td align="center">
                        18.0
                    </td>
                </tr>
            
                <tr>
                    <td>
                        2011-09-27 16:26:38.0
                    </td>
                    <td align="center">
                        22.0
                    </td>
                </tr>


Relevant in der Main ist eigentlich nur der Ausschnitt
Java:
/**Scanning SensorSites with Data**/
			WebsiteReader dataSite = new WebsiteReader();
			String[] htmlCodeDataSite = new String[arrayLength];
	
		for(int i=0; i < 2; i++){
		htmlCodeDataSite[i] = dataSite.getStrFromUrl(htmlSensorLinks[i]);
					
	WebsiteScanner sensorDataScanner = new WebsiteScanner(htmlCodeDataSite[i], dataStartTag, dataEndTag, timeStartTag, timeEndTag);
						sensorDataScanner.scanForSensorData();
				}

--> Wobei htmlSensorLinks[i] einfach nur die ganzen links enthält die nacheinander eingelesen werden sollen.


Damit werden die seiten eingelesen und als String zurück geleifert.
Java:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;


public class WebsiteReader {
	
	/**Constructor**/
	public WebsiteReader(){ 
							
	}


	public String getStrFromUrl(String surl) {
	      
		final String userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12";
	      
	      try {
	         URL url = new URL(surl);
	         URLConnection conn = url.openConnection();
	         conn.addRequestProperty("User-Agent", userAgent);
	 
	         BufferedReader in = new BufferedReader(new InputStreamReader(
	               conn.getInputStream()));
	         String str;
	         StringBuilder builder = new StringBuilder(1024);
	         while ((str = in.readLine()) != null) {
	            builder.append(str);
	            builder.append("\n"); //damit es hinterher auch so aussieht wie vorher ;-) 
	         }
	         in.close();
				         //Test-Output
				         //System.out.println(builder.toString());
	         
			System.out.println("Seite wurde eingelesen.");	         
			return builder.toString();
	      
	      } catch (MalformedURLException e) {
	         System.out.println(e.getMessage());
	      
	      } catch (IOException e) {
	         System.out.println(e.getMessage());
	      }
		return "Error";
	   }
	
}


Damit werden die Daten aus dem html code extrahiert und zurückgeliefert
Java:
public ArrayList<String> scanForSensorData(){
		
String keinHTML = htmlCodeData.replaceAll("\\<.*?\\>", "");    //ENTFERNT HTML CODE!
		
		String split[] = keinHTML.split(" ");
		ArrayList<String> sensorDataList = new ArrayList<String>();
		
		for(int i=0; i < split.length; i++){
		if(!split[i].trim().equals("")){   //entfernt alle leerzeichen vor und hinter dem String
		// entfernt die Absätze (\n) hinter den strings
                                    sensorDataList.add(split[i].trim());	   			
                                        }
			
		}
									
				//Test-Output
				for(int k=0; k < sensorDataList.size(); k++){
										System.out.println(sensorDataList.get(k));
									}	 
 return sensorDataList;
		
	}

So sieht nach der extrahierung die Ausgabe also díe ArrayList aus:
"
2011-09-27
15:37:05.0
18.0
2011-09-27
16:26:38.0
22.0
"
usw.

Wie gesagt für einen Link klappt das wunderbar. für zwei schon nicht mehr :(.
 
Warum nutzt du eigentlich nicht eine JDOM-API oder SAX? Das könnte deutlich einfacher sein! Schau dir doch mal die Klassen HTMLEditorKit, HTML und HTMLDocument an.
 
mh, hab ich keine Ahnung von aber könnte man sich ja mal ansehen ^^.

Nur habe ich jetzt schon so viel Code darauf aufbauend, es muss doch auch ne lösung für das problem geben ...oder? :(
 
Was leider noch fehlt ist die Klasse WebsiteScanner ...
Ich vermute da der Fehler da irgendwo zu finden sein sollte da der Rest soweit ganz gut aussieht.
Wäre alos nett wenn du uns diese Klasse auch noch posten könntest.
 
Hi SPiKEe danke das du mir so intensiv hilfst :)

Hier der Websitescanner:

Java:
public class WebsiteScanner {
	
                private String htmlCodeData;
	private String dataStartTag;
	private String dataEndTag;
	private String timeStartTag;
	private String timeEndTag;


/**Constructor for SensorDataSite**/
	public WebsiteScanner(String htmlCodeData, String dataStartTag, String dataEndTag, String timeStartTag, String timeEndTag){
		
		this.htmlCodeData = htmlCodeData;
		this.dataStartTag = dataStartTag;
		this.dataEndTag = dataEndTag;
		this.timeStartTag = timeStartTag;
		this.timeEndTag = timeEndTag;
	}


public ArrayList<String> scanForSensorData(){
		
	String keinHTML = htmlCodeData.replaceAll("\\<.*?\\>", "");    //ENTFERNT HTML CODE!
		
		String split[] = keinHTML.split(" ");
		ArrayList<String> sensorDataList = new ArrayList<String>();
		
	for(int i=0; i < split.length; i++){
	if(!split[i].trim().equals("")){   //entfernt alle leerzeichen vor und hinter dem Strin
	sensorDataList.add(split[i].trim());	   // entfernt die Absätze (\n) hinter den strings
			}
			
		}
									
		//Test-Output
			for(int k=0; k < sensorDataList.size(); k++){
										System.out.println(sensorDataList.get(k));
									}
		return sensorDataList;
		
	}

}


Das sind eigentlich die wichtigen Sachen für den Vorgang. Alles andere hat mit vorherigen Abläufen zu tun und ist nicht direkt da nötig wo, es nicht weitergeht....

Sollte das nicht reichen kann ich aber auch gerne die gesamte Klasse nochmal posten.

Vielen Dank :)

edit:
also ich habe jetzt mal den Debugger durchlaufen lassen und stoße in der Klasse: WebsiteReader und der Methode: getStrFromUrl(String surl) auf folgendes Problem.

Wenn ich an der Stelle (siehe Bild1) bin und dann einen Step weiter gehe bekomme ich jede Menge Exceptions (siehe Bild2), diese kann ich mit "next Step" aber alle durchgehen und dann läuft das Programm erstmal weiter.

Leider kann ich damit nicht so recht was anfangen, normal ist das doch nicht oder?

Bild1
58661d1320178744-line.jpg




Bild2
58662d1320178744-exceptions.jpg


Ok, ich bekomm hier graue Haare, ich weiß nicht was das Problem ist :(....

Ich würde mich rieeesig freuen wenn jmd Lust hat das bei sich mal nachzustellen. Ich habe mal eine kleines Testprogramm dazu gemacht in der Hoffnung das sich das Problem so besser eingrenzen lässt... aber ich kann es nicht finden.

Hier der Code dafür: siehe Zip im Anhang

Wär echt cool wenn sich das jmd mal anschauen könnte :(....

Danke im voraus
 

Anhänge

  • Test.zip
    4,5 KB · Aufrufe: 10
Zuletzt bearbeitet von einem Moderator:
Also erstmal : es gibt hier eine Anhangsfunktion

-> Antworten -> Erweitert -> Anhäge

Bei Fremhostern hat man das Problem das die Daten nach einer gewissen Zeit gelöscht werden und man so keinen Zugriff mehr darauf hat.
Dein RAR-File ist das beste Beispiel : RS meldet das die Datei nicht gefunden wurde !

Auch würde ich dir empfehlen wenn Möglich das ZIP-Format zu verwenden statt dem RAR-Format : es gibt hier genug User die KEINEN Zugang zu WinRAR haben da diese kein Windows haben *ich weis nicht wie es mit der Unterstützung seit V4 aussieht*.
ZIP hingegen kannst du auf jedem System öfnen.

Aber das Problem erkenne ich auch so : laut DIESER Exception ist die URL scheinbar ungültig. Da URL.openConnection() vieles im Hintergrund macht kann es schon mal passieren das versucht wird eine IP zu erkennen obwohl ein Host-Name verwendet wurd.

Hier wäre also mal interessant mit welchem Wert du die URL für dieses DeBugg gefüttert hast.
 

Anhänge

  • line.jpg
    line.jpg
    123,3 KB · Aufrufe: 74
  • exceptions.jpg
    exceptions.jpg
    162,8 KB · Aufrufe: 72

Neue Beiträge

Zurück