Hablando de rastreadores, el uso de URLConnection que viene con Java puede lograr algunas funciones básicas de rastreo de páginas, pero para algunas funciones más avanzadas, como el procesamiento de redirecciones y la eliminación de etiquetas HTML, simplemente usar URLConnection no es suficiente.
Aquí podemos utilizar el paquete jar de terceros HttpClient.
A continuación, usamos HttpClient para escribir simplemente una demostración que se arrastra a Baidu:
importar java.io.FileOutputStream;
importar java.io.InputStream;
importar java.io.OutputStream;
importar org.apache.commons.httpclient.HttpClient;
importar org.apache.commons.httpclient.HttpStatus;
importar org.apache.commons.httpclient.methods.GetMethod;
/**
*
* @autor Llámame por qué
*
*/
Araña de clase pública {
HttpClient estático privado httpClient = nuevo HttpClient();
/**
* ruta @param
* Enlace a la página de destino
* @return Devuelve un valor booleano, que indica si la página de destino se descarga normalmente
* @throwsException
* Excepción de IO al leer la secuencia de una página web o escribir una secuencia de archivos local
*/
Página de descarga booleana estática pública (ruta de cadena) lanza una excepción {
//Definir flujos de entrada y salida
Entrada de flujo de entrada = nulo;
Salida OutputStream = nulo;
// Obtener el método de publicación
GetMethod getMethod = nuevo GetMethod(ruta);
//Ejecutar, devolver código de estado
int statusCode = httpClient.executeMethod(getMethod);
// Procesar el código de estado
// Para simplificar, solo se procesa el código de estado con un valor de retorno de 200
si (código de estado == HttpStatus.SC_OK) {
entrada = getMethod.getResponseBodyAsStream();
//Obtiene el nombre del archivo de la URL
Nombre de archivo de cadena = ruta.subcadena(ruta.lastIndexOf('/') + 1)
+ ".html";
// Obtener el flujo de salida del archivo
salida = new FileOutputStream(nombre de archivo);
// Salida al archivo
int byte temporal = -1;
mientras ((tempByte = input.read()) > 0) {
salida.write(tempByte);
}
//Cerrar el flujo de entrada
si (entrada! = nulo) {
entrada.cerrar();
}
//Cerrar el flujo de salida
si (salida! = nulo) {
salida.close();
}
devolver verdadero;
}
devolver falso;
}
público estático vacío principal (String [] argumentos) {
intentar {
// Toma la página de inicio y la salida de Baidu
Spider.downloadPage("http://www.baidu.com");
} captura (Excepción e) {
e.printStackTrace();
}
}
}
Sin embargo, un rastreador tan básico no puede satisfacer las necesidades de varios rastreadores.
Primero, presentemos el rastreador de amplitud.
Creo que todo el mundo está familiarizado con la amplitud primero. En términos simples, se pueden entender los rastreadores de amplitud primero como este.
Pensamos en Internet como un gráfico dirigido súper grande. Cada enlace en una página web es un borde dirigido, y cada archivo o página pura sin enlace es el punto final del gráfico:
El rastreador de amplitud es uno de esos rastreadores que rastrean este gráfico dirigido, comenzando desde el nodo raíz y rastreando los datos de los nuevos nodos capa por capa.
El algoritmo de recorrido de ancho es el siguiente:
(1) Vertex V se coloca en la cola.
(2) Continuar la ejecución cuando la cola no esté vacía; de lo contrario, el algoritmo estará vacío.
(3) Retire la cola, obtenga el nodo principal V, visite el vértice V y marque que V ha sido visitado.
(4) Encuentre la primera columna de vértice adyacente del vértice V.
(5) Si el vértice col adyacente de V no ha sido visitado, entonces col se coloca en la cola.
(6) Continúe buscando otros vértices adyacentes de V y vaya al paso (5). Si se han visitado todos los vértices adyacentes de V, vaya al paso (2).
Según el algoritmo de recorrido de ancho, el orden de recorrido de la imagen de arriba es: A->B->C->D->E->F->H->G->I, de modo que se recorre capa por capa. .
El rastreador de amplitud en realidad rastrea una serie de nodos semilla, que es básicamente lo mismo que el recorrido del gráfico.
Podemos colocar las URL de las páginas que deben rastrearse en una tabla TODO y las páginas visitadas en una tabla Visitada:
El proceso básico del rastreador de amplitud es el siguiente:
(1) Compare el enlace analizado con el enlace de la tabla Visitado. Si el enlace no existe en la tabla Visitado, significa que no ha sido visitado.
(2) Coloque el enlace en la tabla TODO.
(3) Después del procesamiento, obtenga un enlace de la tabla TODO y colóquelo directamente en la tabla Visitada.
(4) Continúe el proceso anterior para la página web representada por este enlace. Etcétera.
A continuación, crearemos un rastreador de amplitud paso a paso.
Primero, diseñe una estructura de datos para almacenar la tabla TODO. Teniendo en cuenta la necesidad de primero en entrar, primero en salir, usamos una cola y personalizamos una clase Quere:
importar java.util.LinkedList;
/**
* Clase de cola personalizada para guardar la tabla TODO
*/
Cola de clase pública {
/**
* Definir una cola e implementarla usando LinkedList
*/
cola privada LinkedList<Object> = new LinkedList<Object>();
/**
* Agregar t a la cola
*/
public void enQueue (Objeto t) {
cola.addLast(t);
}
/**
* Elimina el primer artículo de la cola y devuélvelo.
*/
Objeto público deQueue() {
devolver cola.removeFirst();
}
/**
* Devuelve si la cola está vacía
*/
público booleano isQueueEmpty() {
devolver cola.isEmpty();
}
/**
* Determinar y devolver si la cola contiene t
*/
contians booleanos públicos (Objeto t) {
cola de retorno.contiene(t);
}
/**
* Determinar y devolver si la cola está vacía
*/
público booleano vacío() {
devolver cola.isEmpty();
}
}
También se necesita una estructura de datos para registrar las URL que se han visitado, es decir, la tabla Visitada.
Teniendo en cuenta la función de esta tabla, siempre que se vaya a acceder a una URL, primero se busca en esta estructura de datos. Si la URL actual ya existe, la tarea de URL se descarta.
Esta estructura de datos no debe estar duplicada y se puede buscar rápidamente, por lo que se elige HashSet para el almacenamiento.
En resumen, creamos otra clase SpiderQueue para guardar la tabla Visitada y la tabla TODO:
importar java.util.HashSet;
importar java.util.Set;
/**
* Clase personalizada para guardar la tabla visitada y la tabla no visitada
*/
clase pública SpiderQueue {
/**
* La colección de URL visitadas, es decir, la tabla Visitada.
*/
Conjunto estático privado<Objeto> URL visitada = nuevo HashSet<>();
/**
* Agregar a la cola de URL visitadas
*/
addVisitedUrl vacío estático público (URL de cadena) {
URL visitada.add(url);
}
/**
* Eliminar las URL visitadas
*/
removeVisitedUrl vacío estático público (URL de cadena) {
URL visitada.remove(url);
}
/**
* Obtener el número de URL visitadas
*/
público estático int getVisitedUrlNum() {
devolver URL visitada.size();
}
/**
* La colección de URL a visitar, es decir, la tabla no visitada.
*/
Cola estática privada unVisitedUrl = nueva cola();
/**
* Obtener la cola de no visitados
*/
Cola estática pública getUnVisitedUrl() {
devolver URL no visitada;
}
/**
* La URL no visitada no visitada se retira de la cola
*/
Objeto estático público unVisitedUrlDeQueue() {
devolver unVisitedUrl.deQueue();
}
/**
* Asegúrese de que cada URL solo se visite una vez al agregar la URL a unVisitedUrl
*/
addUnvisitedUrl vacío estático público (URL de cadena) {
if (url != null && !url.trim().equals("") && !visitedUrl.contains(url)
&& !unVisitedUrl.contians(url))
URL no visitada.enQueue(url);
}
/**
* Determinar si la cola de URL no visitadas está vacía
*/
público estático booleano unVisitedUrlsEmpty() {
devolver URL no visitada.empty();
}
}
Lo anterior es una encapsulación de algunas clases personalizadas. El siguiente paso es definir una clase de herramienta para descargar páginas web. La definimos como la clase DownTool:
controlador de paquetes;
importar java.io.*;
importar org.apache.commons.httpclient.*;
importar org.apache.commons.httpclient.methods.*;
importar org.apache.commons.httpclient.params.*;
clase pública DownTool {
/**
* Genere el nombre de archivo de la página web que se guardará según la URL y el tipo de página web, y elimine los caracteres que no sean nombres de archivo en la URL
*/
Cadena privada getFileNameByUrl (URL de cadena, Tipo de contenido de cadena) {
// Elimina los siete caracteres "http://"
URL = URL.substring(7);
// Confirma que la página capturada es de tipo texto/html
si (contentType.indexOf("html")! = -1) {
// Convierte todos los símbolos especiales de las URL en guiones bajos
url = url.replaceAll("[//?/:*|<>/"]", "_") + ".html";
} demás {
url = url.replaceAll("[//?/:*|<>/"]", "_") + "."
+ contentType.substring(contentType.lastIndexOf("/") + 1);
}
URL de retorno;
}
/**
* Guarde la matriz de bytes de la página web en un archivo local, filePath es la dirección relativa del archivo que se guardará
*/
privado vacío saveToLocal(byte[] datos, String filePath) {
intentar {
DataOutputStream salida = nuevo DataOutputStream(nuevo FileOutputStream(
nuevo archivo(filePath)));
para (int i = 0; i < data.length; i++)
out.write(datos[i]);
salida.flush();
fuera.cerrar();
} captura (IOException e) {
e.printStackTrace();
}
}
//Descarga la página web a la que apunta la URL
archivo de descarga de cadena pública (URL de cadena) {
Cadena filePath = nulo;
// 1. Generar objeto HttpClinet y establecer parámetros
HttpClient httpClient = nuevo HttpClient();
//Establece el tiempo de espera de la conexión HTTP en 5 segundos
httpClient.getHttpConnectionManager().getParams()
.setConnectionTimeout(5000);
// 2. Generar objeto GetMethod y establecer parámetros
GetMethod getMethod = nuevo GetMethod(url);
//Establece el tiempo de espera de la solicitud de obtención en 5 segundos
getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 5000);
//Establecer procesamiento de reintento de solicitud
getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
nuevo DefaultHttpMethodRetryHandler());
// 3. Ejecutar solicitud GET
intentar {
int statusCode = httpClient.executeMethod(getMethod);
// Determinar el código de estado de acceso
si (código de estado! = HttpStatus.SC_OK) {
System.err.println("Método fallido: "
+ getMethod.getStatusLine());
rutaarchivo = nulo;
}
// 4. Procesar el contenido de la respuesta HTTP
byte[] ResponseBody = getMethod.getResponseBody() // Leer como matriz de bytes
// Genera el nombre del archivo al guardar según la URL de la página web
ruta_archivo = "temp//"
+ getFileNameByUrl(url,
getMethod.getResponseHeader("Tipo de contenido")
.getValue());
saveToLocal(responseBody, filePath);
} captura (HttpException e) {
//Se produce una excepción fatal. Puede ser que el protocolo sea incorrecto o que haya algún problema con el contenido devuelto.
System.out.println("Compruebe si su dirección http es correcta");
e.printStackTrace();
} captura (IOException e) {
//Se produce una excepción en la red
e.printStackTrace();
} finalmente {
// Liberar la conexión
getMethod.releaseConnection();
}
devolver ruta del archivo;
}
}
Aquí necesitamos una clase HtmlParserTool para manejar etiquetas HTML:
controlador de paquetes;
importar java.util.HashSet;
importar java.util.Set;
importar org.htmlparser.Node;
importar org.htmlparser.NodeFilter;
importar org.htmlparser.Parser;
importar org.htmlparser.filters.NodeClassFilter;
importar org.htmlparser.filters.OrFilter;
importar org.htmlparser.tags.LinkTag;
importar org.htmlparser.util.NodeList;
importar org.htmlparser.util.ParserException;
importar modelo.LinkFilter;
clase pública HtmlParserTool {
// Obtener enlaces en un sitio web, el filtro se utiliza para filtrar enlaces
conjunto estático público <String> extracLinks (URL de cadena, filtro LinkFilter) {
Establecer enlaces <String> = nuevo HashSet<String>();
intentar {
Analizador analizador = nuevo analizador (url);
parser.setEncoding("gb2312");
// Filtra la etiqueta <frame>, utilizada para extraer el atributo src en la etiqueta del marco
NodeFilter frameFilter = nuevo NodeFilter() {
serialVersionUID largo final estático privado = 1L;
@Anular
aceptación booleana pública (nodo nodo) {
if (node.getText().startsWith("frame src=")) {
devolver verdadero;
} demás {
devolver falso;
}
}
};
// OrFilter para establecer la etiqueta de filtro <a> y la etiqueta <frame>
OrFilter linkFilter = nuevo OrFilter (nuevo NodeClassFilter (
LinkTag.clase), frameFilter);
// Obtener todas las etiquetas filtradas
Lista de nodos = parser.extractAllNodesThatMatch(linkFilter);
para (int i = 0; i < lista.tamaño(); i++) {
Etiqueta de nodo = list.elementAt(i);
if (etiqueta instancia de LinkTag)// <a> etiqueta
{
Enlace LinkTag = etiqueta (LinkTag);
Cadena linkUrl = link.getLink();// URL
si (filtro.aceptar (enlaceUrl))
enlaces.add(enlaceUrl);
} else// etiqueta <marco>
{
// Extrae el enlace del atributo src en el marco, como <frame src="test.html"/>
Marco de cadena = tag.getText();
int inicio = frame.indexOf("src=");
marco = marco.subcadena (inicio);
int final = frame.indexOf(" ");
si (fin == -1)
final = frame.indexOf(">");
Cadena frameUrl = frame.substring(5, end - 1);
si (filtro.aceptar (frameUrl))
enlaces.add(frameUrl);
}
}
} captura (ParserException e) {
e.printStackTrace();
}
enlaces de retorno;
}
}
Finalmente, escribamos una clase de rastreador para llamar a la clase y función de encapsulación anterior:
controlador de paquetes;
importar java.util.Set;
importar modelo.LinkFilter;
importar modelo.SpiderQueue;
clase pública BfsSpider {
/**
* Inicializar la cola de URL usando semilla
*/
initCrawlerWithSeeds vacío privado (String [] semillas) {
para (int i = 0; i < semillas.longitud; i++)
SpiderQueue.addUnvisitedUrl(semillas[i]);
}
//Definir un filtro para extraer enlaces que comiencen con http://www.xxxx.com
rastreo de vacío público (String [] semillas) {
Filtro LinkFilter = nuevo LinkFilter() {
aceptación booleana pública (URL de cadena) {
si (url.startsWith ("http://www.baidu.com"))
devolver verdadero;
demás
devolver falso;
}
};
//Inicializar cola de URL
initCrawlerWithSeeds(semillas);
// Condición de bucle: el enlace a rastrear no está vacío y el número de páginas web rastreadas no supera las 1000
mientras (!SpiderQueue.unVisitedUrlsEmpty()
&& SpiderQueue.getVisitedUrlNum() <= 1000) {
//URL del encabezado de la cola retirada de la cola
Cadena visitUrl = (Cadena) SpiderQueue.unVisitedUrlDeQueue();
si (visitaUrl == nulo)
continuar;
DownTool downLoader = nuevo DownTool();
//Descargar pagina web
downLoader.downloadFile(visitaUrl);
// Pon esta URL en la URL visitada
SpiderQueue.addVisitedUrl(visitaUrl);
//Extrae la URL de la página web de descarga
Establecer enlaces <String> = HtmlParserTool.extracLinks (visitUrl, filtro);
// Nuevas URL no visitadas están en cola
para (enlace de cadena: enlaces) {
SpiderQueue.addUnvisitedUrl(enlace);
}
}
}
//entrada del método principal
público estático vacío principal (String [] argumentos) {
Rastreador BfsSpider = nuevo BfsSpider();
rastreador.crawling(new String[] { "http://www.baidu.com" });
}
}
Después de ejecutarlo, puede ver que el rastreador ha rastreado todas las páginas en la página web de Baidu:
Lo anterior es todo el contenido de Java que utiliza el kit de herramientas HttpClient y el rastreador de ancho para rastrear contenido. Es un poco más complicado, así que los amigos deberían pensarlo detenidamente, espero que pueda ser útil para todos.