C :: Aufgabe #90 :: Lösung #1

1 Lösung Lösung öffentlich
#90

Web Request: Titel anzeigen

Fortgeschrittener - C von Alucard1766 - 24.08.2015 um 10:36 Uhr
Ziel ist es, nach Eingabe einer Aufgabennummer, den zugehörigen Titel der C# Aufgabe auf http://trainyourprogrammer.de/csharp auszugeben. Dies mittels eines http web requests.

Beispiele

Konsolenausgabe:

Gib die Aufgabennummer ein: 42
Titel: 99 Bottles of Beer - Selbstständige Lösung


Konsolenausgabe:

Gib die Aufgabennummer ein: 999
Aufgabe nicht gefunden.
#1
vote_ok
von devnull (8870 Punkte) - 27.12.2015 um 18:07 Uhr
Im Lösungsprogramm werden folgende Libraries benutzt:
- libcurl
- htmlstreamparser
Die libcurl ist auf einem Linux-System normalerweise immer dabei.

Die C#-Seiten von http://trainyourprogrammer.de werden sequentiell nach der geforderten Aufgabennummer durchsucht.
Dies lässt sich sicher noch optimieren.
Anwendungsbeispiel:

Konsolenausgabe:

$ ./webreq 85
Suche auf http://trainyourprogrammer.de (C#)
Suche auf Seite 1
Suche auf Seite 2
Suche auf Seite 3
Titel #85: "Alle Harshad-Zahlen von 1 bis 100 berechnen"

Quellcode ausblenden C-Code
/*******************************
 * webreq.c  Titel anzeigen (C#)
 *******************************/
#include <stdio.h>
#include <curl/curl.h>
#include <htmlstreamparser.h>

#define WEBURL "http://trainyourprogrammer.de"

#define MAX_LEN   255
#define MAX_PAGES  12

#define min(x,y) ((x) < (y)) ? (x) : (y)

typedef enum _parse_state {
	INITIALIZED,
	TOPIC_HREF_FOUND,
	TITLE_CLASS_FOUND,
	TITLE_SPAN_FOUND,
	TITLE_TEXT_FOUND,
	FINISHED
} parse_state_t;

typedef struct _userdata {
		HTMLSTREAMPARSER  *hsp;
		int number;
		parse_state_t state;
		char title[MAX_LEN+1];
} userdata_t;


/* libcurl: write callback (received data from HTTP server) */
static size_t parse_html(void *buffer, size_t size, size_t nmemb,
                         void *data) {
  userdata_t *ud = (userdata_t *)data;
  char href_part[16];
  size_t realsize = size * nmemb;
  size_t p, len;
  
  for (p = 0; p < realsize; p++) {
    html_parser_char_parse(ud->hsp, ((char *)buffer)[p]);
    switch(ud->state) {

	case INITIALIZED:	    
        /* Suche HTML-Referenz zur Aufgabe */
	    sprintf(href_part, "csharp-%d-", ud->number);	  
		if (html_parser_cmp_tag(ud->hsp, "a", 1)) {
          if (html_parser_cmp_attr(ud->hsp, "href", 4)) {
            if (html_parser_is_in(ud->hsp, HTML_VALUE_ENDED)) {
              html_parser_val(ud->hsp)[html_parser_val_length(ud->hsp)] = '\0';
		      if (strncmp(html_parser_val(ud->hsp), href_part, strlen(href_part)) == 0)
			    ud->state = TOPIC_HREF_FOUND;
		    }
          }
	    }
	    break;
	    
    case TOPIC_HREF_FOUND:  	    
	    /* Suche class-Attributwert "title" */
		if (html_parser_cmp_tag(ud->hsp, "div", 3)) {
          if (html_parser_cmp_attr(ud->hsp, "class", 5)) {
            if (html_parser_is_in(ud->hsp, HTML_VALUE_ENDED)) {
              html_parser_val(ud->hsp)[html_parser_val_length(ud->hsp)] = '\0';
		      if (strcmp(html_parser_val(ud->hsp), "title") == 0)
		        ud->state = TITLE_CLASS_FOUND;
			}
          }
		}
		break;

    case TITLE_CLASS_FOUND:
	    /* Suche "span"-Tags */
		if (html_parser_cmp_tag(ud->hsp, "span", 4))
		  ud->state = TITLE_SPAN_FOUND;
		break;  

    case TITLE_SPAN_FOUND:
        /* extrahiere Aufgabentitel */
        if ((len = html_parser_inner_text_length(ud->hsp)) > 0) {
		  len = min(len, MAX_LEN);	
		  strncpy(ud->title, html_parser_inner_text(ud->hsp), len);
		  ud->title[len] = '\0';
		  ud->state = TITLE_TEXT_FOUND;
	    }
		break;  

    case TITLE_TEXT_FOUND:
    default:
		ud->state = FINISHED;
	}
  }
  return realsize;
}

int main(int argc, char *argv[])
{
  CURL *curl;
  HTMLSTREAMPARSER *hsp;
  userdata_t ud;
	
  char url[MAX_LEN+1];		/* URL string */ 
  char text[MAX_LEN+1];   	/* html inner text (title) */
  char val[128];    		/* attribute value */
  char attr[6];       		/* attribute name */
  char tag[4];     			/* tag name */
  int topic, page;

  /* check args */
  if (argc != 2) {
    printf("Usage: %s Nummer\n", argv[0]);
    return EXIT_FAILURE;
  }

  /* init HTML stream parser */  
  if ((hsp = html_parser_init()) != NULL) {
	html_parser_set_tag_to_lower(hsp, 1);
	html_parser_set_attr_to_lower(hsp, 1);
	html_parser_set_tag_buffer(hsp, tag, sizeof(tag));
	html_parser_set_attr_buffer(hsp, attr, sizeof(attr));
	html_parser_set_val_buffer(hsp, val, sizeof(val)-1);
    html_parser_set_inner_text_buffer(hsp, text, sizeof(text)-1);	
  }
  else {
	fprintf(stderr, "Cannot initialize html stream parser.\n");
    return EXIT_FAILURE;
  }
  
  /* init user data struct */	
  topic = atoi(argv[1]);
  ud.number = min(topic, 999);
  ud.title[0] = '\0';
  ud.hsp = hsp;

  /* init libcurl */  
  if ((curl = curl_easy_init()) != NULL) {
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, parse_html);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ud);
  }
  else {
	fprintf(stderr, "Cannot initialize curl lib.\n");
    return EXIT_FAILURE;
  }

  /* browse the pages on the web site */
  printf("Suche auf %s (C#)\n", WEBURL);  
  for (page=1; page <= MAX_PAGES; page++) {
	printf("Suche auf Seite %d\n", page);  
	sprintf(url, "%s/index.pl?page=csharp&seite=%d", WEBURL, page);
	curl_easy_setopt(curl, CURLOPT_URL, url);
    ud.state = INITIALIZED;
    curl_easy_perform(curl);
    if (ud.state == FINISHED)
		break;
  }
  if (strlen(ud.title) > 0)
	printf("Titel #%d: \"%s\"\n", topic, ud.title);
  else
    printf("Aufgabe #%d nicht gefunden.\n", topic);
    
  /* cleanup */
  curl_easy_cleanup(curl);
  html_parser_cleanup(hsp);
  return 0;
}

Kommentare:

Für diese Lösung gibt es noch keinen Kommentar

Bitte melden Sie sich an um eine Kommentar zu schreiben.
Kommentar schreiben