[python] Python에서 URL을 생성 할 때 경로의 구성 요소를 결합하는 방법

예를 들어 /js/foo.js와 같은 리소스 경로에 대한 접두사 경로를 결합하고 싶습니다.

결과 경로가 서버의 루트에 상대적 이길 원합니다. 위의 예에서 접두사가 “media”이면 결과는 /media/js/foo.js가됩니다.

os.path.join은이 작업을 정말 잘 수행하지만 경로를 연결하는 방법은 OS에 따라 다릅니다. 이 경우 로컬 파일 시스템이 아닌 웹을 대상으로한다는 것을 알고 있습니다.

URL에서 사용되는 경로로 작업 할 때 가장 좋은 대안이 있습니까? os.path.join이 충분히 잘 작동합니까? 내가 직접 굴려야하나요?



답변

OP가 게시 한 댓글에서 그는 조인 ( ;- 의 핵심 작업 중 하나)에서 “절대 URL”을 보존하고 싶지 않은urlparse.urljoin같으 므로 피하는 것이 좋습니다. os.path.join정확히 같은 이유로 나쁠 것입니다.

그래서 나는 다음과 같은 것을 사용할 것입니다. '/'.join(s.strip('/') for s in pieces)(리딩 /도 무시해야한다면-리딩 부분이 특수한 경우라면 당연히 가능합니다 ;-).


답변

다음을 사용할 수 있습니다 urllib.parse.urljoin.

>>> from urllib.parse import urljoin
>>> urljoin('/media/path/', 'js/foo.js')
'/media/path/js/foo.js'

그러나 조심하십시오 :

>>> urljoin('/media/path', 'js/foo.js')
'/media/js/foo.js'
>>> urljoin('/media/path', '/js/foo.js')
'/js/foo.js'

그 이유는 당신은 다른 결과를 얻을 /js/foo.jsjs/foo.js전자는 이미 웹 사이트의 루트에서 시작 것을 의미 슬래시로 시작하기 때문이다.

Python 2에서는 다음을 수행해야합니다.

from urlparse import urljoin


답변

말했듯 os.path.join이 현재 OS를 기반으로 경로를 결합합니다. posixpath네임 스페이스 아래 posix 시스템에서 사용되는 기본 모듈입니다 os.path.

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

따라서 사용 posixpath.join가능하며 모든 플랫폼에서 작동하는 URL 대신 가져 와서 사용할 수 있습니다 .

편집 : @Pete의 제안은 좋은 것입니다. 가독성을 높이기 위해 가져 오기를 별칭으로 지정할 수 있습니다.

from posixpath import join as urljoin

편집 : 소스를 살펴보면 이것이 더 명확 해졌거나 적어도 이해하는 데 도움이되었다고 생각합니다 os.py(여기 코드는 Python 2.7.11에서 가져온 것입니다. os.py네임 스페이스에서 사용할 경로 모듈을 선택하는 조건부 가져 오기가 있습니다 os.path. 모든 기본 모듈 ( posixpath, ntpath, os2emxpath, riscospath)에서 가져올 수 os.py별칭으로, path, 거기 모든 시스템에서 사용할 수 존재한다. 현재 OS를 기반으로 런타임에 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))


답변

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에 직접 매핑되어 후자가 선호됩니다.


답변

furl을 사용 pip install furl하면 다음과 같습니다.

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


답변

나는 이것이 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 조각 식별자 빈 문자열