Récupèrer la source html d'un site web
Page 1 sur 1
Récupèrer la source html d'un site web
Je débute dans le monde des réseaux, et je voudrais réaliser une application qui récupère la source html d'un site web donné.
Je pense qu'il faut que je fasse une requête http sur le serveur du site et que je lui envoie un message pour qu'il m'envoie la source html. Ensuite j'ai plus qu'à l'enregistrer dans un fichier.
Je conseille de commencer par lire un peu de théorie ici :
http://mapage.noos.fr/emdel/reseaux.htm
il y a aussi des exercices pratiques.
une fois qu'on sait faire un client, il suffit de se connecter au serveur, de faire une requête http et de récupérer le fichier html (qui sera précédé d'un en-tête http)...
Je conseille un travail en couche qui respecte les différents niveaux (socket, http, html)
ça n'est pas compliqué, tu créés un petit client TCP qui va se connecter au serveur du site (généralement port 80 mais à vérifier quand même), ensuite il faut envoyer une requête sur ta socket de type :
GET /index.html\n
ensuite tu n'as plus qu'à lire sur ta socket la page html demandé, dans ce cas là, c'est index.html.
Bon j'ai fait un effort pour le faire en C89, la gestion des erreurs est minimale, je laisse le soin à Emmanuel de le corriger si besoin est.
ceci fonctionne sous Windows et devrait fonctionner aussi sous GNU/Linux...
OK, pour les sizeof, mais c'est pas une solution générale qui peut prêter à confusion et on se retrouve avec des 0 inutiles en ligne...
Par contre, j'ai pas compris pourquoi tu as appelé setsockopt ().
Le nom du fichier était incorrect.
Mais il y a quelque chose que je n'ai pas très bien compris dans votre code.
Moi j'ai appris à donner une adresse IP à mon socket ainsi :
Mais dans votre code, vous semblez faire :
Pouvez-vous m'expliquer un petit peu s'il vous plait ?
C'est parce que l'adresse provient d'une récupération par gethostbyname(). On fait une copie directe mais comme les types ne sont pas les mêmes, on force un peu le compilateur à coup de memcpy(). Cette manip est réputée fiable et portable...
est ce que pour remplir HOST et FILENAME, il faut toujours couper l'adresse au premier / ou est-ce qu'il y a des exceptions ?
Je ne sais pas répondre aux questions concernant HTTP, mais sur le plan du langage C c'est identique.
On aurait très bien pu faire ceci :
Par contre, j'ai pas compris pourquoi tu as appelé setsockopt ().
Pour setsockopt() je te renvoi vers la norme POSIX.1 :
http://www.opengroup.org/onlinepubs/000095399/functions/setsockopt.html
Je pense qu'il faut que je fasse une requête http sur le serveur du site et que je lui envoie un message pour qu'il m'envoie la source html. Ensuite j'ai plus qu'à l'enregistrer dans un fichier.
Je conseille de commencer par lire un peu de théorie ici :
http://mapage.noos.fr/emdel/reseaux.htm
il y a aussi des exercices pratiques.
une fois qu'on sait faire un client, il suffit de se connecter au serveur, de faire une requête http et de récupérer le fichier html (qui sera précédé d'un en-tête http)...
Je conseille un travail en couche qui respecte les différents niveaux (socket, http, html)
ça n'est pas compliqué, tu créés un petit client TCP qui va se connecter au serveur du site (généralement port 80 mais à vérifier quand même), ensuite il faut envoyer une requête sur ta socket de type :
GET /index.html\n
ensuite tu n'as plus qu'à lire sur ta socket la page html demandé, dans ce cas là, c'est index.html.
Bon j'ai fait un effort pour le faire en C89, la gestion des erreurs est minimale, je laisse le soin à Emmanuel de le corriger si besoin est.
- Code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#define HOST "mapage.noos.fr"
#define PORT 80
#define FILE "/emdel/"
int main (void)
{
struct hostent *host_address = gethostbyname (HOST);
if (host_address != NULL)
{
int socket_id = socket (PF_INET, SOCK_STREAM, 0);
if (socket_id != -1)
{
struct sockaddr_in sockname;
int optval = 1;
setsockopt (socket_id, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof optval);
sockname.sin_family = host_address->h_addrtype;
sockname.sin_port = htons (PORT);
memcpy (&sockname.sin_addr.s_addr, host_address->h_addr,
host_address->h_length);
if (connect (socket_id, (struct sockaddr *) &sockname,
sizeof (struct sockaddr_in)) != -1)
{
char str[1024];
int l;
write (socket_id, "GET ", sizeof ("GET ") - 1);
write (socket_id, FILE, sizeof (FILE) - 1);
write (socket_id, " HTTP/1.1\r\nHost: ",
sizeof (" HTTP/1.1\r\nHost: ") - 1);
write (socket_id, HOST, sizeof (HOST) - 1);
write (socket_id, "\r\n\r\n", sizeof ("\r\n\r\n") - 1);
while ((l = read (socket_id, str, sizeof (str) - 1)))
{
str[l] = 0;
printf ("%s", str);
}
shutdown (socket_id, 2);
close (socket_id);
}
else /* connect () */
{
perror ("connect ()");
}
}
else /* socket () */
{
perror ("socket ()");
}
}
else /* gethostbyname () */
{
perror ("gethostbyname ()");
}
return 0;
}
ceci fonctionne sous Windows et devrait fonctionner aussi sous GNU/Linux...
- Code:
#include <stdio.h>
#include <string.h>
#if defined (WIN32)
#include <winsock2.h>
#elif defined (linux)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#define closesocket(s) close (s)
typedef int SOCKET;
typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR;
#endif
#define HOST "mapage.noos.fr"
#define PORT 80
#define FILENAME "/emdel/index.htm"
static void envoyer (SOCKET sock, char const *s)
{
send (sock, s, strlen (s), 0);
}
int client (void)
{
struct hostent *host_address = gethostbyname (HOST);
if (host_address != NULL)
{
SOCKET socket_id = socket (PF_INET, SOCK_STREAM, 0);
if (socket_id != INVALID_SOCKET)
{
struct sockaddr_in sockname = { 0 };
#if 0
int optval = 1;
setsockopt (socket_id, SOL_SOCKET, SO_REUSEADDR, (void *) &optval,
sizeof optval);
#endif
sockname.sin_family = host_address->h_addrtype;
sockname.sin_port = htons (PORT);
memcpy (&sockname.sin_addr.s_addr, host_address->h_addr,
host_address->h_length);
if (connect (socket_id, (struct sockaddr *) &sockname,
sizeof (struct sockaddr_in)) != -1)
{
char str[1024];
int l;
envoyer (socket_id, "GET ");
envoyer (socket_id, FILENAME);
envoyer (socket_id, " HTTP/1.1\r\nHost: ");
envoyer (socket_id, HOST);
envoyer (socket_id, "\r\n\r\n");
while ((l = recv (socket_id, str, sizeof (str) - 1, 0)))
{
str[l] = 0;
printf ("%s", str);
}
shutdown (socket_id, 2);
closesocket (socket_id);
}
else /* connect () */
{
perror ("connect ()");
}
}
else /* socket () */
{
perror ("socket ()");
}
}
else /* gethostbyname () */
{
perror ("gethostbyname ()");
}
return 0;
}
int main (void)
{
#if defined (WIN32)
WSADATA WSAData;
int erreur = WSAStartup (MAKEWORD (2, 0), &WSAData);
#else
int erreur = 0;
#endif
client ();
#if defined (WIN32)
WSACleanup ();
#endif
return EXIT_SUCCESS;
}
OK, pour les sizeof, mais c'est pas une solution générale qui peut prêter à confusion et on se retrouve avec des 0 inutiles en ligne...
Par contre, j'ai pas compris pourquoi tu as appelé setsockopt ().
Le nom du fichier était incorrect.
Mais il y a quelque chose que je n'ai pas très bien compris dans votre code.
Moi j'ai appris à donner une adresse IP à mon socket ainsi :
- Code:
sin.sin_addr.s_addr = htonl (INADDR_ANY);
// OU
sin.sin_addr.s_addr = inet_addr "XX.XXX.XXX.XXX");
Mais dans votre code, vous semblez faire :
- Code:
memcpy (&sockname.sin_addr.s_addr , host_address->h_addr, host_address->h_length);
Pouvez-vous m'expliquer un petit peu s'il vous plait ?
C'est parce que l'adresse provient d'une récupération par gethostbyname(). On fait une copie directe mais comme les types ne sont pas les mêmes, on force un peu le compilateur à coup de memcpy(). Cette manip est réputée fiable et portable...
est ce que pour remplir HOST et FILENAME, il faut toujours couper l'adresse au premier / ou est-ce qu'il y a des exceptions ?
Je ne sais pas répondre aux questions concernant HTTP, mais sur le plan du langage C c'est identique.
On aurait très bien pu faire ceci :
- Code:
envoyer (socket_id,
"GET " FILENAME " HTTP/1.1\r\n"
"Host: " HOST "\r\n\r\n");
Par contre, j'ai pas compris pourquoi tu as appelé setsockopt ().
Pour setsockopt() je te renvoi vers la norme POSIX.1 :
http://www.opengroup.org/onlinepubs/000095399/functions/setsockopt.html
Dernière édition par -ed- le Lun 1 Sep 2014 - 2:37, édité 1 fois (Raison : typo dans le titre)
Page 1 sur 1
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum
|
|