java - page - InputStream desde una URL
read page content java (6)
(a) wwww.somewebsite.com/a.txt
no es una ''URL de archivo''. No es una URL en absoluto. Si coloca http://
en el frente, sería una URL HTTP, que es claramente lo que pretende aquí.
(b) FileInputStream
es para archivos, no para URL.
(c) La forma de obtener un flujo de entrada desde cualquier URL es a través de URL.openStream(),
o URL.getConnection().getInputStream(),
que es equivalente pero puede que tenga otras razones para obtener el URLConnection
y jugarlo primero .
¿Cómo obtengo un InputStream de una URL?
por ejemplo, quiero tomar el archivo en url wwww.somewebsite.com/a.txt
y leerlo como InputStream en Java, a través de un servlet.
He intentado
InputStream is = new FileInputStream("wwww.somewebsite.com/a.txt");
pero lo que obtuve fue un error:
java.io.FileNotFoundException
Aquí hay un ejemplo completo que lee los contenidos de la página web dada. La página web se lee de un formulario HTML. Usamos clases estándar de InputStream
, pero podría hacerse más fácilmente con la biblioteca JSoup.
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.6</version>
</dependency>
Estas son las dependencias de Maven. Usamos la biblioteca de Apache Commons para validar cadenas de URL.
package com.zetcode.web;
import com.zetcode.service.WebPageReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name = "ReadWebPage", urlPatterns = {"/ReadWebPage"})
public class ReadWebpage extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/plain;charset=UTF-8");
String page = request.getParameter("webpage");
String content = new WebPageReader().setWebPageName(page).getWebPageContent();
ServletOutputStream os = response.getOutputStream();
os.write(content.getBytes(StandardCharsets.UTF_8));
}
}
El servlet ReadWebPage
lee el contenido de la página web determinada y lo envía de vuelta al cliente en formato de texto sin formato. La tarea de leer la página se delega a WebPageReader
.
package com.zetcode.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import org.apache.commons.validator.routines.UrlValidator;
public class WebPageReader {
private String webpage;
private String content;
public WebPageReader setWebPageName(String name) {
webpage = name;
return this;
}
public String getWebPageContent() {
try {
boolean valid = validateUrl(webpage);
if (!valid) {
content = "Invalid URL; use http(s)://www.example.com format";
return content;
}
URL url = new URL(webpage);
try (InputStream is = url.openStream();
BufferedReader br = new BufferedReader(
new InputStreamReader(is, StandardCharsets.UTF_8))) {
content = br.lines().collect(
Collectors.joining(System.lineSeparator()));
}
} catch (IOException ex) {
content = String.format("Cannot read webpage %s", ex);
Logger.getLogger(WebPageReader.class.getName()).log(Level.SEVERE, null, ex);
}
return content;
}
private boolean validateUrl(String webpage) {
UrlValidator urlValidator = new UrlValidator();
return urlValidator.isValid(webpage);
}
}
WebPageReader
valida la URL y lee los contenidos de la página web. Devuelve una cadena que contiene el código HTML de la página.
<!DOCTYPE html>
<html>
<head>
<title>Home page</title>
<meta charset="UTF-8">
</head>
<body>
<form action="ReadWebPage">
<label for="page">Enter a web page name:</label>
<input type="text" id="page" name="webpage">
<button type="submit">Submit</button>
</form>
</body>
</html>
Finalmente, esta es la página de inicio que contiene el formulario HTML. Esto está tomado de mi tutorial sobre este tema.
Con algo de éxito utilizo este método. Maneja redirecciones y se puede pasar una cantidad variable de encabezados HTTP como Map<String,String>
. También permite redirecciones de HTTP a HTTPS .
private InputStream urlToInputStream(URL url, Map<String, String> args) {
HttpURLConnection con = null;
InputStream inputStream = null;
try {
con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(15000);
con.setReadTimeout(15000);
if (args != null) {
for (Entry<String, String> e : args.entrySet()) {
con.setRequestProperty(e.getKey(), e.getValue());
}
}
con.connect();
int responseCode = con.getResponseCode();
/* By default the connection will follow redirects. The following
* block is only entered if the implementation of HttpURLConnection
* does not perform the redirect. The exact behavior depends to
* the actual implementation (e.g. sun.net).
* !!! Attention: This block allows the connection to
* switch protocols (e.g. HTTP to HTTPS), which is <b>not</b>
* default behavior. See: https://.com/questions/1884230
* for more info!!!
*/
if (responseCode < 400 && responseCode > 299) {
String redirectUrl = con.getHeaderField("Location");
try {
URL newUrl = new URL(redirectUrl);
return urlToInputStream(newUrl, args);
} catch (MalformedURLException e) {
URL newUrl = new URL(url.getProtocol() + "://" + url.getHost() + redirectUrl);
return urlToInputStream(newUrl, args);
}
}
/*!!!!!*/
inputStream = con.getInputStream();
return inputStream;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Ejemplo de llamada
private InputStream getInputStreamFromUrl(URL url, String user, String passwd) throws IOException {
String encoded = Base64.getEncoder().encodeToString((user + ":" + passwd).getBytes(StandardCharsets.UTF_8));
Map<String,String> httpHeaders=new Map<>();
httpHeaders.put("Accept", "application/json");
httpHeaders.put("User-Agent", "myApplication");
httpHeaders.put("Authorization", "Basic " + encoded);
return urlToInputStream(url,httpHeaders);
}
Su código original usa FileInputStream, que es para acceder a los archivos alojados en el sistema de archivos.
El constructor que utilizó intentará ubicar un archivo llamado a.txt en la subcarpeta www.somewebsite.com del directorio de trabajo actual (el valor de la propiedad del sistema user.dir). El nombre que proporciona se resuelve en un archivo utilizando la clase Archivo.
Los objetos de URL son la forma genérica de resolver esto. Puede usar URL para acceder a los archivos locales, pero también a los recursos alojados en la red. La clase URL admite el protocolo file: // además de http: // o https: // para que esté listo.
Tratar:
final InputStream is = new URL("http://wwww.somewebsite.com/a.txt").openStream();
Use java.net.URL#openStream()
con una URL adecuada (¡incluido el protocolo!). P.ej
InputStream input = new URL("http://www.somewebsite.com/a.txt").openStream();
// ...