Echando código: ¿Como ver geográficamente con quienes visitan el Blog?: El API de Google MAPS

Usando Google Maps para mostrar quienes visitan a KodeGeek.com
Desde hace tiempo que había querido jugar con el API de Yahoo para hacer mapas; No sólo no te ponen la restricción estupida de cuantas veces lo puedes llamar (como Google Maps), sino que también es muy fácil de usar. La idea es mostrar en un mapa de Yahoo en donde está la gente que visita este blog. Sin embargo ni Google ni Yahoo Maps soportan mapas de las calles fuera de los Estados Unidos o Inglaterra, mientras que Google Maps si soporta una vista satelital. Así que al final vamos a trabajar con Google Maps.
Si la vida te da limones, te sale hacer limonada (o en pocas palabras, suck it up!)
Ya hablando en serio, para hacer un mapa en Google maps usted necesita hacer lo siguiente:
- Obtener una clave para poder usar el servicio de Google Maps. Es grátis.
- Obtener la lista de direcciones IP a colocar en el mapa. Esas las saco yo de mi bitacora de Apache
- Hacer el mapa entre direcciones IP y Pais con Latitud y Longitud. Más de eso adelante, este paso es crítico.
- Escribir las coordenadas en un formato XML que el parser de AJAX de Google maps pueda entender.
- Crear el mapa con Google maps y bajarse las coordenadas utilizando XML-RPC. De esa manera no tocamos el código, solamente necesitamos actualizar los "marcadores" (markers) de Google Maps cada vez que queramos mostrar los datos. Es obligatorio que se lea como usar el API de Google Maps, no es nada complicado.
- ¡Exito!
- Utilizando NetNeo, de la gente de el proyecto CAIDA me consigo la longitud y latitud de los sistemas autonomos.
- La base de datos de paises y direcciones IP de el proyecto LUDOS me da la otra parte de el rompecabezas.
- Tengo que bajarme ambos archivos, y también tengo que preprocesar los archivos antes de tratar de meterlos en la base de datos en sus respectivas tablas.
- Luego tengo que importar la bitacora de Apache en la base de datos. Hay preprocesamiento.
Las buenas noticias es que si se puede, para ello nos olvidamos de LUDO y CAIDA y en vez de eso utilizamos el servicio gratuito de HostIP.info. Ellos te permiten bajarte la base de datos para que tu hagas tu propio procesamiento, pero dado que son pocas (menos de 10000) diferentes direcciones IP que vamos a procesar entonces utilizamos su API por HTTP. Les recomiendo que los visiten y que contribuyan para que así la base de datos siga creciendo.
El código que utilizamos para generar los marcadores en formato XML (Direcciones IP únicas, con todos los datos) es el siguiente:
1:#!/usr/bin/perlEl programa cuando corre se ve así:
2:
3:use strict;
4:use LWP::UserAgent;
5:use Date::Manip;
6:
7:# For example: $HOME/logs/kodegeek.com-Jan-2006.gz
8:use constant LOG_FILE =>
9: "$ENV{HOME}/logs/kodegeek.com-" .
10: &UnixDate("today", "%b") .
11: "-" .
12: &UnixDate("today", "%Y") .
13: ".gz";
14:
15:my $MARKER_FILE =
16: "$ENV{HOME}/public_html/kodegeek_marker.xml";
17:
18:my %ips = &parseLogFile(LOG_FILE);
19:
20:# Get the latitude and longitude information
21:# and construct the map information.
22:#
23:# Make a backup
24:if ( -f "${MARKER_FILE}") {
25: system("mv ${MARKER_FILE} ${MARKER_FILE}.old");
26:}
27:open(OUT_XML, ">${MARKER_FILE}") || die "$!, $MARKER_FILE";
28:print OUT_XML "<markers description=\"kodegeek access log markers\">\n";
29:my $total=0.0;
30:my $used=0.0;
31:foreach my $ip (values %ips) {
32: $total++;
33: &getIpGeoData($ip);
34: if ( ($ip->getLatitude() != "")
35: && ($ip->getLongitude() != "")) {
36: $used++;
37: printf "[INFO]: Adding ip=%s, country=%s, city=%s,
latitude=%s, longitude=%s\n",
38: $ip->getIp(),
39: $ip->getCountry(),
40: $ip->getCity(),
41: $ip->getLatitude(),
42: $ip->getLongitude();
43: print OUT_XML "<marker ip=\"" .
44: $ip->getIp() .
45: "\" country=\"" .
46: $ip->getCountry() .
47: "\" city=\"" .
48: $ip->getCity() .
49: "\" lat=\"" .
50: $ip->getLatitude() .
51: "\" lng=\"" .
52: $ip->getLongitude() .
53: "\"/>\n";
54: }
55:}
56:print OUT_XML "</markers>\n";
57:close(OUT_XML);
58:
59:if (($used < $total) && ($total > 0)) {
60: printf "[WARNING]: %s of the IP addresses were
rejected due insufficient data\n",
61: ($used / $total);
62:}
63:
64:# Download the file from the desired URL
65:# using the free service at http://www.hostip.info
66:#
67:sub getIpGeoData {
68: my ($ip) = $_[0];
69:
70: my $ua = LWP::UserAgent->new(
71: agent => "kodeGeek/visitor_geo_map_generator.pl 1.0",
72: from => 'josevnz@kodegeek.com'
73: );
74: my $response = $ua->get("http://api.hostip.info/get_html.php?ip=" .
75: $ip->getIp() ."&position=true");
76: if ($response->is_success) {
77: my($country, $city, $latitude, $longitude) =
78: split("\n", $response->content);
79: $ip->setCountry((split("\:", $country))[1]);
80: $ip->setCity((split("\:", $city))[1]);
81: $ip->setLatitude((split("\:", $latitude))[1]);
82: $ip->setLongitude((split("\:", $longitude))[1]);
83: } else {
84: die $response->status_line;
85: }
86: return $response->status_line;
87:}
88:
89:# Parse the GeoFile
90:# @param The file to parse
91:# @return An hastable with the unique IP addresses and
92:# the number of ocurrences
93:sub parseLogFile {
94: my %IpMap = ();
95: my $file = $_[0];
96: printf "[INFO]: Parsing LogFile %s\n", $file;
97: open(INPUT_FILE, "/bin/zcat $file |") || die "$!";
98: # Not portable, but who cares!
99: while(<INPUT_FILE>) {
100: chomp($_);
101: my @tokens = split('\s', $_);
102: my $ip = undef;
103: if (! defined $IpMap{$tokens[0]}) {
104: $ip = IpInfo::new($tokens[0]);
105: $IpMap{$tokens[0]}=$ip;
106: } else {
107: $ip = $IpMap{$tokens[0]};
108: }
109: $ip->addVisit();
110:
111: }
112: close(INPUT_FILE);
113: return %IpMap;
114:}
115:
116:# Models an Ip address information
117:package IpInfo;
118:
119:sub new {
120: if (!defined $_[0]) {
121: die "[ERROR]: Please pass an IP address.";
122: }
123: my $ref = {};
124: $ref->{ip}=$_[0];
125: bless $ref;
126:}
127:
128:sub addVisit {
129: my $ref = shift;
130: $ref->{count}++;
131:}
132:
133:sub getVisits {
134: my $ref = shift;
135: return $ref->{count};
136:}
137:
138:sub getIp {
139: my $ref = shift;
140: return $ref->{ip};
141:}
142:
143:sub getLatitude {
144: my $ref = shift;
145: return $ref->{latidude};
146:}
147:
148:sub getLongitude {
149: my $ref = shift;
150: return $ref->{longitude};
151:}
152:
153:sub getCountry {
154: my $ref = shift;
155: return $ref->{country};
156:}
157:
158:sub getCity {
159: my $ref = shift;
160: return $ref->{city};
161:}
162:
163:sub setLatitude {
164: my $ref = shift;
165: $_[0] =~ s/^\s|$\s//;
166: $ref->{latidude}=$_[0];
167:}
168:
169:sub setLongitude {
170: my $ref = shift;
171: $_[0] =~ s/^\s|$\s//;
172: $ref->{longitude}=$_[0];
173:}
174:
175:sub setCountry {
176: my $ref = shift;
177: $_[0] =~ s/^\s|$\s//;
178: $ref->{country}=$_[0];
179:}
180:
181:sub setCity {
182: my $ref = shift;
183: $_[0] =~ s/^\s|$\s//;
184: $ref->{city}=$_[0];
185:}
186:
187:1;
188:
189:__END__
190:=head1 NAME
191:visitor_geo_map_generator.pl - Create a map with the location of the visitors
192:to the KodeGeek weblog.
193:
194:=head1 DESCRIPTION
195:
196:The script downloads and prepares for import data from several free sources.
197:
198:=head1 LICENSE
199:
200:GPL
201:
202:=head1 AUTHOR
203:
204:Jose Vicente Nunez Zuleta (josevnz@kodegeek.com)
205:
206:=cut
[josevnz@localhost bin]$ ./visitor_geo_map_generator.pl%77 de efectividad traduciendo las direcciones, todo por grátis. Bastante aceptable en mi opinión.
[INFO]: Parsing LogFile /home/josevnz/logs/kodegeek.com-Jan-2006.gz
[INFO]: Adding ip=66.249.71.50, country=UNITED STATES (US), city=Manassas, VA, latitude=38.7474, longitude=-77.4854
[INFO]: Adding ip=201.243.240.170, country=NETHERLANDS (NL), city=The Hague, latitude=52.0833, longitude=4.3
[INFO]: Adding ip=64.76.62.58, country=UNITED STATES (US), city=Miami, FL, latitude=25.7757, longitude=-80.2108
[INFO]: Adding ip=66.142.40.220, country=UNITED STATES (US), city=Olivette, MO, latitude=38.6723, longitude=-90.3772
[INFO]: Adding ip=84.121.72.243, country=SPAIN (ES), city=Murcia, latitude=37.9833, longitude=-1.11667
[INFO]: Adding ip=207.46.98.80, country=UNITED STATES (US), city=CALEDONIA, MI, latitude=42.7939, longitude=-85.5132
[INFO]: Adding ip=206.48.96.113, country=VENEZUELA (VE), city=Caracas, latitude=10.4667, longitude=-67.0333
[INFO]: Adding ip=82.51.190.12, country=ITALY (IT), city=Salerno, latitude=39.3667, longitude=16.4
[INFO]: Adding ip=68.142.249.86, country=UNITED STATES (US), city=Sunnyvale, CA, latitude=37.3857, longitude=-122.026
[INFO]: Adding ip=66.196.91.121, country=UNITED STATES (US), city=MAYSVILLE, KY, latitude=38.6295, longitude=-83.7801
[WARNING]: 0.334332833583208 of the IP addresses were rejected due insufficient data
El XML generado se ve similar a esto:
1:<markers description="kodegeek access log markers">Y de el lado de el cliente solamente necesitamos poner un HTML con el respectivo Javascript que llama las librerías de Google Map, se baja nuestro archivo de marcadores y genera el mapa en todo su esplendor:
2:<marker ip="66.249.71.50" country="UNITED STATES (US)"
city="Manassas, VA" lat="38.7474" lng="-77.4854"/>
3:<marker ip="201.243.240.170" country="NETHERLANDS (NL)"
city="The Hague" lat="52.0833" lng="4.3"/>
...
108:<marker ip="68.142.249.86" country="UNITED STATES (US)"
city="Sunnyvale, CA" lat="37.3857" lng="-122.026"/>
109:<marker ip="194.179.83.87" country="SPAIN (ES)"
city="Madrid" lat="40.4333" lng="-3.7"/>
110:</markers>
1:<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"Es increiblement lo fácil que resulta utilizar el API de Google Maps. Tienen muchos ejemplos y grupos de soporte, les recomiendo que juegen un poco con ella, saldrán gratamente sorprendidos.
2:"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3:<html xmlns="http://www.w3.org/1999/xhtml">
4: <head>
5: <script src="http://maps.google.com/maps?file=api&v=1&key=AAA"
6: type="text/javascript"></script>
7: </head>
8: <body>
9: <div id="map" style="width: 600px; height: 500px"></div>
10: <script type="text/javascript">
11: //<![CDATA[
12: /*
13: * Construct a map based on the Apache visitor access log
14: for the site KodeGeek.com
15: * Author: Jose Vicente Nunez Zuleta (josevnz@kodegeek.com)
16: * License: GPL
17: * Blog: http://kodegeek.com
18: */
19:
20: /*
21: * Create a marker whose info window displays the
22: * ip address, country and state of the visitor
23: * @param XML fragment with the required attributes
24: * @return A marker object with the appropriate event handlers
25: */
26: function customMarker(markerInfo) {
27:
28: var point = new GPoint(
29: parseFloat(markerInfo.getAttribute("lng")),
30: parseFloat(markerInfo.getAttribute("lat")));
31:
32: var marker = new GMarker(point);
33:
34: var infoHtml =
35: "<b>Direcciónn IP:</b>" +
36: markerInfo.getAttribute("ip") +
37: ", <b>Paíns:</b>" +
38: markerInfo.getAttribute("country") +
39: ", <b>Ciudad:</b>" +
40: markerInfo.getAttribute("city");
41: "</b>";
42:
43: GEvent.addListener(
44: marker,
45: 'click',
46: function() {
47: marker.openInfoWindowHtml(infoHtml);
48: }
49: );
50: return marker;
51: }
52:
53: /*
54: * Retrieve the marker information from the
55: * given request and creater the proper event handlers
56: * @param map Global map object
57: * @param request Global request object
58: */
59: function stateChange(request, map) {
60: if (request.readyState == 4) {
61: var xmlDoc = request.responseXML;
62: var markers =
63: xmlDoc.documentElement.getElementsByTagName("marker");
64: for (var i = 0; i < markers.length; i++) {
65: map.addOverlay(customMarker(markers[i]));
66: }
67: } // end if
68: } // end request
69:
70: var map = new GMap(document.getElementById("map"));
71: map.setMapType(G_HYBRID_TYPE);
72: map.addControl(new GSmallMapControl());
73: map.centerAndZoom(new GPoint(0.0, 0.0), 16);
74: map.openInfoWindow(map.getCenterLatLng(),
75: document.createTextNode("KodeGeek,
76: http://KodeGeek.com"));
77: var request = GXmlHttp.create();
78: request.open('GET', 'kodegeek_marker.xml', true);
79: request.onreadystatechange = stateChange(request, map);
80: request.send(null);
81:
82: //]]>
83: </script>
84: </body>
85:
86:</html>
El código como siempre está en CVS.
Bueno, esto va a correr de ahora en adelante, así que aqui les dejo el enlace para que se diviertan :)
Buscar en Technorati: Google Maps



0 Comentarios:
Publicar un comentario en la entrada
Enlaces a este articulo:
Crear un vínculo
<< Regresar