Как безопасно получить расширение файла из URL?
Рассмотрим следующие 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
Каков правильный способ определения расширений файлов (.m3u/.asx/.pls)? Очевидно, что последний не имеет расширения файла.
EDIT: Я забыл упомянуть, что m3u/asx/pls являются плейлистами (текстовыми файлами) для аудиопотоков и должны анализироваться по-разному. Цель определяет расширение, а затем отправляет URL-адрес правильной функции синтаксического анализа. Например.
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() should return the file extension (if any), preferrably without connecting to the URL.
Ответы
Ответ 1
Настоящий правильный способ - вообще не использовать расширения файлов. Выполните запрос GET (или HEAD) к соответствующему URL-адресу и используйте возвращенный HTTP-заголовок "Content-type", чтобы получить тип содержимого. Расширения файлов ненадежны.
Посмотрите типы MIME (типы носителей IANA) для получения дополнительной информации и списка полезных типов MIME.
Ответ 2
Используйте urlparse
для анализа пути из URL-адреса, затем os.path.splitext
, чтобы получить расширение.
import urlparse, os
url = 'http://www.plssomeotherurl.com/station.pls?id=111'
path = urlparse.urlparse(url).path
ext = os.path.splitext(path)[1]
Обратите внимание, что расширение не может быть надежным индикатором типа файла. Заголовок HTTP Content-Type
может быть лучше.
Ответ 3
Это проще всего с requests
и mimetypes
:
import requests
import mimetypes
response = requests.get(url)
content_type = response.headers['content-type']
extension = mimetypes.guess_extension(content_type)
Расширение включает префикс точки. Например, extension
- '.png'
для типа контента 'image/png'
.
Ответ 4
Расширения файлов в основном не имеют смысла в URL-адресах. Например, если вы перейдете к http://code.google.com/p/unladen-swallow/source/browse/branches/release-2009Q1-maint/Lib/psyco/support.py?r=292, вы хотите, чтобы расширение было ".py", несмотря на то, что страница является HTML, а не Python?
Используйте заголовок Content-Type, чтобы определить "тип" URL-адреса.
Ответ 5
$ 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
>>>
Ответ 6
Чтобы получить тип содержимого, вы можете написать функцию, подобную написанной с использованием urllib2.
Если вам все равно нужно использовать содержимое страницы, вполне вероятно, что вы будете использовать urllib2, поэтому не нужно импортировать os.
import urllib2
def getContentType(pageUrl):
page = urllib2.urlopen(pageUrl)
pageHeaders = page.headers
contentType = pageHeaders.getheader('content-type')
return contentType
Ответ 7
Другой подход, который не учитывает ничего другого, кроме фактического расширения файла из 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
edit: добавлена обработка явных портов от: 1234
Ответ 8
Используйте urlparse, который получит большую часть выше отсортированного:
http://docs.python.org/library/urlparse.html
затем разделите "путь" вверх. Возможно, вы сможете разделить путь с помощью os.path.split, но ваш пример 2 с: 8024 на конце требует ручной обработки. Всегда ли ваши расширения файлов имеют три буквы? Или всегда буквы и цифры? Используйте регулярное выражение.
Ответ 9
Вы можете попробовать модуль rfc6266 как:
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)