имя файла urllib2

Если я открою файл с помощью urllib2, например:

remotefile = urllib2.urlopen('http://example.com/somefile.zip')

Есть ли простой способ получить имя файла, отличное от анализа исходного URL-адреса?

РЕДАКТИРОВАТЬ: изменил openfile на urlopen... не уверен, как это произошло.

EDIT2: в итоге я использовал:

filename = url.split('/')[-1].split('#')[0].split('?')[0]

Если я не ошибаюсь, это также должно исключить все потенциальные запросы.


person defrex    schedule 02.10.2008    source источник
comment
я думаю это не правильно. Я имею в виду urllib2.openfile(...)   -  person user15453    schedule 02.10.2008
comment
Убедитесь, что вы знаете, что вам нужно в этих двух случаях: завершающая косая черта (http://example.com/somefile/) и отсутствие пути: http://example.com Ваш пример точно не сработает в последнем случае (возвращение example.com). Как и окончательный ответ @insin. Это еще одна причина, по которой использование urlsplit является хорошим советом.   -  person nealmcb    schedule 09.02.2012
comment
из заголовков ответов: stackoverflow.com/questions/11783269/   -  person jozxyqk    schedule 01.11.2015
comment
Многие ответы здесь упускают из виду тот факт, что есть два места для поиска имени файла: URL-адрес и поле заголовка Content-Disposition. Все текущие ответы, в которых упоминается заголовок, не упоминают, что cgi.parse_header() будет правильно его анализировать. Здесь есть лучший ответ: stackoverflow.com/a/11783319/205212   -  person ʇsәɹoɈ    schedule 11.10.2016


Ответы (14)


Вы имели в виду urllib2.urlopen?

Вы могли бы поднять предполагаемое имя файла, если сервер отправлял заголовок Content-Disposition, проверяя remotefile.info()['Content-Disposition'], но я думаю, что вам просто нужно проанализировать URL-адрес .

Вы можете использовать urlparse.urlsplit, но если у вас есть какие-либо URL-адреса, как во втором примере, вам все равно придется извлекать имя файла самостоятельно:

>>> urlparse.urlsplit('http://example.com/somefile.zip')
('http', 'example.com', '/somefile.zip', '', '')
>>> urlparse.urlsplit('http://example.com/somedir/somefile.zip')
('http', 'example.com', '/somedir/somefile.zip', '', '')

Можно просто сделать так:

>>> 'http://example.com/somefile.zip'.split('/')[-1]
'somefile.zip'
>>> 'http://example.com/somedir/somefile.zip'.split('/')[-1]
'somefile.zip'
person Jonny Buchanan    schedule 02.10.2008
comment
Используйте posixpath.basename() вместо ручного разделения на '/'. - person Thomas Wouters; 02.10.2008
comment
Я бы всегда использовал urlsplit() и никогда не разбивал строки напрямую. Последний будет задыхаться, если у вас есть URL-адрес, к которому добавлен фрагмент или запрос, скажем, example. com/filename.html?cookie=55#Section_3. - person Dan Lenski; 02.10.2008
comment
Как насчет экранированных символов? Должны ли они быть расшифрованы в первую очередь? - person awiebe; 07.07.2017

Если вам нужно только само имя файла, предполагая, что в конце нет переменных запроса, таких как http://example.com/somedir/somefile.zip?foo=bar, тогда вы можете использовать для этого os.path.basename:

[user@host]$ python
Python 2.5.1 (r251:54869, Apr 18 2007, 22:08:04) 
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.path.basename("http://example.com/somefile.zip")
'somefile.zip'
>>> os.path.basename("http://example.com/somedir/somefile.zip")
'somefile.zip'
>>> os.path.basename("http://example.com/somedir/somefile.zip?foo=bar")
'somefile.zip?foo=bar'

Некоторые другие постеры упоминали об использовании urlparse, который будет работать, но вам все равно нужно будет удалить начальный каталог из имени файла. Если вы используете os.path.basename(), вам не нужно об этом беспокоиться, так как он возвращает только последнюю часть URL-адреса или пути к файлу.

person Jay    schedule 02.10.2008
comment
Использование os.path для синтаксического анализа URL-адресов, по-видимому, зависит от текущих путей разделения ОС таким же образом, как и URL-адреса. Я не думаю, что это гарантировано для каждой ОС. - person Rafał Dowgird; 11.06.2013
comment
Это не будет работать в Windows. Вместо этого используйте import posixpath; posixpath.basename. - person j08lue; 12.01.2017

Я думаю, что «имя файла» не очень четко определенная концепция, когда речь идет о передаче http. Сервер может (но не обязан) предоставить его в качестве заголовка «content-disposition», вы можете попытаться получить его с помощью remotefile.headers['Content-Disposition']. Если это не удается, вам, вероятно, придется самостоятельно анализировать URI.

person Rafał Dowgird    schedule 02.10.2008

Только что увидел, что я обычно делаю..

filename = url.split("?")[0].split("/")[-1]
person TMF Wolfman    schedule 20.03.2015

Использование urlsplit — самый безопасный вариант:

url = 'http://example.com/somefile.zip'
urlparse.urlsplit(url).path.split('/')[-1]
person Filipe Correia    schedule 31.03.2013

Вы имеете в виду urllib2.urlopen? В модуле urllib2 нет функции с именем openfile.

В любом случае, используйте функции urllib2.urlparse:

>>> from urllib2 import urlparse
>>> print urlparse.urlsplit('http://example.com/somefile.zip')
('http', 'example.com', '/somefile.zip', '', '')

Вуаля.

person Dan Lenski    schedule 02.10.2008

Вы также можете объединить оба из двух лучших ответов: используя urllib2.urlparse.urlsplit(), чтобы получить часть пути URL-адреса, а затем os.path.basename для фактического имени файла.

Полный код будет:

>>> remotefile=urllib2.urlopen(url)
>>> try:
>>>   filename=remotefile.info()['Content-Disposition']
>>> except KeyError:
>>>   filename=os.path.basename(urllib2.urlparse.urlsplit(url).path)
person Yth    schedule 28.04.2016

Функция os.path.basename работает не только с путями к файлам, но и с URL-адресами, поэтому вам не нужно вручную анализировать URL-адрес самостоятельно. Кроме того, важно отметить, что вы должны использовать result.url вместо исходного URL-адреса, чтобы следовать ответам перенаправления:

import os
import urllib2
result = urllib2.urlopen(url)
real_url = urllib2.urlparse.urlparse(result.url)
filename = os.path.basename(real_url.path)
person Régis B.    schedule 11.05.2015

Я думаю, это зависит от того, что вы подразумеваете под синтаксическим анализом. Невозможно получить имя файла без анализа URL-адреса, т.е. удаленный сервер не дает вам имя файла. Однако вам не нужно много делать самому, есть модуль urlparse:

In [9]: urlparse.urlparse('http://example.com/somefile.zip')
Out[9]: ('http', 'example.com', '/somefile.zip', '', '', '')
person miracle2k    schedule 02.10.2008

не то, что я знаю из.

но вы можете легко разобрать его следующим образом:

url = 'http://example.com/somefile.zip'
print url.split('/')[-1]

person Corey Goldberg    schedule 02.10.2008

используя запросы, но вы можете легко сделать это с помощью urllib(2)

import requests
from urllib import unquote
from urlparse import urlparse

sample = requests.get(url)

if sample.status_code == 200:
    #has_key not work here, and this help avoid problem with names

    if filename == False:

        if 'content-disposition' in sample.headers.keys():
            filename = sample.headers['content-disposition'].split('filename=')[-1].replace('"','').replace(';','')

        else:

            filename = urlparse(sample.url).query.split('/')[-1].split('=')[-1].split('&')[-1]

            if not filename:

                if url.split('/')[-1] != '':
                    filename = sample.url.split('/')[-1].split('=')[-1].split('&')[-1]
                    filename = unquote(filename)
person DoomedRaven    schedule 26.02.2014

Вы, вероятно, можете использовать здесь простое регулярное выражение. Что-то типа:

In [26]: import re
In [27]: pat = re.compile('.+[\/\?#=]([\w-]+\.[\w-]+(?:\.[\w-]+)?$)')
In [28]: test_set 

['http://www.google.com/a341.tar.gz',
 'http://www.google.com/a341.gz',
 'http://www.google.com/asdasd/aadssd.gz',
 'http://www.google.com/asdasd?aadssd.gz',
 'http://www.google.com/asdasd#blah.gz',
 'http://www.google.com/asdasd?filename=xxxbl.gz']

In [30]: for url in test_set:
   ....:     match = pat.match(url)
   ....:     if match and match.groups():
   ....:         print(match.groups()[0])
   ....:         

a341.tar.gz
a341.gz
aadssd.gz
aadssd.gz
blah.gz
xxxbl.gz
person Vovan Kuznetsov    schedule 10.09.2015

Использование PurePosixPath, который не зависит от операционной системы и корректно обрабатывает URL-адреса. это питоническое решение:

>>> from pathlib import PurePosixPath
>>> path = PurePosixPath('http://example.com/somefile.zip')
>>> path.name
'somefile.zip'
>>> path = PurePosixPath('http://example.com/nested/somefile.zip')
>>> path.name
'somefile.zip'

Обратите внимание, что здесь нет сетевого трафика или чего-то еще (т. е. эти URL-адреса никуда не ведут) — просто используются стандартные правила синтаксического анализа.

person Adam Nelson    schedule 11.04.2016

import os,urllib2
resp = urllib2.urlopen('http://www.example.com/index.html')
my_url = resp.geturl()

os.path.split(my_url)[1]

# 'index.html'

Это не openfile, но, возможно, все же помогает :)

person user15453    schedule 02.10.2008