¿Cómo obtener con seguridad la extensión de archivo de una URL?

Considere las siguientes URL

 http://m3u.com/tunein.m3u
 http://asxsomeurl.com/listen.asx:8024
 http://www.plssomeotherurl.com/station.pls?id=111
 http://22.198.133.16:8024

¿Cuál es la forma correcta de determinar las extensiones de archivo (.m3u / .asx / .pls)? Obviamente el último no tiene una extensión de archivo.

EDITAR: Olvidé mencionar que m3u / asx / pls son listas de reproducción (archivos de texto) para transmisiones de audio y se deben analizar de manera diferente. El objective determina la extensión y luego envía la url a la función de análisis adecuada. P.ej

url = argv[1] ext = GetExtension(url) if ext == "pls": realurl = ParsePLS(url) elif ext == "asx": realurl = ParseASX(url) (etc.) else: realurl = url Play(realurl) 

GetExtension () debe devolver la extensión del archivo (si corresponde), preferiblemente sin conectarse a la URL.

La verdadera forma correcta es no usar las extensiones de archivo en absoluto. Realice una solicitud GET (o HEAD) a la URL en cuestión y use el encabezado HTTP devuelto “Tipo de contenido” para obtener el tipo de contenido. Las extensiones de archivo no son fiables.

Consulte la referencia MIME multimedia para obtener una lista de los tipos MIME útiles.

Use urlparse para analizar la ruta de acceso de la URL, luego os.path.splitext para obtener la extensión.

 import urlparse, os url = 'http://www.plssomeotherurl.com/station.pls?id=111' path = urlparse.urlparse(url).path ext = os.path.splitext(path)[1] 

Tenga en cuenta que la extensión puede no ser un indicador confiable del tipo de archivo. El Content-Type HTTP Content-Type puede ser mejor.

Esto es más fácil con requests y mimetypes :

 import requests import mimetypes response = requests.get(url) content_type = response.headers['content-type'] extension = mimetypes.guess_extension(content_type) 

La extensión incluye un prefijo de punto. Por ejemplo, la extension es '.png' para el tipo de contenido 'image/png' .

Las extensiones de archivo básicamente no tienen sentido en las URL. Por ejemplo, si va a http://code.google.com/p/unladen-swallow/source/browse/branches/release-2009Q1-maint/Lib/psyco/support.py?r=292 , ¿desea que la extensión será “.py” a pesar del hecho de que la página es HTML, no Python?

Utilice el encabezado Content-Type para determinar el “tipo” de una URL.

 $ python3 Python 3.1.2 (release31-maint, Sep 17 2010, 20:27:33) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from os.path import splitext >>> from urllib.parse import urlparse >>> >>> urls = [ ... 'http://m3u.com/tunein.m3u', ... 'http://asxsomeurl.com/listen.asx:8024', ... 'http://www.plssomeotherurl.com/station.pls?id=111', ... 'http://22.198.133.16:8024', ... ] >>> >>> for url in urls: ... path = urlparse(url).path ... ext = splitext(path)[1] ... print(ext) ... .m3u .asx:8024 .pls >>> 

Para obtener el tipo de contenido, puede escribir una función como la que escribí usando urllib2. Si necesita utilizar el contenido de la página de todos modos, es probable que use urllib2, por lo que no es necesario importar el sistema operativo.

 import urllib2 def getContentType(pageUrl): page = urllib2.urlopen(pageUrl) pageHeaders = page.headers contentType = pageHeaders.getheader('content-type') return contentType 

Un enfoque diferente que no tiene en cuenta nada más, excepto la extensión de archivo real de una url:

 def fileExt( url ): # compile regular expressions reQuery = re.compile( r'\?.*$', re.IGNORECASE ) rePort = re.compile( r':[0-9]+', re.IGNORECASE ) reExt = re.compile( r'(\.[A-Za-z0-9]+$)', re.IGNORECASE ) # remove query string url = reQuery.sub( "", url ) # remove port url = rePort.sub( "", url ) # extract extension matches = reExt.search( url ) if None != matches: return matches.group( 1 ) return None 

edición: agregado manejo de puertos explícitos desde: 1234

Use urlparse, que obtendrá la mayoría de los anteriores ordenados:

http://docs.python.org/library/urlparse.html

luego divide el “camino”. Es posible que pueda dividir la ruta utilizando os.path.split, pero su ejemplo 2 con: 8024 en el extremo necesita manejo manual. ¿Son sus extensiones de archivo siempre tres letras? ¿O siempre letras y números? Usa una expresión regular.

Puedes probar el módulo rfc6266 como :

 import requests import rfc6266 req = requests.head(downloadLink) headersContent = req.headers['Content-Disposition'] rfcFilename = rfc6266.parse_headers(headersContent, relaxed=True).filename_unsafe filename = requests.utils.unquote(rfcFilename)