Как объединить компоненты пути при создании URL-адреса в Python
например, я хочу присоединить путь префикса к путям ресурсов, таким как /js/foo.js.
Я хочу, чтобы результирующий путь должен быть относительно корня сервера. В приведенном выше примере, если префикс был "media", я бы хотел, чтобы результат был /media/js/foo.js.
ОС.путь.join делает это очень хорошо,но как он соединяет пути зависит от ОС. В этом случае я знаю, что ориентируюсь на веб, а не на локальную файловую систему.
есть ли лучшая альтернатива, когда вы не работа с путями, которые вы знаете, будут использоваться в URL-адресах? Уилл ОС.путь.работа достаточно хорошо? Я должен просто свернуть свой собственный?
8 ответов:
поскольку, из комментариев, опубликованных OP, кажется, что он не хотите сохранить "абсолютные URL" в соединении (что является одним из ключевых заданий
urlparse.urljoin
; -), Я бы рекомендовал избегать этого.os.path.join
также было бы плохо, по той же самой причине.Итак, я бы использовал что-то вроде
'/'.join(s.strip('/') for s in pieces)
(если ведущий/
также должны быть проигнорированы - если ведущая часть должна быть специальной, это также возможно, конечно; -).
вместо python2
>>> import urlparse >>> urlparse.urljoin('/media/path/', 'js/foo.js') '/media/path/js/foo.js'
но будьте осторожны,
>>> import urlparse >>> urlparse.urljoin('/media/path', 'js/foo.js') '/media/js/foo.js'
а также
>>> import urlparse >>> urlparse.urljoin('/media/path', '/js/foo.js') '/js/foo.js'
Python3
>>> import urllib.parse >>> urllib.parse.urljoin('/media/path/', 'js/foo.js') '/media/path/js/foo.js'
причина, по которой вы получаете разные результаты от
/js/foo.js
иjs/foo.js
это потому, что первый начинается с косой черты, которая означает, что он уже начинается в корне сайта.
как вы говорите,
os.path.join
соединяет пути на основе текущей ОС.posixpath
является базовым модулем, который используется в системах posix под пространством именos.path
:>>> os.path.join is posixpath.join True >>> posixpath.join('/media/', 'js/foo.js') '/media/js/foo.js'
так что вы можете просто импортировать и использовать
posixpath.join
вместо URL, который доступен и будет работать на любой платформе.Edit: @предложение Пита является хорошим, вы можете псевдоним импорта для увеличения читаемость
from posixpath import join as urljoin
Edit: я думаю, что это стало яснее, или, по крайней мере, помогло мне понять, если вы посмотрите в источник
os.py
(код здесь от Python 2.7.11, плюс я обрезал некоторые биты). Есть условный импорт вos.py
это выбирает, какой модуль пути использовать в пространстве именos.path
. Все базовые модули (posixpath
,ntpath
,os2emxpath
,riscospath
), которые могут быть импортированы вos.py
С псевдонимомpath
, существуют и существуют для использования на всех системах.os.py
просто выбирает один из модулей для использования в пространстве именos.path
во время выполнения на основе текущей ОС.# os.py import sys, errno _names = sys.builtin_module_names if 'posix' in _names: # ... from posix import * # ... import posixpath as path # ... elif 'nt' in _names: # ... from nt import * # ... import ntpath as path # ... elif 'os2' in _names: # ... from os2 import * # ... if sys.version.find('EMX GCC') == -1: import ntpath as path else: import os2emxpath as path from _emx_link import link # ... elif 'ce' in _names: # ... from ce import * # ... # We can use the standard Windows path. import ntpath as path elif 'riscos' in _names: # ... from riscos import * # ... import riscospath as path # ... else: raise ImportError, 'no os specific module found'
это делает работу хорошо:
def urljoin(*args): """ Joins given arguments into an url. Trailing but not leading slashes are stripped for each argument. """ return "/".join(map(lambda x: str(x).rstrip('/'), args))
на basejoin на urllib может быть то, что вы ищете.
basejoin = urljoin(base, url, allow_fragments=True) Join a base URL and a possibly relative URL to form an absolute interpretation of the latter.
Edit: я не заметил раньше, но urllib.basejoin, кажется, сопоставляется непосредственно с urlparse.urljoin, что делает последнее предпочтительным.
Я знаю, что это немного больше, чем просил OP, однако у меня были куски по следующему url-адресу, и я искал простой способ присоединиться к ним:
>>> url = 'https://api.foo.com/orders/bartag?spamStatus=awaiting_spam&page=1&pageSize=250'
оглядываясь вокруг:
>>> split = urlparse.urlsplit(url) >>> split SplitResult(scheme='https', netloc='api.foo.com', path='/orders/bartag', query='spamStatus=awaiting_spam&page=1&pageSize=250', fragment='') >>> type(split) <class 'urlparse.SplitResult'> >>> dir(split) ['__add__', '__class__', '__contains__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getslice__', '__getstate__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__module__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmul__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '__weakref__', '_asdict', '_fields', '_make', '_replace', 'count', 'fragment', 'geturl', 'hostname', 'index', 'netloc', 'password', 'path', 'port', 'query', 'scheme', 'username'] >>> split[0] 'https' >>> split = (split[:]) >>> type(split) <type 'tuple'>
Так что в дополнение к пути присоединения, который уже был дан в других ответах,чтобы получить то, что я искал, я сделал следующее:
>>> split ('https', 'api.foo.com', '/orders/bartag', 'spamStatus=awaiting_spam&page=1&pageSize=250', '') >>> unsplit = urlparse.urlunsplit(split) >>> unsplit 'https://api.foo.com/orders/bartag?spamStatus=awaiting_spam&page=1&pageSize=250'
По словам документация это занимает ровно 5 часть кортеж.
со следующим форматом кортежа:
схема 0 url спецификатор схемы пустая строка
netloc 1 сетевое расположение часть пустая строка
путь 2 иерархический путь пустая строка
запрос 3 компонент запроса пустая строка
фрагмент 4 идентификатор фрагмента пустая строка
чтобы немного улучшить ответ Алекса Мартелли, следующее будет не только очищать дополнительные косые черты, но и сохранять конечные (конечные) косые черты, которые иногда могут быть полезны :
>>> items = ["http://www.website.com", "/api", "v2/"] >>> url = "/".join([(u.strip("/") if index + 1 < len(items) else u.lstrip("/")) for index, u in enumerate(items)]) >>> print(url) http://www.website.com/api/v2/
это не так легко читать, хотя,и не будет очистки нескольких дополнительных конечных косых черт.