Jak programowo pobrać stronę internetową w języku Java

117

Chciałbym móc pobrać kod HTML strony internetowej i zapisać go w pliku String, aby móc go przetworzyć. Ponadto, jak poradzić sobie z różnymi typami kompresji.

Jak miałbym się do tego zabrać za pomocą Java?

jjnguy
źródło
Jest to w zasadzie szczególny przypadek stackoverflow.com/questions/921262/ ...
Robin Green

Odpowiedzi:

110

Oto testowany kod przy użyciu klasy URL języka Java . Zalecałbym jednak lepszą pracę niż tutaj, jeśli chodzi o obsługę wyjątków lub przekazywanie ich w górę stosu wywołań.

public static void main(String[] args) {
    URL url;
    InputStream is = null;
    BufferedReader br;
    String line;

    try {
        url = new URL("http://stackoverflow.com/");
        is = url.openStream();  // throws an IOException
        br = new BufferedReader(new InputStreamReader(is));

        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
    } catch (MalformedURLException mue) {
         mue.printStackTrace();
    } catch (IOException ioe) {
         ioe.printStackTrace();
    } finally {
        try {
            if (is != null) is.close();
        } catch (IOException ioe) {
            // nothing to see here
        }
    }
}
Bill the Lizard
źródło
16
DataInputStream.readLine () jest przestarzała, ale poza tym bardzo dobrym przykładem. Użyłem InputStreamReader () opakowanego w BufferedReader (), aby uzyskać funkcję readLine ().
mjh2007
2
Nie bierze to pod uwagę kodowania znaków, więc chociaż wydaje się, że działa z tekstem ASCII, ostatecznie doprowadzi do „dziwnych znaków”, gdy wystąpi niezgodność.
artbristol
W trzeciej linii zamień DataInputStreamna BufferedReader. I zamień "dis = new DataInputStream(new BufferedInputStream(is));"na"dis = new BufferedReader(new InputStreamReader(is));"
kolobok
1
@akapelko Dziękuję. Zaktualizowałem moją odpowiedź, aby usunąć wywołania przestarzałych metod.
Bill the Lizard
2
a co z zamknięciem InputStreamReader?
Alexander - Przywróć Monikę
170

Użyłbym przyzwoitego parsera HTML, takiego jak Jsoup . To jest tak proste, jak:

String html = Jsoup.connect("http://stackoverflow.com").get().html();

Obsługuje GZIP i odpowiedzi podzielone na fragmenty oraz kodowanie znaków w pełni transparentnie. Oferuje również więcej korzyści, takich jak przechodzenie po HTML i manipulowanie za pomocą selektorów CSS, takich jak jQuery. Musisz tylko złapać go jako Document, a nie jako plik String.

Document document = Jsoup.connect("http://google.com").get();

Naprawdę nie masz chcesz uruchamiać podstawowych metod String, a nawet wyrażeń regularnych w HTML, aby to przetworzyć.

Zobacz też:

BalusC
źródło
3
Dobra odpowiedź. Trochę za późno. ;)
jjnguy
59
Lepiej niż nigdy.
BalusC,
Fantastyczna biblioteka :) Dzięki za to.
Jakub P.
Dlaczego nikt wcześniej nie powiedział mi o .html (). Tak bardzo zastanawiałem się, jak łatwo przechowywać kod HTML pobrany przez Jsoup i to bardzo pomaga.
Avamander
dla nowicjuszy, jeśli używasz tej biblioteki w systemie Android, musisz jej użyć w innym wątku, ponieważ domyślnie działa w tym samym wątku aplikacji, co spowoduje, że aplikacja wyrzuciNetworkOnMainThreadException
Mohammed Elrashied
25

Odpowiedź Billa jest bardzo dobra, ale możesz chcieć zrobić kilka rzeczy z żądaniem, takich jak kompresja lub klienty użytkownika. Poniższy kod pokazuje, w jaki sposób można zastosować różne typy kompresji do żądań.

URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection(); // Cast shouldn't fail
HttpURLConnection.setFollowRedirects(true);
// allow both GZip and Deflate (ZLib) encodings
conn.setRequestProperty("Accept-Encoding", "gzip, deflate");
String encoding = conn.getContentEncoding();
InputStream inStr = null;

// create the appropriate stream wrapper based on
// the encoding type
if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
    inStr = new GZIPInputStream(conn.getInputStream());
} else if (encoding != null && encoding.equalsIgnoreCase("deflate")) {
    inStr = new InflaterInputStream(conn.getInputStream(),
      new Inflater(true));
} else {
    inStr = conn.getInputStream();
}

Aby ustawić również klienta użytkownika, dodaj następujący kod:

conn.setRequestProperty ( "User-agent", "my agent name");
jjnguy
źródło
Dla tych, którzy chcą przekonwertować InputStream na ciąg, zobacz tę odpowiedź .
SSight3
setFollowRedirects pomaga, używam setInstanceFollowRedirects w moim przypadku, w wielu przypadkach otrzymywałem puste strony internetowe przed ich użyciem. Zakładam, że próbujesz użyć kompresji, aby szybciej pobrać plik.
gouessej
12

Cóż, możesz skorzystać z wbudowanych bibliotek, takich jak URL i URLConnection , ale nie zapewniają one dużej kontroli.

Osobiście wybrałbym bibliotekę Apache HTTPClient .
Edit: HTTPClient został ustawiony do końca życia przez Apache. Zamiennik to: Składniki HTTP

Jon Skeet
źródło
Brak wersji Java programu System.Net.WebRequest?
FlySwat
1
W pewnym sensie byłby to adres URL. :-) Na przykład: nowy adres URL („ google.com”). OpenStream () // => InputStream
Daniel Spiewak
1
@Jonathan: To, co powiedział Daniel, w większości - chociaż WebRequest daje ci większą kontrolę niż URL. HTTPClient jest bliżej funkcjonalności, IMO.
Jon Skeet
9

Wszystkie wyżej wymienione podejścia nie powodują pobrania tekstu strony internetowej tak, jak wygląda w przeglądarce. obecnie wiele danych jest ładowanych do przeglądarek poprzez skrypty na stronach html. żadna z wyżej wymienionych technik nie obsługuje skryptów, po prostu pobiera tylko tekst HTML. HTMLUNIT obsługuje javascripts. więc jeśli chcesz pobrać tekst strony internetowej tak, jak wygląda w przeglądarce, powinieneś użyć HTMLUNIT .

user3690910
źródło
1

Najprawdopodobniej będziesz musiał wyodrębnić kod z bezpiecznej strony internetowej (protokół https). W poniższym przykładzie plik html jest zapisywany do c: \ temp \ filename.html Ciesz się!

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;

import javax.net.ssl.HttpsURLConnection;

/**
 * <b>Get the Html source from the secure url </b>
 */
public class HttpsClientUtil {
    public static void main(String[] args) throws Exception {
        String httpsURL = "https://stackoverflow.com";
        String FILENAME = "c:\\temp\\filename.html";
        BufferedWriter bw = new BufferedWriter(new FileWriter(FILENAME));
        URL myurl = new URL(httpsURL);
        HttpsURLConnection con = (HttpsURLConnection) myurl.openConnection();
        con.setRequestProperty ( "User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:63.0) Gecko/20100101 Firefox/63.0" );
        InputStream ins = con.getInputStream();
        InputStreamReader isr = new InputStreamReader(ins, "Windows-1252");
        BufferedReader in = new BufferedReader(isr);
        String inputLine;

        // Write each line into the file
        while ((inputLine = in.readLine()) != null) {
            System.out.println(inputLine);
            bw.write(inputLine);
        }
        in.close(); 
        bw.close();
    }
}
Specjalista ds. Kontroli jakości
źródło
0

Na komputerze z systemem Unix / Linux możesz po prostu uruchomić „wget”, ale tak naprawdę nie jest to opcja, jeśli piszesz klienta wieloplatformowego. Oczywiście zakłada się, że tak naprawdę nie chcesz robić zbyt wiele z danymi, które pobierasz między momentem ich pobrania a trafieniem na dysk.

Timo Geusch
źródło
Zacząłbym również od tego podejścia i zreformowałbym je później, jeśli jest niewystarczające
Dustin Getz
0

Jetty ma klienta HTTP, którego można użyć do pobrania strony internetowej.

package com.zetcode;

import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;

public class ReadWebPageEx5 {

    public static void main(String[] args) throws Exception {

        HttpClient client = null;

        try {

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

            String url = "http://www.something.com";

            ContentResponse res = client.GET(url);

            System.out.println(res.getContentAsString());

        } finally {

            if (client != null) {

                client.stop();
            }
        }
    }
}

Przykład drukuje zawartość prostej strony internetowej.

W tutorialu Reading a web page in Java napisałem sześć przykładów programistycznego pobierania strony internetowej w Javie przy użyciu URL, JSoup, HtmlCleaner, Apache HttpClient, Jetty HttpClient i HtmlUnit.

Jan Bodnar
źródło
0

Uzyskaj pomoc od tej klasy, pobiera kod i filtruje niektóre informacje.

public class MainActivity extends AppCompatActivity {

    EditText url;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate( savedInstanceState );
        setContentView( R.layout.activity_main );

        url = ((EditText)findViewById( R.id.editText));
        DownloadCode obj = new DownloadCode();

        try {
            String des=" ";

            String tag1= "<div class=\"description\">";
            String l = obj.execute( "http://www.nu.edu.pk/Campus/Chiniot-Faisalabad/Faculty" ).get();

            url.setText( l );
            url.setText( " " );

            String[] t1 = l.split(tag1);
            String[] t2 = t1[0].split( "</div>" );
            url.setText( t2[0] );

        }
        catch (Exception e)
        {
            Toast.makeText( this,e.toString(),Toast.LENGTH_SHORT ).show();
        }

    }
                                        // input, extrafunctionrunparallel, output
    class DownloadCode extends AsyncTask<String,Void,String>
    {
        @Override
        protected String doInBackground(String... WebAddress) // string of webAddress separate by ','
        {
            String htmlcontent = " ";
            try {
                URL url = new URL( WebAddress[0] );
                HttpURLConnection c = (HttpURLConnection) url.openConnection();
                c.connect();
                InputStream input = c.getInputStream();
                int data;
                InputStreamReader reader = new InputStreamReader( input );

                data = reader.read();

                while (data != -1)
                {
                    char content = (char) data;
                    htmlcontent+=content;
                    data = reader.read();
                }
            }
            catch (Exception e)
            {
                Log.i("Status : ",e.toString());
            }
            return htmlcontent;
        }
    }
}
Sohaib Aslam
źródło
0

Aby to zrobić przy użyciu potężnego NIO.2 Files.copy (InputStream in, Path target):

URL url = new URL( "http://download.me/" );
Files.copy( url.openStream(), Paths.get("downloaded.html" ) );
Jan Tibar
źródło
-1

Użyłem rzeczywistej odpowiedzi na ten post ( adres URL ) i zapisałem dane wyjściowe do pliku.

package test;

import java.net.*;
import java.io.*;

public class PDFTest {
    public static void main(String[] args) throws Exception {
    try {
        URL oracle = new URL("http://www.fetagracollege.org");
        BufferedReader in = new BufferedReader(new InputStreamReader(oracle.openStream()));

        String fileName = "D:\\a_01\\output.txt";

        PrintWriter writer = new PrintWriter(fileName, "UTF-8");
        OutputStream outputStream = new FileOutputStream(fileName);
        String inputLine;

        while ((inputLine = in.readLine()) != null) {
            System.out.println(inputLine);
            writer.println(inputLine);
        }
        in.close();
        } catch(Exception e) {

        }

    }
}
A_01
źródło