Como hacer un HEAD request en Python
Estuve el domingo unas cuantas horas buscando por internet como hacer esto y me estaba frustrando. Mi nuevo mini-proyecto secreto requiere monitorizar unas imágenes regularmente para ir actualizándolas a medida que van cambiando mediante un cron script que se ejecuta cada 15 minutos. Hay dos opciones:
- Bajarnos las imágenes todas las veces y comparar el md5sum para ver si han cambiado
- o hacer un pedido HEAD en vez de GET y hacer uso de las cabeceras Last-Modified y ETag.
¿Que cuales son las ventajas del punto dos? Lo más importante es que nos ahorramos ancho de banda nosotros y a los que le estemos bajando las imágenes, tampoco es cuestión de abusar del servidor de otra persona. Ojo que esto no aplica sólo a las imágenes, cualquier servidor moderno de hoy en día tiene soporte para estas cabeceras y las devolverá con cualquier tipo de archivo, incluso los que estén generados dinámicamente. Nos ahorramos ancho de banda porque sólo pedimos la cabecera del archivo que exceptuando casos extremos será mucho más pequeño que el resto del documento. Esto es especialmente útil para el contenido estático (js, imagenes, css, etc) y contenido que se baja regularmente como feeds RSS. Además de ahorrar ancho de banda también hacemos que el script vaya más rápido ya que no tiene que procesar todo el documento.
La idea es que hacemos un pedido HEAD inicial y guardamos el Last-Modified y ETag, luego en los subsiguientes pedidos enviamos pedidos GET con las cabeceras If-Modified-Since y If-None-Match. If-Modified-Since se usa con la fecha que guardamos anteriormente y If-None-Match con el ETag. Si ambos campos son los mismos en el archivo actual del lado del servidor entonces este debe responder con un ‘304 Not Modified’
import StringIO
import pycurl
c = pycurl.Curl()
s = StringIO.StringIO()
c.setopt(pycurl.URL, 'http://theragingche.com/images/hand_made_cms.gif')
c.setopt(pycurl.HEADER, True) # estas dos lineas son las que importan
c.setopt(pycurl.NOBODY, True) # para hacer un pedido HEAD
c.setopt(pycurl.WRITEFUNCTION, s.write)
c.perform()
print s.getvalue()
Nos devuelve solo la cabecera:
$ python head.py
HTTP/1.1 200 OK
Date: Mon, 26 Nov 2007 12:29:50 GMT
Server: Apache/2.0.54 (Fedora)
Last-Modified: Thu, 16 Mar 2006 19:02:45 GMT
ETag: "303247c3-105-40f21566a7f40"
Accept-Ranges: bytes
Content-Length: 261
Connection: close
Content-Type: image/gif
X-Pad: avoid browser bug
Si luego hacemos:
import StringIO
import pycurl
c = pycurl.Curl()
s = StringIO.StringIO()
c.setopt(pycurl.URL, 'http://theragingche.com/images/hand_made_cms.gif')
# especificamos las cabeceras
c.setopt(pycurl.HTTPHEADER,
['If-Modified-Since: Thu, 16 Mar 2006 19:02:45 GMT',
'If-None-Match: "303247c3-105-40f21566a7f40"'])
c.setopt(pycurl.WRITEFUNCTION, s.write)
c.perform()
print c.getinfo(pycurl.RESPONSE_CODE)
Nos da:
$ python head.py
304
-
Articles
- October 2014
- May 2011
- April 2011
- January 2011
- December 2010
- November 2010
- September 2010
- August 2010
- July 2010
- February 2010
- December 2009
- August 2009
- June 2009
- April 2009
- March 2009
- February 2009
- January 2009
- December 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
- August 2006
- July 2006
- June 2006
- May 2006
- April 2006
- March 2006
- February 2006
- January 2006
- December 2005
- November 2005
- October 2005
- September 2005
- August 2005
- July 2005
- December 2004
- November 2004
- October 2004
- September 2004
- August 2004
- July 2004
- June 2004
- May 2004
- April 2004
- March 2004
- February 2004
- January 2004
- December 2003
- November 2003
- October 2003
- September 2003
- August 2003
- July 2003
-
Meta