C :: Aufgabe #90
1 Lösung
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
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.
Lösungen:
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:
C-Code
- 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"
/*******************************
* 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;
}
