El rastreador abre la URL
(1) Análisis HTML: necesita algún tipo de analizador HTML para analizar cada página que encuentre 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.
(4) Determine cuándo se completa: no subestime este problema. No es fácil determinar si la tarea se ha completado, especialmente en un entorno de subprocesos múltiples.
Primero, análisis HTML
El analizador HTML proporcionado en este artículo está implementado mediante la clase ParseHTML, que es muy conveniente de usar: primero cree una instancia de esta clase y luego configure su propiedad Fuente Para que se analice el documento HTML:
parse html parse = new parse html();
Analizar. Source = "<p>Hola mundo</p>;
A continuación, puede utilizar un bucle para verificar todo el texto y las etiquetas contenidas en el documento HTML. Normalmente, el proceso de verificación se puede iniciar desde el método de prueba Eof. El bucle while comienza:
while(!parse.Eof())
{
char ch = parse();
< El p> El método Parse devolverá los caracteres contenidos en el documento HTML; el contenido que devuelve solo contiene aquellos caracteres que no son etiquetas HTML. Si se encuentra una etiqueta HTML, el método Parse devolverá un valor de 0, lo que indica que se encuentra una etiqueta HTML. , podemos usar el método GetTag() para manejarloIf (ch==0)
{
HTMLTag = Parse. >
}
En términos generales, una de las tareas más importantes de un programa araña es descubrir varios atributos HREF, lo que se puede realizar a través de la función de índice de C#. Por ejemplo, el siguiente código lo hará. Extraiga el valor del atributo HREF (si existe).
attribute href = tag[" HREF "]
string link = href value
Obtener el atributo. Después del objeto, el valor del atributo se puede obtener a través de Attribute.Value
En segundo lugar, procesar la página HTML
Lo primero que debe hacer es, por supuesto. La descarga de páginas HTML se puede realizar a través de la clase HttpWebRequest proporcionada por C#:
HttpWebRequest request = (HttpWebRequest)WebRequest.
Response = GetResponse(). /p>
Secuencia = respuesta.
A continuación, crearemos una secuencia basada en la solicitud. Antes de realizar otro procesamiento, debemos determinar si el archivo es binario o Archivos de texto, un archivo diferente. Los tipos tienen diferentes métodos de procesamiento. El siguiente código determina si el archivo es un archivo binario
If (! Response.ToLower().StartsWith("text/")
{<. /p>
SaveBinaryFile(respuesta);
Devolver nulo
}
búfer de cadena = ", OK;
Si 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.
lector = new StreamReader(flujo);
mientras( (línea = lector.ReadLine())!=null)
{
buffer+= line+"\r\n";
}
Después de cargar el archivo completo, debes guardarlo como un archivo de texto.
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. Debido a que el archivo binario no contiene HTML, habrá. no más HTML. El enlace requiere procesamiento de araña. 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. byte[]buffer = new byte[1024];
A continuación, determine 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 es /images/logo.gif, entonces la ruta local y el nombre deben ser c:\ test c: \test\images\logo.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.
string filename = convertFilename(response.response uri);
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.
Salida del flujo flujo = archivo. crear(nombre de archivo);
Stream inStream = respuesta. GetResponseStream();
A continuación, puede leer el contenido del archivo web y escribirlo en un archivo local, lo que se puede hacer fácilmente con un bucle.
int l;
do
{
l = en la secuencia. read(buffer, 0,
buffer. length);
if (l & gt0)
salida. Write(buffer, 0, l);
} while (l & gt; 0);
Tercero, subprocesos múltiples
Usamos la clase DocumentWorker. encapsulación Todas las operaciones en la URL de descarga. Cada vez que se crea una instancia de DocumentWorker, ingresa a un bucle en espera de procesar la siguiente URL. El siguiente es el bucle principal de DocumentWorker:
And (!m_spider.exit)
{
m_uri = m_spider. obtener trabajo();
m_spider. araña hecho. trabajador comenzar();
página de cadena = obtener página();
If (página!=null)
ProcessPage(página); /p>
m _Araña. spider done . work end();
}
El bucle se ejecutará hasta que el indicador de salida se establezca en verdadero (cuando el usuario hace clic en el botón "Cancelar", el indicador de salida se activa). establecido en verdadero). Dentro del bucle, llamamos al trabajo del observador para obtener una URL. GetWork esperará hasta que la URL esté disponible; otros hilos la obtendrán analizando el documento y buscando enlaces. La clase Done utiliza los métodos WorkerBegin y WorkerEnd para determinar cuándo se completa toda la operación de descarga.
Como se puede observar en la Figura 1, el programa araña permite al usuario decidir el número de hilos a utilizar. 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 más subprocesos. Por otro lado, 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.
En cuarto lugar, ¿se ha completado la tarea?
El uso de múltiples subprocesos para descargar archivos simultáneamente mejora efectivamente el rendimiento, pero también genera problemas de administración de subprocesos. Una de las preguntas más complicadas es: ¿cuándo termina la araña su trabajo? Aquí necesitamos usar una clase especial para emitir juicios.
Primero, es necesario explicar qué significa exactamente “hacer el trabajo”. El trabajo del programa araña se completa sólo cuando no hay URL esperando ser descargadas en el sistema y todos los subprocesos de trabajo han completado su trabajo de procesamiento. En otras palabras, hacer el trabajo significa que no hay descargas en espera ni URL descargadas.
La clase Done proporciona un método WaitDone, que se utiliza para 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.
public void WaitDone()
{
Monitor. enter(this);
while(m_active threads >0)
{
Monitor. Espera(esto);
}
Monitorizar. exit(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, lo que fácilmente puede hacer que el programa araña se detenga inmediatamente tan pronto como se inicia. Para resolver este problema, 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, luego llame a WaitDone. WaitDone esperará a que el programa araña complete su trabajo. El siguiente es el código para WaitBegin:
public void WaitBegin()
{
Monitor. enter(esto);
mientras(!m_started)
{
monitorear. Espera(esto);
}
Monitorizar. exit(this);
}
El método WaitBegin esperará hasta que se establezca el indicador m_started. El indicador m_started lo establece el método WorkerBegin. WorkerStart; se llamará cuando el subproceso de trabajo comience a procesar cada URL; se llamará a WorkerEnd cuando finalice el procesamiento. WorkerBegin y workend ayudan al objeto Done a determinar su estado de trabajo actual. El siguiente es el código para el método WorkerBegin:
public void WorkerBegin()
{
Monitor. enter(this);
m_active threads++;
m_started = true
Monitor. Pulso(este);
Monitorizar. Salir (esto);
}
El método WorkerBegin primero aumenta el número de subprocesos activos actualmente, luego establece el indicador m_started y finalmente llama al método Pulse para notificar a los subprocesos en espera. el hilo de trabajo para comenzar. Como se mencionó anteriormente, el método que puede esperar al objeto Done es el método WaitBegin. El método WorkerEnd se llama cada vez que se procesa una URL:
Public void WorkTrend()
{
Monitor. enter(this);
m_hilos activos-;
Monitor. Pulso(este);
Monitorizar.
Salir (this);
}
El método WorkerEnd disminuye el contador de subprocesos activos de m_activeThreads y llama a Pulse para liberar subprocesos que pueden estar esperando el objeto Done; como se mencionó anteriormente, puede Estar esperando el objeto Done. El método es el método WaitDone.