C :: Aufgabe #136

3 Lösungen Lösungen öffentlich

Regelmäßiges Runterladen und Abspeichern von Dateien

Anfänger - C von ZRX88 - 04.12.2016 um 12:06 Uhr
Eine Firma X stellt euch einen FTP Zugang (ggf. mit Zugang + PW ) zur Verfügung, wo sie jeden Tag eine Datei xyz.txt updaten und mit den aktuellsten Datensätzen befüllen.

Im ersten Schritt sollen diese Dateien heruntergeladen werden und dann auch in einem Ordner auf der Festplatte abgelegt werden.
Zum Wiedererkennen soll sowohl die Quelle als auch der Zeitpunkt des Downloads abgespeichert werden:
mögliche Beispiele:
* Zielorder > File 'FTP_x_xzy_2016_12_24.txt'
* Zielorder > Ordername '2016-12-24' > File 'xyz.txt'

Wichtig: Die Ablage muss sauber strukturiert sein.

Anmerkung: Da ich euch keinen FTP zur Verfügung stelle und wenn ihr keinen eigenen zum Testen habt:
Stattdessen ladet doch einfach den Inhalt von https://trainyourprogrammer.de/python herunter.

Optional:
* Erweitert das Programm so, dass es alle Dateien auf dem FTP herunterlädt.
* Alternativ: Speichert den Inhalt von alle verfügbaren Python Aufgaben Seiten herunter?


Lösungen:

vote_ok
von devnull (8870 Punkte) - 05.12.2016 um 16:34 Uhr
Sourcen der verwendeten FTP-Bibliothek sind hier zu finden: FTPlib.
Getestet wurde Anonymous FTP mit proftpd unter Ubuntu 14.04 LTS.

Quellcode ausblenden C-Code
/****************************************
 * ftpdown.c 	FTP Download
 * compile:gcc -Wall -o ftpdown ftpdown.c -lftp
 ****************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ftplib.h>

#define REMOTE_HOST "localhost"
#define REMOTE_USER "anonymous"
#define REMOTE_PW   "anonymous"
#define REMOTE_FILE "xyz.txt"

enum { ERROR_CONNECT, ERROR_LOGIN, ERROR_GET };


void ftp_error(int rtype, int rcode) {
	fprintf(stderr, "%s\n", "***FTP Error:");
	switch (rtype) {
	case ERROR_CONNECT:
		fprintf(stderr, "%s", "no connection.");
		break;
	case ERROR_LOGIN:	
		fprintf(stderr, "%s", "login not permitted.");
		break;
	case ERROR_GET:	
		fprintf(stderr, "%s", "cannot get the remote file.");
		break;
	default:
		fprintf(stderr, "%s", "unknown error.");
	}
	fprintf(stderr, " (error code = %d)\n", rcode);
}
			
char *get_local_path(const char *filename) {
	static char local_path[256];
	char tmbuf[16];
	time_t t;
		
	strcpy(local_path, getenv("HOME"));
	strcat(local_path, "/Downloads/FTP_xyz_");
	t = time(NULL);
	strftime(tmbuf, 16, "%Y_%m_%d.txt", localtime(&t));
	strcat(local_path, tmbuf);
	return local_path;
}
 
int main(void) {
	netbuf *nctrl;
	char stbuf[64];
    size_t fsize;
    int ftprc;

	FtpInit();

	if ((ftprc = FtpConnect(REMOTE_HOST, &nctrl)) == 0) {
		ftp_error(ERROR_CONNECT, ftprc);
		exit(EXIT_FAILURE);
	}

	if ((ftprc = FtpSysType(stbuf, 64, nctrl)) == 1)
		printf("System type of remote host is %s\n", stbuf);

	if ((ftprc = FtpLogin(REMOTE_USER, REMOTE_PW, nctrl)) == 0) {
		ftp_error(ERROR_LOGIN, ftprc);
		FtpQuit(nctrl);
		exit(EXIT_FAILURE);
	}

	if ((ftprc = FtpSize(REMOTE_FILE, (int *)&fsize, FTPLIB_ASCII, nctrl)) == 1)
		printf("Size of remote file '%s' is %zd.\n", REMOTE_FILE, fsize);
	
	if ((ftprc = FtpGet(get_local_path(REMOTE_FILE), REMOTE_FILE, 
				FTPLIB_ASCII, nctrl)) == 0)
		ftp_error(ERROR_GET, ftprc);
	else
		printf("Remote file '%s' loaded as '%s'.\n", REMOTE_FILE, 
				get_local_path(REMOTE_FILE));
			
	FtpQuit(nctrl);
	return 0;
}

1 Kommentar
vote_ok
von devnull (8870 Punkte) - 05.12.2016 um 21:41 Uhr
Lösung 2 liest den Inhalt des Remote-Directory "." und lädt alle Dateien herunter.

Konsolenausgabe:

System type of remote host is UNIX
Download remote directory list: /home/kepler/Downloads/FTP_dir_2016_12_05.lst.
3 remote file(s) found.
Download: xyz.dat -> /home/kepler/Downloads/FTP_xyz_2016_12_05.dat
Download: def.txt -> /home/kepler/Downloads/FTP_def_2016_12_05.txt
Download: abc.txt -> /home/kepler/Downloads/FTP_abc_2016_12_05.txt

Quellcode ausblenden C-Code
/****************************************************
 * ftpdown2.c 	FTP Download
 * compile:     gcc -Wall -o ftpdown2 ftpdown2.c -lftp
 *****************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <ftplib.h>

#define REMOTE_HOST "localhost"
#define REMOTE_USER "anonymous"
#define REMOTE_PW   "anonymous"
#define FLIST_MAX   64

enum {	ERROR_CONNECT, 
		ERROR_LOGIN, 
		ERROR_DIR, 
		ERROR_ACCESS,
		ERROR_GET };

void ftp_error(int rtype, int rcode) {
	fprintf(stderr, "%s\n", "***FTP Error:");
	switch (rtype) {
	case ERROR_CONNECT:
		fprintf(stderr, "%s", "no connection.");
		break;
	case ERROR_LOGIN:	
		fprintf(stderr, "%s", "login not permitted.");
		break;
	case ERROR_DIR:	
		fprintf(stderr, "%s", "cannot get remote directory list.");
		break;
	case ERROR_ACCESS:	
		fprintf(stderr, "%s", "cannot access remote directory.");
		break;
	case ERROR_GET:	
		fprintf(stderr, "%s", "cannot get the remote file.");
		break;
	default:
		fprintf(stderr, "%s", "unknown error.");
	}
	fprintf(stderr, " (error code = %d)\n", rcode);
}

void ftp_abort(int rtype, int rcode, netbuf *nc) {
	ftp_error(rtype, rcode);
	FtpQuit(nc);
	exit(EXIT_FAILURE);
}
		
char *comp(char *fname) {
	/* remove line feed */
	if (fname[strlen(fname)-1] == '\n')
		fname[strlen(fname)-1] = '\0';
	return fname;	
}
			
char *get_local_path(const char *filename) {
	static char local_path[256];
	char fname[256];
	char tmbuf[16];
	char *extn;
	time_t t;
	
	strcpy(fname, filename);
	if ((extn = strchr(fname, '.')) != NULL) {
		*extn = '\0';
		++extn;
	}
	strcpy(local_path, getenv("HOME"));
	strcat(local_path, "/Downloads/FTP_");
	strcat(local_path, fname);
	t = time(NULL);
	strftime(tmbuf, sizeof(tmbuf), "_%Y_%m_%d", localtime(&t));
	strcat(local_path, tmbuf);
	if (extn != NULL) {
		strcat(local_path, ".");
		strcat(local_path, extn);
    }
	return local_path;
}
 
int main(void) {
	netbuf *nctrl, *ndata;
	char dirlst[256];
	char rddbuf[256];
	char *flist[FLIST_MAX];
	char stbuf[64];
	int fcount;
    int ftprc;

	FtpInit();

	/* connect - get handle nctrl */
	if ((ftprc = FtpConnect(REMOTE_HOST, &nctrl)) == 0)
		ftp_abort(ERROR_CONNECT, ftprc, nctrl);

	/* get remote system type */
	if ((ftprc = FtpSysType(stbuf, sizeof(stbuf), nctrl)) == 1)
		printf("System type of remote host is %s\n", stbuf);

	/* login */
	if ((ftprc = FtpLogin(REMOTE_USER, REMOTE_PW, nctrl)) == 0)
		ftp_abort(ERROR_LOGIN, ftprc, nctrl);

	/* download remote directory list */
	strcpy(dirlst, get_local_path("dir.lst"));	
	if ((ftprc = FtpDir(dirlst, "*.txt", nctrl)) == 1)
		printf("Download remote directory list: %s.\n", dirlst);
	else
		ftp_abort(ERROR_DIR, ftprc, nctrl);
	
	/* access remote directory - get handle ndata */	
	if ((ftprc = FtpAccess(".", FTPLIB_DIR, FTPLIB_ASCII, nctrl, &ndata)) == 0)
		ftp_abort(ERROR_ACCESS, ftprc, nctrl);

	/* get and store filenames */
	fcount=0;
	flist[0]=NULL;
	memset(rddbuf, 0, sizeof(rddbuf));
	while (FtpRead(rddbuf, sizeof(rddbuf), ndata) > 0) {
		if ((flist[fcount] = malloc(strlen(comp(rddbuf))+1)) != NULL)
			strcpy(flist[fcount], rddbuf);
		else
			break;
		flist[++fcount] = NULL;
		if (fcount > FLIST_MAX-2)
			break;
	}
	FtpClose(ndata);
	printf("%d remote file(s) found.\n", fcount);
	
	/* get and store files */
	fcount=0;
	while (flist[fcount] != NULL) {
		if ((ftprc = FtpGet(get_local_path(flist[fcount]), flist[fcount], FTPLIB_ASCII, nctrl)) == 0)
			ftp_error(ERROR_GET, ftprc);
		else
			printf("Download: %s -> %s\n", flist[fcount], get_local_path(flist[fcount]));
		memset(rddbuf, 0, sizeof(rddbuf));
		free(flist[fcount++]);
	}

	/* clean up */
	FtpQuit(nctrl);
	return 0;
}
vote_ok
von devnull (8870 Punkte) - 14.12.2016 um 13:28 Uhr
Lösung 3 lädt die Python-Aufgabentitel herunter.
Realisiert mit der libcurl via HTTPS-Protokoll.
Quellcode ausblenden C-Code
/***********************************
 * pydown.c  Python-Titel anzeigen
 ***********************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <regex.h>
#include <curl/curl.h>
#include <htmlstreamparser.h>

#define DEBUG  0

#define WEBURL           "https://trainyourprogrammer.de"
#define HTTP_PROXY_HOST  ""
#define HTTP_PROXY_PORT  0

#define TOPIC_NAME  "python"
#define TOPIC_DESC  "Python"
#define MAX_LEN     255
#define MAX_PAGES   12

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

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

typedef struct _userdata {
        HTMLSTREAMPARSER  *hsp;
        parse_state_t state;
        int number;
        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;
  regex_t regex;
  regmatch_t pm[2];
  char href_part[32];
  char href_pattern[32];
  char topic_snum[8];
  size_t realsize = size * nmemb;
  size_t p, len;
  int pm_len;

  if (DEBUG) {
    if (realsize > 0) {
	  fprintf(stderr, "###Data block size is %zd (%zd/%zd).\n", realsize, size, nmemb);
    } else {
	  fprintf(stderr, "###Nothing to parse (%zd/%zd).\n", size, nmemb);
	  return 0;
    }
  }
  for (p = 0; p < realsize; p++) {
    html_parser_char_parse(ud->hsp, ((char *)buffer)[p]);
    switch(ud->state) {

    case TOPIC_NR_SEARCH:
        /* Suche <div class="nr"> */
        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), "nr") == 0)
                ud->state = TOPIC_HREF_SEARCH;
            }
          }
        }
        break;

    case TOPIC_HREF_SEARCH:
        /* Suche <a href="python-135-..." */
	    sprintf(href_part, "%s-", TOPIC_NAME);
        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) {
                if (DEBUG)
                  fprintf(stderr, "href-val=[%s]\n", html_parser_val(ud->hsp));

				/* extract problem number */
				sprintf(href_pattern, "%s-([0-9]{1,4})-", TOPIC_NAME);
                if (regcomp(®ex, href_pattern, REG_EXTENDED) == 0) {
				  if (regexec(®ex, html_parser_val(ud->hsp), 2, pm, 0) == 0) {
					if (pm[1].rm_so > 0) {
                      pm_len = (int)(pm[1].rm_eo - pm[1].rm_so);
					  sprintf(topic_snum, "%*s", pm_len, html_parser_val(ud->hsp)+pm[1].rm_so);
					  topic_snum[pm_len] = 0;
					  ud->number = atoi(topic_snum);
				    }
				  }
			      regfree(®ex);
				}
                ud->state = TOPIC_HREF_FOUND;
			  }
            }
          }
        }
        break;

    case TOPIC_HREF_FOUND:
        /* Suche <div class="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>Titeltext</span> */
        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';
		  if (len > 0)
			printf("Titel #%-3d : \"%s\"\n", ud->number, ud->title);
          ud->state = TITLE_TEXT_FOUND;
        }
        break;

    case TITLE_TEXT_FOUND:
        /* Status-Reset oder Ende */
		ud->state = (ud->number > 1) ? TOPIC_NR_SEARCH : FINISHED;
		break;

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

int main(int argc, char *argv[])
{
  CURL *curl;
  CURLcode curl_res;
  userdata_t ud;
  HTMLSTREAMPARSER *hsp;

  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[6];              /* tag name */
  int page;

  char errbuf[MAX_LEN+1];   /* curl error buffer */
  size_t errlen;

  /* 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 */
  ud.number = -1;
  ud.title[0] = '\0';
  ud.hsp = hsp;

  /* init libcurl */
  if ((curl = curl_easy_init()) != NULL) {
	if (strlen(HTTP_PROXY_HOST) > 0) {
	  curl_easy_setopt(curl, CURLOPT_PROXY, HTTP_PROXY_HOST);
	  if (HTTP_PROXY_PORT > 0)
        curl_easy_setopt(curl, CURLOPT_PROXYPORT, (long)HTTP_PROXY_PORT);
	}
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, parse_html);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &ud);
    curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
  }
  else {
    fprintf(stderr, "Cannot initialize curl lib.\n");
    return EXIT_FAILURE;
  }

  /* browse the pages on the web site */
  for (page=1; page <= MAX_PAGES; page++) {
    printf("\nAufgaben auf der %s-Seite %d:\n\n", TOPIC_DESC, page);
    sprintf(url, "%s/index.pl?page=%s&seite=%d", WEBURL, TOPIC_NAME, page);
    curl_easy_setopt(curl, CURLOPT_URL, url);
    ud.state = TOPIC_HREF_SEARCH;
    if ((curl_res = curl_easy_perform(curl)) != CURLE_OK) {
		errlen = strlen(errbuf);
		fprintf(stderr, "\nlibcurl: (%d) ", curl_res);
		fprintf(stderr, "%s\n", (errlen)?errbuf:curl_easy_strerror(curl_res));
		break;
	}
    if (ud.state == FINISHED)
        break;
  }

  /* cleanup */
  curl_easy_cleanup(curl);
  html_parser_cleanup(hsp);
  return 0;
}