Red de conocimiento informático - Espacio del host - Quiero aprender a rastrear sitios web. ¿Puede algún experto enviarme el código? Java, C#, C++ son todos aceptables, gracias de antemano. Correo electrónico: ds15221060249@163.com

Quiero aprender a rastrear sitios web. ¿Puede algún experto enviarme el código? Java, C#, C++ son todos aceptables, gracias de antemano. Correo electrónico: ds15221060249@163.com

C# es particularmente adecuado para construir programas araña porque tiene HTTP integrado y capacidades de subprocesos múltiples, los cuales son muy críticos para los programas araña. Las siguientes son las cuestiones clave que deben resolverse al construir un programa araña: ⑴ Análisis HTML: se necesita algún tipo de analizador HTML para analizar cada página encontrada por el programa araña.

⑵ Procesamiento de página: cada página descargada debe procesarse. El contenido descargado puede guardarse en el disco o analizarse y procesarse más a fondo.

⑶ Subprocesos múltiples: solo con capacidades de subprocesos múltiples los programas spider pueden ser verdaderamente eficientes.

⑷ Determine cuándo se completa: no subestime este problema. No es sencillo determinar si la tarea se ha completado, especialmente en un entorno de subprocesos múltiples.

1. Análisis de HTML

El analizador HTML proporcionado se implementa mediante la clase ParseHTML, que es muy conveniente de usar: primero cree una instancia de esta clase y luego establezca su atributo Fuente. documento HTML a analizar:

El siguiente es el fragmento de código:

ParseHTMLparse=newParseHTML();

parse.Source="HelloWorld";

Luego puedes usar un bucle para verificar todo el texto y las etiquetas contenidas en el documento HTML. Normalmente, el proceso de verificación puede comenzar con un bucle while que prueba el método Eof:

El siguiente es un fragmento de código:

while(!parse.Eof())

{

charch=parse.Parse();

El método Parse devolverá los caracteres contenidos en el documento HTML. El contenido devuelto solo contiene aquellos caracteres que no lo son. Etiquetas HTML. Si se encuentra una etiqueta HTML, el método Parse devolverá un valor de 0, lo que indica que ahora se encuentra una etiqueta HTML. Después de encontrar una etiqueta, podemos usar el método GetTag() para procesarla.

El siguiente es el fragmento de código:

if(ch==0)

{

HTMLTagtag=parse.GetTag() ;

}

Generalmente, una de las tareas más importantes de un programa araña es descubrir cada atributo HREF, lo que se puede lograr con la ayuda de la función de indexación de C#. Por ejemplo, el siguiente código extraerá el valor del atributo HREF si existe.

El siguiente es el fragmento de código:

Attributehref=tag["HREF"];

stringlink=href.Value;

Obtener atributo Después del objeto, el valor del atributo se puede obtener a través de Attribute.Value.

2. Procesamiento de páginas HTML

Veamos cómo procesar páginas HTML. Lo primero que debe hacer es, por supuesto, descargar la página HTML, lo que se puede lograr a través de la clase HttpWebRequest proporcionada por C#:

El siguiente es un fragmento de código:

HttpWebRequestrequest=( HttpWebRequest)WebRequest.Create(m_uri) ;

response=request.GetResponse();

stream=response.GetResponseStream();

A continuación creamos un transmitir desde la solicitud. Antes de realizar otro procesamiento, primero debemos determinar si el archivo es un archivo binario o un archivo de texto. Los diferentes tipos de archivos se procesan de manera diferente. El siguiente código determina si el archivo es un archivo binario.

El siguiente es el fragmento de código:

if(!response.ContentType.ToLower().StartsWith("text/"))

{

SaveBinaryFile(respuesta);

returnnull;

}

stringbuffer="", línea;

Si el El archivo no es un archivo de texto, lo leemos como un archivo binario. Si es un archivo de texto, primero cree un StreamReader a partir de la secuencia y luego agregue el contenido del archivo de texto al búfer línea por línea.

El siguiente es un fragmento de código:

reader=newStreamReader(stream);

while((line=reader.ReadLine())!=null)

p>

{

buffer+=line+"rn";

}

Después de cargar el archivo completo, debe guardarlo como un archivo de texto.

El siguiente es un fragmento de código:

SaveTextFile(buffer);

Echemos un vistazo a cómo se almacenan estos dos tipos diferentes de archivos.

La declaración del tipo de contenido del archivo binario no comienza con "texto/". El programa araña guarda directamente el archivo binario en el disco sin procesamiento adicional. Esto se debe a que el archivo binario no contiene HTML. entonces no lo hará. Luego está el HTML que la araña debe procesar. A continuación se detallan los pasos para escribir un archivo binario.

Primero prepare un búfer para almacenar temporalmente el contenido del archivo binario.

El siguiente es un fragmento de código:

byte[]buffer=newbyte[1024];

El siguiente paso es determinar la ruta y el nombre del archivo guardado localmente. Si desea descargar el contenido de un sitio web myhost.com a la carpeta local c:test, la ruta en línea y el nombre del archivo binario son, entonces la ruta local y el nombre deben ser c:testimageslogo.gif. Al mismo tiempo, también debemos asegurarnos de que el subdirectorio de imágenes se haya creado en el directorio c:test. Esta parte de la tarea se completa con el método convertFilename.

El siguiente es un fragmento de código:

stringfilename=convertFilename(response.ResponseUri);

El método convertFilename separa la dirección HTTP y crea la estructura de directorio correspondiente. . Después de determinar el nombre y la ruta del archivo de salida, puede abrir la secuencia de entrada para leer la página web y la secuencia de salida para escribir el archivo local.

El siguiente es el fragmento de código:

StreamoutStream=File.Create(filename);

StreaminStream=response.GetResponseStream();

A continuación, puede leer el contenido del archivo web y escribirlo en un archivo local, lo que se puede hacer fácilmente mediante un bucle.

El siguiente es el fragmento de código:

intl;

do

{

l=inStream. Read( buffer, 0,

buffer.Length);

if(l>0)

outStream.Write(buffer, 0, l);

}

while(l>0);

3. Multiproceso

Usamos la clase DocumentWorker para encapsular todas las operaciones de descargando una URL. Cada vez que se crea una instancia de DocumentWorker, ingresa en un bucle esperando que se procese la siguiente URL.

El siguiente es el bucle principal de DocumentWorker:

El siguiente es el fragmento de código:

while(!m_spider.Quit)

{

m_uri= m_spider.ObtainWork();

m_spider.SpiderDone.WorkerBegin();

stringpage=GetPage();

if(página!= null)

p>

ProcessPage(page);

m_spider.SpiderDone.WorkerEnd();

}

Este bucle se ejecutará hasta que la marca de salida se establezca en verdadero (cuando el usuario presiona el botón "Cancelar", la bandera de salida se establece en verdadero). Dentro del bucle, llamamos a ObtenerWork para obtener una URL. GetWork esperará hasta que esté disponible una URL que solo se puede obtener analizando el documento y buscándolo en otros hilos. La clase Done utiliza los métodos WorkerBegin y WorkerEnd para determinar cuándo se ha completado toda la operación de descarga.

Como se puede ver en la Figura 1, el programa araña permite a los usuarios determinar la cantidad de subprocesos a usar. En la práctica, el número óptimo de subprocesos se ve afectado por muchos factores. Si su máquina tiene un alto rendimiento o tiene dos procesadores, puede configurar una mayor cantidad de subprocesos; por el contrario, si el ancho de banda de la red y el rendimiento de la máquina son limitados, configurar demasiados subprocesos no necesariamente mejorará el rendimiento.

4. ¿Se completó la tarea?

El uso de varios subprocesos para descargar archivos al mismo tiempo mejora efectivamente el rendimiento, pero también trae problemas de administración de subprocesos. Una de las preguntas más complejas es: ¿cuándo completa su trabajo el programa araña? Aquí necesitamos usar una clase dedicada Hecho para juzgar.

En primer lugar, es necesario explicar el significado específico de "hacer el trabajo". El trabajo de la araña se completa sólo cuando no hay URL esperando ser descargadas en el sistema y todos los subprocesos de trabajo han terminado su procesamiento. Dicho esto, hacer el trabajo significa que no hay más descargas pendientes ni URL descargadas.

La clase Done proporciona un método WaitDone, cuya función es esperar hasta que el objeto Done detecte que el programa araña ha completado su trabajo. A continuación se muestra el código para el método WaitDone.

El siguiente es el fragmento de código:

publicvoidWaitDone()

{

Monitor.Enter(this);

mientras(m_activeThreads>0)

{

Monitor.Esperar(esto);

}

Monitor.Salir( this) ;

}

El método WaitDone esperará hasta que no haya más hilos activos. Sin embargo, debe tenerse en cuenta que no hay subprocesos activos en la etapa inicial de descarga, por lo que es fácil hacer que el programa araña se detenga inmediatamente tan pronto como se inicia. Para resolver este problema, también necesitamos otro método, WaitBegin, para esperar a que el programa araña entre en la fase de trabajo "formal". La secuencia de llamada general es: primero llame a WaitBegin y luego llame a WaitDone. WaitDone esperará a que el programa araña complete su trabajo.

El siguiente es el código para WaitBegin:

El siguiente es el fragmento de código:

publicvoidWaitBegin()

{

Monitor.Enter (esto);

mientras(!m_started)

{

Monitor.Espera(esto);

}

Monitorear .Exit(this);

Citado del blog de Felomeng en el artículo "Producción de programas rastreadores/araña (lenguaje C#)", se ha introducido el método básico de implementación del programa rastreador. Dijo que se ha implementado la funcionalidad Crawler. Es solo que hay un problema de eficiencia y la velocidad de descarga puede ser lenta. Esto se debe a dos motivos:

1. El análisis y la descarga no se pueden realizar simultáneamente. Los dos pasos del programa rastreador se presentaron en "Producción del programa Crawler/Spider (lenguaje C#)": análisis y descarga. En un programa de un solo subproceso, los dos no se pueden ejecutar al mismo tiempo. En otras palabras, la red estará inactiva durante el análisis. Cuanto mayor sea el tiempo de análisis, menor será la eficiencia de la descarga. Lo contrario también es cierto. El análisis no se puede realizar al mismo tiempo durante la descarga. El siguiente paso del análisis solo se puede realizar después de detener la descarga. El problema ha surgido y creo que todos pensarán: ¿no se resolvería el problema si el análisis y la descarga se realizaran en diferentes subprocesos?

2. Solo descarga de un solo subproceso. Creo que todos han tenido experiencia descargando recursos como Internet Express, en el que se puede configurar la cantidad de subprocesos (el valor predeterminado en versiones recientes es 10 y el valor predeterminado era 5 en el pasado). Dividirá el archivo en partes iguales al número de subprocesos y luego cada subproceso descargará su propia parte, de modo que se pueda mejorar la eficiencia de la descarga. Creo que todos tienen experiencia en aumentar la cantidad de subprocesos para mejorar la eficiencia de la descarga. Pero los usuarios cuidadosos encontrarán que cuando el ancho de banda es cierto, cuantos más subprocesos, más rápida será la velocidad, pero alcanzará un pico en un punto determinado. Como herramienta de descarga especial, ¿cómo puede un rastreador ser eficiente sin capacidades de subprocesos múltiples? ¿No es el propósito de los rastreadores en la era de la información no obtener información rápidamente? Por lo tanto, el rastreador necesita varios subprocesos (un número controlable) para descargar páginas web al mismo tiempo.

Bien, después de comprender y analizar el problema, es hora de resolverlo:

No es difícil implementar varios subprocesos en C#. Tiene un espacio de nombres: System.Threading, que proporciona soporte para subprocesos múltiples.

Para iniciar un nuevo hilo, se requiere la siguiente inicialización:

ThreadStart startDownload = new ThreadStart( DownLoad

//Configuración de inicio del hilo: es decir; , cada hilo ejecuta DownLoad() Nota: DownLoad() debe ser un método sin parámetros

Descarga del hiloThread = new Thread(startDownload); //Crea una instancia de la nueva clase que se abrirá

downloadThread.Start();//Iniciar el hilo

Dado que el método iniciado al principio del hilo no puede tener parámetros, esto agrega problemas a los recursos compartidos de subprocesos múltiples. Sin embargo, podemos usar variables a nivel de clase (por supuesto, también podemos usar otros métodos, creo que este método es el más simple y fácil de usar) para resolver este problema. Después de saber cómo habilitar la descarga multiproceso, es posible que tengas varias preguntas:

1.

2. ¿Cómo evitar que varios hilos descarguen la misma página web?

3. ¿Cómo juzgar el final de un hilo?

4. ¿Cómo controlar el final de un hilo?

Las siguientes son soluciones a estos problemas:

1. El número de subprocesos se puede lograr mediante un bucle for, al igual que el programa dot que utilizan los principiantes para programar.

Por ejemplo, se sabe que el usuario ha especificado n subprocesos (es una variable de tipo int). Puede utilizar el siguiente método para iniciar cinco subprocesos.

Thread[] downloadThread;

// Hilo de descarga de declaración, esta es la ventaja de C#, es decir, cuando se inicializa la matriz, no es necesario especificar su longitud. sólo se puede especificar cuando se utiliza.

Esta declaración debe ser a nivel de clase, lo que también brinda la posibilidad de que otros métodos las controlen

ThreadStart startDownload = new ThreadStart( DownLoad );

// Configuración de inicio del subproceso: es decir, cada subproceso ejecuta DownLoad()

downloadThread = new Thread[ n ];//Aplica recursos para el subproceso y determina el número total de subprocesos

for( int i = 0; i < n; i++ )//Abrir el número especificado de subprocesos

{

downloadThread[i] = new Thread( startDownload );// Especifique la configuración de inicio del hilo

downloadThread[i].Start();//Abra los hilos uno por uno

}

Bien, ¿es muy sencillo controlar el número de hilos abiertos?

2. A continuación surge una pregunta: Todos los hilos llaman al método DonwLoad(), entonces, ¿cómo evitar que descarguen la misma página web al mismo tiempo?

Este problema es fácil de resolver. Simplemente cree una tabla de direcciones URL y cada dirección de la tabla solo podrá ser solicitada por un hilo. Implementación específica:

Puede usar la base de datos para crear una tabla con cuatro columnas, una de las cuales se usa específicamente para almacenar la dirección URL y las otras dos columnas almacenan el hilo correspondiente a la dirección y el número. de veces que se ha solicitado la dirección. La última columna almacena el contenido descargado. (Por supuesto, no es necesaria una columna correspondiente al hilo). Cuando se aplica un hilo, establezca la columna correspondiente al hilo en el número de hilo actual y configure la columna si se ha aplicado una vez para que se aplique una vez, de modo que otros hilos no puedan postularse para la página. Si la descarga se realiza correctamente, el contenido se almacena en la columna de contenido. Si no tiene éxito, la columna de contenido permanecerá vacía como una de las bases para volver a descargar. Si no tiene éxito repetidamente, el proceso se aplicará para el siguiente después de alcanzar el número de reintentos (correspondiente al número de veces que se realizó la descarga). dirección URL solicitada, que el usuario puede configurar).

El código principal es el siguiente (tomando VFP como ejemplo):

CREATE TABLE (ctablename) ( curl M , ctext M , ldowned I , threadNum I )

&&Cree una tabla ctablename.dbf, que incluya la dirección, el contenido del texto, el número de intentos de descarga y el indicador del hilo (el valor inicial es -1, el indicador del hilo es un número entero que comienza en 0) Campo

cfullname = (ctablename) + '.dbf'&&Agregar extensión a la tabla

USE (cfullname)

IR ARRIBA

LOCALIZAR PARA (EMPTY( ALLTRIM( ctext ) ) AND ldowned < 2 AND

( threadNum = thisNum OR threadNum = - 1) )

&&Encuentre la dirección URL que no se ha descargado correctamente y debe descargarse y pertenece a los permisos de este hilo. thisNum es el número del hilo actual.

Se puede obtener pasando parámetros

gotUrl =. curl

recNum = RECNO()

IF recNum <= RECCOUNT() THEN &&Si dicha dirección URL se encuentra en la lista

ACTUALIZAR (cfullname) SET ldowned = (ldowned + 1), threadNum =

thisNum WHERE RECNO() = recNum &&Actualiza la tabla, actualiza este registro a aplicado, es decir, suma 1 al número de descargas,

Columna de indicador de hilo Establezca el número de este hilo.

cfulltablename = (ctablename) + '.dbf'

USE (cfulltablename)

ESTABLECER EXACTO EN

LOCATE FOR curl = (csiteurl) && csiteurl es un parámetro, que es la dirección URL correspondiente al contenido descargado

recNumNow = RECNO()&&Obtenga el número de registro que contiene esta dirección

p>

UPDATE (cfulltablename) SET ctext = (ccontent) WHERE RECNO() =

recNumNow &&Inserte el contenido correspondiente de la dirección correspondiente

ctablename = (ctablename) + '.dbf'

USE (ctablename)

IR ARRIBA

ESTABLECER EXACTO EN

LOCATE FOR curl = (cnewurl) &&Buscar si esta dirección existe

IF RECNO() > RECCOUNT() THEN &&Si no existe dicha dirección

SET CARRY OFF

INSERT INTO (ctablename) ( curl , ctext , ldowned , threadNum )

VALUES ( (cnewurl) , "" , 0 , -1 ) &&Agregue la dirección de la página de inicio a la lista

Bien, esto resuelve el conflicto de subprocesos en subprocesos múltiples. Por supuesto, el problema de la deduplicación también se puede resolver en el lenguaje C#. Simplemente cree un archivo temporal (solo texto), guarde todas las direcciones URL y establezca los atributos correspondientes para ellas, pero es posible que la eficiencia de la búsqueda no sea tan rápida. base de datos.

***2 páginas

3. Es difícil juzgar el final del hilo porque siempre está buscando nuevos enlaces. El usuario piensa que se puede suponer que después de que el hilo se repite N veces y aún no puede solicitar una nueva dirección URL, se puede considerar que ha descargado todos los enlaces. El código principal es el siguiente:

string url = "";

int times = 0;

while ( url == "" )//If no se encuentra ninguna coincidencia Registros condicionales, luego busque continuamente registros que cumplan las condiciones

{

url = getUrl.GetAUrl(……);//Llame al método GetAUrl para intentar obtener un valor de URL

p>

if (url == "")//Si no se encuentra

{

veces ++;//El número de los intentos se incrementan

continuar; //Hacer el siguiente intento

}

if ( times > N ) //Si se han realizado suficientes intentos, salir del proceso

{

downloadThread[i].Abort; //Salir del proceso

}

else//Si no lo has hecho intentado suficientes veces

{

Veces = 0 //Restablecer el número de intentos a cero

}

//Continuar con el siguiente paso de procesar la URL obtenida

}

4 Esta pregunta es relativamente simple, porque en la pregunta 1 se sugirió que el hilo se declare como una matriz de nivel de clase. , para que sea fácil de controlar. Simplemente use un bucle for para finalizarlo.

El código es el siguiente:

for( int i = 0; i < n; i++ )//Cerrar el número especificado de subprocesos n

{

downloadThread[i ].Abort();//Cerrar hilos uno por uno

}

Bien, así es como se completa un programa araña Frente a C#, su implementación gira. resulta ser tan simple.

Aquí el autor también quiere recordar a los lectores: el autor solo proporciona una idea y una solución alcanzable, pero no es la mejor. Incluso la solución en sí tiene muchas áreas de mejora, lo que deja al lector pensando.

Finalmente, déjame explicarte el entorno que estoy usando:

winXP sp2 Pro

VFP 9.0

Visual Studio 2003 .net chino Edición empresarial