Python에서 URL을 구성할 때 경로의 구성 요소를 결합하는 방법
예를 들어 /js/foo.js와 같은 리소스 경로의 접두사 경로에 가입하려고 합니다.
결과 경로가 서버 루트에 상대적이 되도록 합니다.위의 예에서 접두사가 "media"이면 결과는 /media/js/foo.js가 됩니다.
os.path.join은 이를 매우 잘 수행하지만 경로에 가입하는 방법은 OS에 따라 다릅니다.이 경우에는 로컬 파일 시스템이 아닌 웹을 대상으로 합니다.
URL에서 사용할 경로를 알고 작업할 때 가장 좋은 대안이 있습니까?will os.path.join은 충분히 잘 작동합니까?제가 직접 굴릴까요?
다음을 사용할 수 있습니다.
>>> 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.js
그리고.js/foo.js
전자가 이미 웹 사이트 루트에서 시작됨을 나타내는 슬래시로 시작하기 때문입니다.
Python 2에서는 다음 작업을 수행해야 합니다.
from urlparse import urljoin
OP가 올린 댓글을 보면, 그는 조인에서 "절대 URL"을 보존하고 싶지 않은 것 같습니다(이것은 주요 작업 중 하나입니다).urlparse.urljoin
;-), 저는 그것을 피하는 것을 추천합니다. os.path.join
또한 좋지 않을 것입니다, 정확히 같은 이유로.
그래서, 저는 그런 것을 사용합니다.'/'.join(s.strip('/') for s in pieces)
에 있는 경우 (선행는경우하경))/
또한 무시해야 합니다. -- 만약 주연 작품이 특별한 경우에도 당연히 가능합니다;-).
처럼, 네말로대,로.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
모듈module)posixpath
,ntpath
,os2emxpath
,riscospath
할 수 입니다.os.py
로서 별칭이 붙은.path
모든 시스템에서 사용할 수 있도록 존재합니다. os.py
에 사용할 모듈 중 하나를 입니다.os.path
현재 OS를 기준으로 실행 시.
# 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))
저는 위의 모든 솔루션에 대해 마음에 들지 않는 점을 발견하고 저만의 솔루션을 생각해 냈습니다.이 버전에서는 부품이 단일 슬래시로 결합되고 선행 슬래시와 후행 슬래시만 남게 됩니다.아니요.pip install
,아니요.urllib.parse.urljoin
기묘한 일
In [1]: from functools import reduce
In [2]: def join_slash(a, b):
...: return a.rstrip('/') + '/' + b.lstrip('/')
...:
In [3]: def urljoin(*args):
...: return reduce(join_slash, args) if args else ''
...:
In [4]: parts = ['https://foo-bar.quux.net', '/foo', 'bar', '/bat/', '/quux/']
In [5]: urljoin(*parts)
Out[5]: 'https://foo-bar.quux.net/foo/bar/bat/quux/'
In [6]: urljoin('https://quux.com/', '/path', 'to/file///', '//here/')
Out[6]: 'https://quux.com/path/to/file/here/'
In [7]: urljoin()
Out[7]: ''
In [8]: urljoin('//','beware', 'of/this///')
Out[8]: '/beware/of/this///'
In [9]: urljoin('/leading', 'and/', '/trailing/', 'slash/')
Out[9]: '/leading/and/trailing/slash/'
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.
편집: 이전에는 몰랐는데 urllib.basejoin이 urlparse.urljoin에 직접 매핑되어 후자를 선호하는 것 같습니다.
사용해서, 서해이용을털,,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 쿼리 구성 요소 빈 문자열
fragment 4 fragment 식별자 빈 문자열
Rune Kaagard는 저에게 효과가 있는 훌륭하고 컴팩트한 솔루션을 제공했습니다. 저는 이에 대해 조금 더 자세히 설명했습니다.
def urljoin(*args):
trailing_slash = '/' if args[-1].endswith('/') else ''
return "/".join(map(lambda x: str(x).strip('/'), args)) + trailing_slash
이렇게 하면 슬래시가 있는 경우 마지막 슬래시를 유지하면서 슬래시의 후행 및 끝에 관계없이 모든 인수를 결합할 수 있습니다.
다음은 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/
하지만 읽기가 그렇게 쉽지 않고 추가 후행 슬래시를 정리하지도 않습니다.
이거 어때:어느 정도 효율적이고 어느 정도 단순합니다.url 경로의 '2' 부분만 가입하면 됩니다.
def UrlJoin(a , b):
a, b = a.strip(), b.strip()
a = a if a.endswith('/') else a + '/'
b = b if not b.startswith('/') else b[1:]
return a + b
OR: 일반적이지만 경로의 URL 부분을 2개만 결합하면 효율성이 떨어집니다.
def UrlJoin(*parts):
return '/'.join([p.strip().strip('/') for p in parts])
테스트 사례:
>>> UrlJoin('https://example.com/', '/TestURL_1')
'https://example.com/TestURL_1'
>>> UrlJoin('https://example.com', 'TestURL_2')
'https://example.com/TestURL_2'
참고: 여기서 머리를 쪼개고 있을 수도 있지만, 적어도 좋은 방법이며 잠재적으로 더 읽기 쉽습니다.
>>> import re
>>> import furl
>>> p = re.compile(r'(\/)+')
>>> url = furl.furl('/media/path').add(path='/js/foo.js').url
>>> url
'/media/path/js/foo.js'
>>> p.sub(r"\1", url)
'/media/path/js/foo.js'
>>> url = furl.furl('/media/path').add(path='js/foo.js').url
>>> url
'/media/path/js/foo.js'
>>> p.sub(r"\1", url)
'/media/path/js/foo.js'
>>> url = furl.furl('/media/path/').add(path='js/foo.js').url
>>> url
'/media/path/js/foo.js'
>>> p.sub(r"\1", url)
'/media/path/js/foo.js'
>>> url = furl.furl('/media///path///').add(path='//js///foo.js').url
>>> url
'/media///path/////js///foo.js'
>>> p.sub(r"\1", url)
'/media/path/js/foo.js'
라이너 하나:
from functools import reduce
reduce(lambda x,y: '{}/{}'.format(x,y), parts)
여기서 부품은 ['https://api.somecompany.com/v1', '날씨', '비']입니다.
제가 사용하고 있는 안전한 버전이 있습니다.접두사와 후행 슬래시를 처리합니다.끝 URI에 대한 후행 슬래시는 별도로 처리됩니다.
def safe_urljoin(*uris) -> str:
"""
Joins the URIs carefully considering the prefixes and trailing slashes.
The trailing slash for the end URI is handled separately.
"""
if len(uris) == 1:
return uris[0]
safe_urls = [
f"{url.lstrip('/')}/" if not url.endswith("/") else url.lstrip("/")
for url in uris[:-1]
]
safe_urls.append(uris[-1].lstrip("/"))
return "".join(safe_urls)
산출물
>>> safe_urljoin("https://a.com/", "adunits/", "/both/", "/left")
>>> 'https://a.com/adunits/both/left'
>>> safe_urljoin("https://a.com/", "adunits/", "/both/", "right/")
>>> 'https://a.com/adunits/both/right/'
>>> safe_urljoin("https://a.com/", "adunits/", "/both/", "right/", "none")
>>> 'https://a.com/adunits/both/right/none'
>>> safe_urljoin("https://a.com/", "adunits/", "/both/", "right/", "none/")
>>> 'https://a.com/adunits/both/right/none/'
고유한 기능을 가진 또 다른 변형:
def urljoin(base:str, *parts:str) -> str:
for part in filter(None, parts):
base = '{}/{}'.format(base.rstrip('/'), part.lstrip('/'))
return base
- 후행 슬래시를 기본 또는 마지막 부분에 유지
- 빈 부품은 무시됩니다.
- 비어 있지 않은 각 부품에 대해 베이스에서 후행을 제거하고 부품에서 선행을 제거한 후 단일 부품으로 결합합니다.
/
urljoin('http://a.com/api', '') -> 'http://a.com/api'
urljoin('http://a.com/api', '/') -> 'http://a.com/api/'
urljoin('http://a.com/api/', '') -> 'http://a.com/api/'
urljoin('http://a.com/api/', '/') -> 'http://a.com/api/'
urljoin('http://a.com/api/', '/a/', '/b', 'c', 'd/') -> 'http://a.com/api/a/b/c/d/'
네, 제가 한 일이 바로 그거예요. 미리 정의된 뿌리로부터 완전히 독립해야 했기 때문입니다.
def url_join(base: str, *components: str, slash_left=True, slash_right=True) -> str:
"""Join two or more url components, inserting '/' as needed.
Optionally, a slash can be added to the left or right side of the URL.
"""
base = base.lstrip('/').rstrip('/')
components = [component.lstrip('/').rstrip('/') for component in components]
url = f"/{base}" if slash_left else base
for component in components:
url = f"{url}/{component}"
return f"{url}/" if slash_right else url
url_join("http://whoops.io", "foo/", "/bar", "foo", slash_left=False)
# "http://whoops.io/foo/bar/foo/"
url_join("foo", "bar")
# "/foo/bar/""
언급URL : https://stackoverflow.com/questions/1793261/how-to-join-components-of-a-path-when-you-are-constructing-a-url-in-python
'programing' 카테고리의 다른 글
Mac OS X에 애드버타이즈 설정 (0) | 2023.06.25 |
---|---|
springboot : 핸들러의 사전 핸들에서 오류 상태 코드를 반환하는 방법요격기 (0) | 2023.06.25 |
프록시 뒤에서 루비 보석을 업데이트하는 방법(ISA-NTLM) (0) | 2023.06.25 |
작업은 Excel 시트를 업데이트할 때 업데이트 가능한 쿼리를 사용해야 합니다. (0) | 2023.06.20 |
빌딩 cx_Oracle 문제 - libclntsh.so .11.1 => 찾을 수 없음 (0) | 2023.06.20 |