在Python中构buildURL时如何joinpath的组件

例如,我想要join像/js/foo.js这样的资源path的前缀path。

我想要得到的path是相对于服务器的根。 在上面的例子中,如果前缀是“media”,我希望结果是/media/js/foo.js。

os.path.join确实做得很好,但它如何joinpath取决于操作系统。 在这种情况下,我知道我的目标是networking,而不是本地文件系统。

当你正在使用你知道将在URLs中使用的path时,有没有最好的select? os.path.join会工作得好吗? 我应该推出自己的?

因为从OP发布的评论看来,他似乎并不想保留连接(这是urlparse.urljoin的关键工作之一)中的“绝对URL”,我build议避免这种情况。 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.jsjs/foo.js得到不同结果的原因是因为前者以斜杠开始,表示它已经从网站根开始。

就像你说的, os.path.join根据当前的操作系统连接path。 posixpath是在命名空间os.path下的posix系统上使用的底层模块:

 >>> os.path.join is posixpath.join True >>> posixpath.join('/media/', 'js/foo.js') '/media/js/foo.js' 

所以你可以导入和使用posixpath.join而不是urls,这是可用的,并将在任何平台上工作。

编辑: @皮特的build议是一个很好的,你可以别名导入增加可读性

 from posixpath import join as urljoin 

编辑:我认为这是更清晰,或者至less帮助我明白,如果你看看os.py的源代码(这里的代码是从Python 2.7.11,加上我已经修剪了一些位)。 os.py中有条件的导入select在命名空间os.path使用哪个path模块。 可以在os.py导入的所有底层模块( posixpathntpathos2emxpathriscospath ),可以作为path ,可以在所有系统上使用。 os.py只是在运行时根据当前操作系统select一个在命名空间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 a url. Trailing but not leading slashes are stripped for each argument. """ return "/".join(map(lambda x: str(x).rstrip('/'), args)) 

urllib包中的basejoin函数可能是你正在寻找的东西。

 basejoin = urljoin(base, url, allow_fragments=True) Join a base URL and a possibly relative URL to form an absolute interpretation of the latter. 

编辑:我没有注意到,但urllib.basejoin似乎直接映射到urlparse.urljoin,使后者首选。

我知道这比OP所要求的要多一点,但是我把这些东西放到了下面的URL中,并且正在寻找一个简单的方法来join它们:

 >>> 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'> 

所以除了已经在其他答案已经回答的pathjoin, 以获得我正在寻找我做了以下几点:

 >>> 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部分元组。

使用以下元组格式:

scheme 0 URL scheme说明符空string

netloc 1networking位置部分空string

path2分层path空string

查询3查询组件空string

片段4片段标识符为空string

使用furl, pip install furl它将是:

  furl.furl('/media/path/').add(path='js/foo.js') 

为了稍微改善Alex Martelli的回应,下面的内容不仅会清除额外的斜线,还会保留尾部的(结尾的)斜杠,有时这些斜杠有时是有用的:

 >>> 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/ 

虽然阅读起来并不容易,但也不会清理多个额外的尾部斜线。