2008-12-23 19 views
26

Quiero escribir un programa en C/C++ que lea dinámicamente una página web y extraiga información de ella. Como ejemplo imagine si desea escribir una aplicación para seguir y registrar una subasta de eBay. ¿Hay alguna manera fácil de obtener la página web? Una biblioteca que proporciona esta funcionalidad? ¿Y hay una manera fácil de analizar la página para obtener los datos específicos?Lectura programática de una página web

+6

muy difícil en C/C++. Es lo suficientemente molesto incluso en idiomas que tienen un amplio soporte para expresiones regulares, análisis XML, métodos HTTP, etc. (por ejemplo, Java). En cuanto a Ebay, tiene una API que deberías usar. – cletus

Respuesta

35

Tener un vistazo a la cURL library:

#include <stdio.h> 
#include <curl/curl.h> 

int main(void) 
{ 
    CURL *curl; 
    CURLcode res; 

    curl = curl_easy_init(); 
    if(curl) { 
    curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se"); 
    res = curl_easy_perform(curl); 
     /* always cleanup */ 
    curl_easy_cleanup(curl); 
    } 
    return 0; 
} 

Por cierto, si no es estrictamente necesario en C++. Te animo a probar C# o Java. Es mucho más fácil y hay una forma integrada.

+4

+1 para cURL - He utilizado cURL en una de mis aplicaciones C++ y funciona muy bien, incluso con proxies y todos los demás obstáculos que pueda encontrar. – BlaM

+0

¡Es bueno aconsejar el uso de la herramienta adecuada para el trabajo! – xtofl

+2

Sería mejor devolver un error si curl es nulo (en el ejemplo anterior). –

2

Puede hacerlo con la programación del socket, pero es complicado implementar las partes del protocolo necesarias para buscar una página de manera confiable. Es mejor usar una biblioteca, como neon. Es probable que esté instalado en la mayoría de las distribuciones de Linux. En FreeBSD usa la biblioteca de búsqueda.

Para analizar los datos, porque muchas páginas no usan XML válido, debe implementar heurística, no un analizador real basado en yacc. Puede implementar estos usando expresiones regulares o una máquina de transición de estado. Como lo que intenta hacer implica mucho ensayo y error, es mejor utilizar un lenguaje de scripting, como Perl. Debido a la alta latencia de la red, no verá ninguna diferencia en el rendimiento.

+0

Si bien no son XML válidos, muchos idiomas tienen bibliotecas que tienen analizadores HTML, que le permitirán usar una interfaz DOM para analizar un documento HTML. –

+0

Sí, el neón también es agradable (pero la mayor parte de mi experiencia es con curl, como se menciona en la respuesta de m3rLinEz. ¿Alguna comparación en algún lado? – bortzmeyer

2

Intente utilizar una biblioteca, como Qt, que puede leer datos de una red y obtener datos de un documento xml. This es un ejemplo de cómo leer un feed xml. Podría usar el feed de eBay, por ejemplo.

2

Hay una biblioteca de TCP/IP gratuita disponible para Windows que admite HTTP y HTTPS, su uso es muy sencillo.

Ultimate TCP/IP

CUT_HTTPClient http; 
http.GET("http://folder/file.htm", "c:/tmp/process_me.htm");  

también se puede obtener archivos y almacenarlos en una memoria intermedia (vía CUT_DataSource clases derivadas). Todo el soporte HTTP habitual está ahí: PUT, HEAD, etc. La compatibilidad con los servidores proxy es muy fácil, al igual que los sockets seguros.

3

No menciona ninguna plataforma, por lo que le doy una respuesta para Win32.

Una forma sencilla de descargar cualquier cosa del Internet es el URLDownloadToFile con el parámetro establecido en IBindStatusCallbackNULL. Para hacer que la función sea más útil, la interfaz de devolución de llamada debe implementarse.

14

código de Windows:

#include <winsock2.h> 
#include <windows.h> 
#include <iostream> 
#pragma comment(lib,"ws2_32.lib") 
using namespace std; 
int main(){ 
    WSADATA wsaData; 
    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { 
     cout << "WSAStartup failed.\n"; 
     system("pause"); 
     return 1; 
    } 
    SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); 
    struct hostent *host; 
    host = gethostbyname("www.google.com"); 
    SOCKADDR_IN SockAddr; 
    SockAddr.sin_port=htons(80); 
    SockAddr.sin_family=AF_INET; 
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr); 
    cout << "Connecting...\n"; 
    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){ 
     cout << "Could not connect"; 
     system("pause"); 
     return 1; 
    } 
    cout << "Connected.\n"; 
    send(Socket,"GET/HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n", strlen("GET/HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n"),0); 
    char buffer[10000]; 
    int nDataLength; 
    while ((nDataLength = recv(Socket,buffer,10000,0)) > 0){   
     int i = 0; 
     while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') { 
      cout << buffer[i]; 
      i += 1; 
     } 
    } 
    closesocket(Socket); 
     WSACleanup(); 
    system("pause"); 
    return 0; 
} 
+1

Tenga cuidado al publicar copiar y pegar las respuestas al pie de página o verbatim a preguntas múltiples, estas tienden a ser señaladas como "spam" por la comunidad. Si está haciendo esto, generalmente significa que las preguntas son duplicadas, así que márquelas como tales en su lugar: http://stackoverflow.com/a/12374407/419 – Kev

Cuestiones relacionadas