2014-10-17 10 views
5

Also habe ich ein Website-Scraper-Programm in C# mit dem HTML Agility-Paket geschrieben. Das war ziemlich geradlinig. Selbst wenn Inkonsistenzen bei der Formatierung auf der Webseite berücksichtigt wurden, brauchte ich nur ein paar Stunden, um zu arbeiten.Wie scrape ich eine Webseite mit C?

Jetzt muss ich dieses Programm in C neu implementieren, damit es in einer Linux-Umgebung ausgeführt werden kann. Dies ist ein großer Albtraum.

Ich kann die Seite zurückziehen, aber wenn es darum geht, durch sie zu ziehen, um die Teile herauszuziehen, die mich interessieren - ich zeichne viele Leerzeichen. Ursprünglich wollte ich eine Lösung implementieren, die meiner HTML-Agility-Option in C# ähnelte, außer mit Tidy und einer anderen XML-Bibliothek, damit ich meine Logik mehr oder weniger beibehalten konnte.

Das hat nicht so gut funktioniert. Die XML-Bibliothek, auf die ich Zugriff habe, scheint xpath nicht zu unterstützen, und ich kann keine installieren, die dies tut. Also habe ich versucht, einen Weg zu finden, die Seite zu lesen, indem ich einen String-Matching verwende, um die gewünschten Daten zu finden. Ich kann nicht anders als zu glauben, dass es einen besseren Weg dafür geben muss.

Hier ist, was ich habe:

#define HTML_PAGE "codes.html" 

int extract() 
{ 

    FILE *html; 

    int found = 0; 
    char buffer[1000]; 
    char searchFor[80], *cp; 

    html = fopen(HTML_PAGE, "r"); 

    if (html) 
    { 

     // this is too error prone, if the buffer cuts off half way through a section of the string we are looking for, it will fail! 
     while(fgets(buffer, 999, html)) 
     { 
      trim(buffer); 

      if (!found) 
      { 
       sprintf(searchFor, "<strong>"); 
       cp = (char *)strstr(buffer, searchFor); 
       if(!cp)continue; 

       if (strncmp(cp + strlen(searchFor), "CO1", 3) == 0 || strncmp(cp + strlen(searchFor), "CO2", 3) == 0) 
       { 
        got_code(cp + strlen(searchFor)); 
       } 
      } 
     } 
    } 

    fclose(html); 

    return 0; 
} 

got_code(html) 
    char *html; 
{ 
    char code[8]; 
    char *endTag; 
    struct _code_st *currCode; 
    int i; 

    endTag = (char *)strstr(html, "</strong>"); 
    if(!endTag)return; 

    sprintf(code, "%.7s", html); 

    for(i=0 ; i<Data.Codes ; i++) 
     if(strcasecmp(Data.Code[i].Code, code)==0) 
      return; 

    ADD_TO_LIST(currCode, _code_st, Data.Code, Data.Codes); 
    currCode->Code = (char *)strdup(code); 

    printf("Code: %s\n", code); 
} 

Die oben nicht richtig funktioniert. Ich bekomme viele der Codes, die mich interessieren, aber wie ich oben erwähnt habe, wenn der Puffer an den falschen Stellen abschneidet, vermisse ich etwas.

Ich habe gerade versucht, den ganzen Teil von HTML zu lesen, an dem ich interessiert bin, in eine Zeichenfolge, aber ich konnte nicht herausfinden, wie man das durchläuft - ich konnte keine Codes angezeigt bekommen.

Weiß jemand, wie ich dieses Problem lösen kann?

EDIT: Ich habe darüber mehr nachgedacht. Gibt es irgendeine Möglichkeit, in der Datei nach vorne zu schauen und nach dem Ende jedes 'Blocks' des zu analysierenden Textes zu suchen und die Puffergröße so einzustellen, dass ich sie lesen kann? Benötige ich einen anderen Dateizeiger für dieselbe Datei? Dies würde (hoffentlich) das Problem des Abschneidens des Puffers an ungünstigen Stellen verhindern.

+0

Vielleicht mit Mono laufen? –

+5

C ist großartig, aber nicht für diese Art von Aufgabe. Verwenden Sie stattdessen etwas anderes, wie Perl oder Python. Hölle, würde sogar PHP tun. –

+0

Ja, ich muss zustimmen. Es fühlt sich einfach wie das falsche Werkzeug für den Job an. –

Antwort

5

Okay, nachdem ich mich mit dem Kopf gegen die Wand geschlagen hatte und versuchte, einen Weg zu finden, meinen obigen Code funktionieren zu lassen, entschied ich mich für einen etwas anderen Ansatz.

Da ich wusste, dass die Daten auf der Seite, die ich scrapping ist in einer großen Zeile enthalten, änderte ich meinen Code, um die Datei zu durchsuchen, bis es gefunden wurde. Dann gehe ich die Linie entlang und suche nach den Blöcken, die ich haben wollte. Dies funktionierte überraschend gut und nachdem ich den Code einige der Blöcke gelesen hatte, war es leicht, kleinere Änderungen vorzunehmen, um Inkonsistenzen im HTML zu berücksichtigen. Der Teil, der am längsten dauerte, war herauszufinden, wie man aussteigen kann, sobald ich das Ende der Linie erreicht hatte, und ich löste das, indem ich vorauseilte, um sicherzustellen, dass es einen weiteren Block zum Lesen gab.

Hier ist mein Code (die hässlich, aber funktionell ist):

#define HTML_PAGE "codes.html" 
#define START_BLOCK "<strong>" 
#define END_BLOCK "</strong>" 

int extract() 
{ 

    FILE *html; 

    int found = 0; 
    char *line = NULL, *endTag, *startTag; 
    size_t len = 0; 
    ssize_t read; 

    char searchFor[80]; 

    html = fopen(HTML_PAGE, "r"); 

    if (html) 
    { 
     while((read = getline(&line, &len, html)) != -1) 
     { 
      if (found) // found line with codes we are interested in 
      { 
       char *ptr = line; 
       size_t nlen = strlen (END_BLOCK); 

       while (ptr != NULL) 
       { 
        sprintf(searchFor, START_BLOCK); 
        startTag = (char *)strstr(ptr, searchFor); 
        if(!startTag) 
        { 
         nlen = strlen (START_BLOCK); 
         ptr += nlen; 
         continue; 
        } 

        if (strncmp(startTag + strlen(searchFor), "CO1", 3) == 0 || strncmp(startTag + strlen(searchFor), "CO2", 3) == 0) 
         got_code(startTag + strlen(searchFor), code); 
        else { 
         nlen = strlen (START_BLOCK); 
         ptr += nlen; 
         continue; 
        } 

        sprintf(searchFor, END_BLOCK); 
        ptr = (char *)strstr(ptr, searchFor); 

        if (!ptr) { found = 0; break; } 

        nlen = strlen (END_BLOCK);     
        ptr += nlen; 

        if (ptr) 
        { 
         // look ahead to make sure we have more to pull out 
         sprintf(searchFor, END_BLOCK); 
         endTag = (char *)strstr(ptr, searchFor); 
         if (!endTag) { break; } 
        } 
       } 

       found = 0; 
       break; 
      } 

      // find the section of the downloaded page we care about 
      // the next line we read will be a blob containing the html we want 
      if (strstr(line, "wiki-content") != NULL) 
      { 
       found = 1; 
      } 
     } 

     fclose(html); 
    } 

    return 0; 
} 

got_code(char *html) 
{ 
    char code[8]; 
    char *endTag; 
    struct _code_st *currCode; 
    int i; 

    endTag = (char *)strstr(html, "</strong>"); 
    if(!endTag)return; 

    sprintf(code, "%.7s", html); 

    for(i=0 ; i<Data.Codes ; i++) 
     if(strcasecmp(Data.Code[i].Code, code)==0) 
      return; 

    ADD_TO_LIST(currCode, _code_st, Data.Code, Data.Codes); 
    currCode->Code = (char *)strdup(code); 

    printf("Code: %s\n", code); 
} 

Nicht annähernd so elegant oder robust wie mein C# -Programm, aber zumindest es zieht zurück alle Informationen, die ich will.

Verwandte Themen