Pobranie kodu strony HTML.

0

Witam

Mam pytanie, w jaki sposób nawiązać połączenie internetowe ze stroną i pobrać z niej kod strony ?

Wiem że zapewne odpowiedz jest zbyt długa, ale może ktoś może wkleic kawałek kodu, lub podac odpowiednie klasy czy jakieś wskazówki ;)

Najlepszy by był program przykład, może ktoś zna link do takiego, szukam w sieci ale nie bardzo :(

Pozdrawiam, i porsze o pomoc

JKD documentacje oczywiście przeglądałem, ale trudno tak na starcie się w niej połapać

0

Opowiem sobie sam. jakby ktoś potrzebował to prosze :) program laczy sie z onetem i pobiera jego kod, proste.

Mam jednak problem ze zrozumieniem i potrzebą tworzenia HandlerFactory , może ktoś wie po co to dokładnie jest ???

Bo wydaje mni sie ze program moze sie bez tego obejsc, a i jescze sprawa zwracanych błędów, jeśli ktoś może pomóc, jak je wykryć ?

import java.net.*;
import java.util.Hashtable;
import java.io.*;

// Content handler that reads input stream and returns a String
class SimpleStringHandler extends ContentHandler {
    public Object getContent(URLConnection conn) throws IOException {
        InputStream input = conn.getInputStream();
        StringBuffer buf = new StringBuffer();
        int c;
        while ((c = input.read()) >= 0) {
            buf.append((char) c);
        }
        input.close();
        return (buf.toString());
    }
}

// Sample factory 
class SampleFactory implements ContentHandlerFactory {
    Hashtable handlers = new Hashtable();
    static private ContentHandler defaultHandler = new SimpleStringHandler();

    // Construct class name for content handler for contentType
    // "majorType/minorTYpe" -> majorType.minorType
    private String mapContentTypeToClassName(String contentType) {
        int len = contentType.length();
        char className[] = new char[len];
        contentType.getChars(0, len, className, 0);
	for (int j = 0; j < len; j++) {
            char c = className[j];
	    // turn '/' to '.'; nonletter and nondigits to '_'
            if (c == '/') {
                className[j] = '.';
            } else if (!Character.isLetterOrDigit(c)) {
                className[j] = '_';
	    }
        }
        return (new String(className));
    }

    public ContentHandler createContentHandler(String contentType) {
        ContentHandler handler = null;
        if (contentType == null)
            return defaultHandler;        // no type specified

        // Check cache first
        handler = (ContentHandler)handlers.get(contentType);
        if (handler != null)
            return handler;

        // Get class name from content
        String className = mapContentTypeToClassName(contentType);
	try {
	    handler = (ContentHandler)Class.forName(className).newInstance();
	} catch(Exception e) {
	    // cannot get handler, just use default
	    handler = defaultHandler;
	}

        // Add newly found handler to cache
        handlers.put(contentType, handler);
        return handler;
    }
}

class Main {
    public static void main(String[] args) {

      /*  if (args.length != 1) {
            System.err.println("Usage: java Main <URL>");
            System.exit(1);
        }

        // Configure system to use our own factory*/
        URLConnection.setContentHandlerFactory(new SampleFactory());
        try {
            URL url = new URL("http://www.onet.pl/");
        
            Object pkgs_html = url.getContent();
            if (pkgs_html != null) {
                System.out.println("class: " + pkgs_html.getClass());
                System.out.println("obj: " + pkgs_html);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    };
}
</url>
0

tak proste zadanko a tak sobie utrudniles :), ale jesli planujesz napisac przegladarke to jestes na dobrej drodze ;). Mialem kiedys to samo zadanie i rozwiazanie wyglada tak

import java.net.*;        // konieczne do posługiwania się klasą URL
import java.io.*;
import java.util.*;

class URLReader {

 public static void main(String[] args) throws Exception {
   BufferedReader list = new BufferedReader(           // lista URLi z pliku url.txt
            new FileReader("url.txt"));// zapisanych w kolejnych liniach
   String urlString;
   while ((urlString = list.readLine()) != null) {
      readAndSave(new URL(urlString)); // tworzony nowy obiekt klasy URL
      }                                // oznaczający zasób z Sieci
   list.close();
   System.exit(0);

 }


 static void readAndSave(URL url) throws Exception {

   BufferedReader in = new BufferedReader(
                         new InputStreamReader(
                          url.openStream()   // zwraca InputStream związany z URLem
                          )
                          );

   String fname = null;
   StringTokenizer st = new StringTokenizer(
                            url.getFile(),    // <- zwraca nazwę pliku dla URLa
                            "/"				//odcinamy domene pobieramu uri
                            );
                            System.out.println(url);
   while (st.hasMoreTokens()) fname = st.nextToken(); // pobieramy nazwę pliku
   													// pod którą ma być zachowany
	if(fname == null){
		fname = "index.html";			//jesli fname okaze sie nullem
	}                                  //fname ustawiamy na index.html

   BufferedWriter out = new BufferedWriter(new FileWriter(fname));

   String s;
   while ((s = in.readLine()) != null) {//odczyt ze strumienia i
         out.write(s);					//zapis do pliku
         out.newLine();
         }
   in.close();		//zamkniecie strumieni
   out.close();
   }

}

Twoj kod po prostu mapuje typ mime na obiekt i go zapisuje. I tak po uruchomieniu programu zawartosc Hashtabla z klasy SampleFactory jest klucz > text/html a wartosc to String zawierajacy kod strony onet.pl, co otrzymujesz wywolujac megode getContent.
By uzyskac sama tresc strony propnuje korzystac z mojej klasy URLReader bo to co napisales bardziej nadawalo by sie na cash przegladarki ale o tym nie bede sie rozpisywal.
Pozdrawiam Bookayashee

0

To lubie, uczciwa konkretna odpowiedz, wielkie dzięki ;-)
Pozwolilem sobie przeksztalcic twoj kod do takiej postaci, teraz ta funkcja realizuje wlasnie to o co mi chodzilo :)
Co o tym sądzisz ?

	 public static String pobierzHTML(URL url) throws Exception {
	
	   BufferedReader pobierz = new BufferedReader(
	                         new InputStreamReader(
	                          url.openStream()   // zwraca InputStream związany z URLem
	                          )
	                          );
	   String temp;
	   String s = "";
	   while ((temp = pobierz.readLine()) != null) {
	         s +=(temp + "\n");
	         }
		  
	   pobierz.close();
	   
	   return s;
	}

i jeszcze pytanie mam odnosnie tego fragmentu

	   String temp;
	   String s = "";
	   while ((temp = pobierz.readLine()) != null) {
	         s +=(temp + "\n");
	         }

Czy nieda sie tego jakos przyspieszyc ?? uproscic ? Troche nie estetyczny kod, mnie sie zdaje [green]

1

Twoja metoda ma zwracać Stringa z podanego URL'a moja natomiast miała zapisywać go do pliku o nazwie wyciagnietej z podanego URL'a, obie rożnia się tylko sposobem zwracanje wartości.
Nie ma sie za bardzo co do niej przyczepiać, robi to co powinna i kod jest krótki, choć na upartego zawsze można się do czegoś przyczepić, chociażby do tego, że to nie metoda powinna wyrzucać wyjątek, tylko wyjatek powinien być przechwytywany przez odpowiednią klase wyjątków, ale to juz naprawde taki szczegół, że nie warto o tym pisać dalej ;).
Co do twojego pytania czy da się przyspieszyć, to nie bardzo, czytanie ze strumienia zależy tu od czasu odpowiedzi zdalnego hosta oraz możliwości łacza, wiec praktycznie nie masz tu możliwości optymalizacji, chociż można by skorzystać z java.nio gdzie czytanie nie jest blokujace, co pozwoliło by wykonywać inne części kodu podczas czekania na odpowiedz hosta, ale to juz inna bajka.
Jesli chodziło ci o wywalenie jednej ze zmiennych String to nie bo potrzebujesz obu zmiennych, jedną do pobirania nowych wartości ze strumienia, a druga do zapamietywania wszystkich wartości jakie uzuskujemy ze strumienia.
Uprościć, jesli Ci chodzi o poprawe kodu to da się co nieco zrobić, np. pętla while wykonuje tylko jedną instukcje a więc można zrezygnować z nawiasów klamrowych, co nic nie zmieni w wykonywaniu się kodu a sam kod bedzie o 2 linijki krótszy. Deklaracje zmiennych też możesz wykonąć w jednej lini,
String tmp, s="";
A wiec całość mogłaby wygladać w następujący spób

static String readHTML(URL url) {
	String tmp, s="";
	try{		
		BufferedReader br = new BufferedReader(
			new InputStreamReader(url.openStream()));
				
		while((tmp=br.readLine()) != null) s += tmp+"\n";
		
		br.close();
	}catch(IOException e){
		e.printStackTrace();	
	}
	return s;
}

Co nic nie zmienia poza formatem meteody

Pozdrawiam BookaYashee

0

To chyba ostatecznie konczy temat, wielkie dzięki za pomoc :-)

0

Witam. Zbudowałem taką sobie klasę:

public class HttpClient extends Thread {
    public HttpClient(){
    }
    
    public String readHTML(URL url) {
        String tmp, s="";
        int i = 0;
        try{                
                BufferedReader br = new BufferedReader(
                        new InputStreamReader(url.openStream()));
                                
                while((tmp=br.readLine()) != null)
                    s += tmp + "\n";
                
                br.close();
        }catch(IOException e){
                JOptionPane.showMessageDialog(null, e.getMessage());     
        }
        return s;
    }
    
    public void run(){
        try {
            readHTML(new URL("http://www.onet.pl"));
        } catch (MalformedURLException ex) {
            JOptionPane.showMessageDialog(null, ex.getMessage()); 
        }
    }
}

Jak widzicie została ona stworzona, aby pobierać kod strony asynchronicznie:

HttpClient client = new HttpClient();
client.start();

Problem w tym, że po wywołaniu powyższego kodu, program łagodnie mówiąc tnie się...
Może nie zamraża, ale samo przeniesienie okna programu zlewej strony ekranu na prawą trwa jakieś 3 sekundy...
Co zrobiłem źle?

2

Ten sam wątek pojawił sie na forum jdn http://jdn.pl/node/1074,
Zauważono tam pewien szczegół ktory, ma duży wplyw na szybkość działania kodu. Zamiast uzycia obiektu typu String do zapamietania strony urzyto tam obiektu StringBuffer dzęki czemu znacząco przyspiesza czas wykonaia kodu ze wzgledu na to że nie ma zbędnej realokacji pamieci w każdej petli.
Załączam poprawioną metode readHTML

public String readHTML(){
StringBuffer content = new StringBuffer();
BufferedReader br = null;
try {
    br = new BufferedReader(new InputStreamReader(url.openStream()));

    String line = null;
    while ((line = br.readLine()) != null) {
        content.append(line).append("\n");
    }
} catch (IOException e) {
    JOptionPane.showMessageDialog(null, e.getMessage());
} finally {
    if (br != null) {
        try {
            br.close();
        } catch (IOException e) {
            JOptionPane.showMessageDialog(null, e.getMessage());                        
        }
    }
}
return content.toString();
}

Pozdrawiam BookaYashee

1 użytkowników online, w tym zalogowanych: 0, gości: 1