जब आप पायथन में एक URL का निर्माण कर रहे हैं, तो एक पथ के घटकों में कैसे शामिल हों


103

उदाहरण के लिए, मैं /js/foo.js जैसे संसाधन पथों के लिए एक उपसर्ग पथ से जुड़ना चाहता हूं।

मैं परिणामी पथ को सर्वर की जड़ के सापेक्ष बनाना चाहता हूं। उपर्युक्त उदाहरण में यदि उपसर्ग "मीडिया" था, तो मैं परिणाम / amedia/js/foo.js होना चाहूंगा।

os.path.join यह वास्तव में अच्छी तरह से करता है, लेकिन यह पथों से कैसे जुड़ता है यह OS पर निर्भर है। इस मामले में मुझे पता है कि मैं वेब को लक्षित कर रहा हूं, स्थानीय फाइल सिस्टम को नहीं।

क्या कोई सबसे अच्छा विकल्प है जब आप उन पथों के साथ काम कर रहे हैं जिन्हें आप जानते हैं कि URL में उपयोग किया जाएगा? क्या os.path.join काफी अच्छा काम करेगा? क्या मुझे सिर्फ अपना रोल करना चाहिए?


1
os.path.joinकाम नहीं करेगा। लेकिन केवल /चरित्र से जुड़कर सभी मामलों में काम करना चाहिए - /विनिर्देश के अनुसार HTTP में मानक पथ विभाजक है।
इंट्राग्रेज

जवाबों:


60

चूंकि, टिप्पणियों को ओपी ने पोस्ट किया है, ऐसा लगता है कि वह जॉइन में "पूर्ण URL" को संरक्षित नहीं करना चाहता है (जो urlparse.urljoin;-) की प्रमुख नौकरियों में से एक है ; मैं उससे बचने की सलाह दूंगा। os.path.joinबुरा भी होगा, ठीक उसी कारण से।

तो, मैं कुछ का उपयोग करूँगा '/'.join(s.strip('/') for s in pieces)(यदि अग्रणी /को भी अनदेखा किया जाना चाहिए - यदि अग्रणी टुकड़ा विशेष आवरण होना चाहिए, तो यह निश्चित रूप से संभव है; ;-)


1
धन्यवाद। मुझे इस बात की इतनी अधिक आवश्यकता नहीं थी कि दूसरे हिस्से पर अग्रणी '/' नहीं हो सकता था, लेकिन पहले भाग पर '' / 'की आवश्यकता थी, मुझे लगता है जैसे कि इस उपयोग के मामले में urljoin कुछ नहीं कर रहा था मेरे लिए। मैं कम से कम जॉइन ("/ मीडिया", "js / foo.js") और जॉइन ("/ मीडिया /", "js / foo.js") को काम करना चाहूंगा। जो सही उत्तर प्रतीत होता है, उसके लिए धन्यवाद: अपना स्वयं का रोल करें।
अमेजन

मुझे उम्मीद थी कि कुछ मेरे लिए स्ट्रिपिंग और जॉइनिंग करेगा।
स्टेच्यूफॉमिक

नहीं, यह खिड़कियों पर काम नहीं करने वाला है, जहां os.path.join('http://media.com', 'content')लौकी वापस आती है http://media.com\content
सीएफ

154

आप उपयोग कर सकते हैं 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.jsऔर js/foo.jsऐसा इसलिए है क्योंकि पूर्व एक स्लैश से शुरू होता है जो दर्शाता है कि यह पहले से ही वेबसाइट रूट पर शुरू होता है।

अजगर 2 पर, आपको करना होगा

from urlparse import urljoin

इसलिए मेरे पास /js/foo.js पर अग्रणी "/" पट्टी है, लेकिन ऐसा लगता है कि os.path.join के साथ भी ऐसा ही होगा। मीडिया के बाद स्लैश की आवश्यकता का मतलब है मुझे वैसे भी अधिकांश काम खुद करना है।
amjoconn

विशेष रूप से एक बार मुझे लगता है कि उपसर्ग को / में समाप्त होना है और लक्ष्य पथ शुरू नहीं हो सकता है / मैं और साथ ही बस संक्षिप्त कर सकता हूं। इस मामले में मुझे यकीन नहीं है कि क्या urljoin वाकई मदद कर रहा है?
amjoconn

3
@MedhatGayed यह मेरे लिए स्पष्ट नहीं है कि urljoinकभी '/' निकालता है। यदि मैं इसे urlparse.urljoin('/media/', '/js/foo.js')लौटाए गए मान के साथ कहूं तो '/js/foo.js' है। इसने सभी मीडिया को हटा दिया, डुप्लिकेट '/' को नहीं। urlparse.urljoin('/media//', 'js/foo.js')वास्तव में वास्तव में '/media//js/foo.js' देता है, इसलिए कोई डुप्लिकेट हटाया नहीं जाता है।
amjoconn

8
urljoin में अजीब व्यवहार होता है यदि आप एक ऐसे घटक में शामिल हो रहे हैं जो अंत नहीं है / यह पहला घटक है जो इसके आधार को स्ट्रिप्स करता है और फिर दूसरे आर्ग्स पर जुड़ता है। वह नहीं जिसकी मुझे उम्मीद होगी।
पीट

7
दुर्भाग्य urljoinसे यूआरएल में शामिल होने के लिए नहीं है। यह HTML दस्तावेज़ों में पाए जाने वाले सापेक्ष URL को हल करने के लिए है, आदि
OrangeDog

46

जैसा कि आप कहते हैं, os.path.joinवर्तमान ओएस के आधार पर पथ से जुड़ता है। posixpathअंतर्निहित मॉड्यूल है जो नामस्थान के तहत पॉज़िक्स सिस्टम पर उपयोग किया जाता है os.path:

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

इसलिए आप केवल posixpath.joinयूआरएल के लिए आयात और उपयोग कर सकते हैं , जो उपलब्ध है और किसी भी प्लेटफ़ॉर्म पर काम करेगा ।

संपादित करें: @ पीट का सुझाव एक अच्छा है, आप वृद्धि की पठनीयता के लिए आयात को अन्य नाम दे सकते हैं

from posixpath import join as urljoin

संपादित करें: मुझे लगता है कि यह स्पष्ट हो गया है, या कम से कम मुझे समझने में मदद मिली है, यदि आप इसके स्रोत को देखते हैं os.py(यहां कोड पायथन 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'

4
from posixpath import join as urljoinअच्छी तरह से यह कुछ पढ़ने के लिए आसान उपनाम।
पीट

29

यह अच्छी तरह से काम करता है:

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

9

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.

संपादित करें: मैंने पहले नोटिस नहीं किया था, लेकिन urllib.basejoin को सीधे urlparse.urljoin को मैप करना प्रतीत होता है, जिससे बाद वाला पसंद किया जाता है।


9

फर्ल का उपयोग करना, pip install furlयह होगा:

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

1
यदि आप चाहते हैं कि परिणाम एक स्ट्रिंग हो जिसे आप .urlअंत में जोड़ सकते हैं :furl.furl('/media/path/').add(path='js/foo.js').url
इयाल लेविन

URL URL में urlparse.urljoin की तुलना में URL से जुड़ने में बेहतर काम करता है। 2 atleast (y)
Ciasto piekarz

यह करने के लिए बेहतर है furl('/media/path/').add(path=furl('/js/foo.js').path).urlक्योंकि furl('/media/path/').add(path='/js/foo.js').urlहै/media/path//js/foo.js
बार्टोलो-otrit

5

मुझे पता है कि यह ओपी द्वारा पूछे जाने की तुलना में थोड़ा अधिक है, हालांकि मेरे पास निम्नलिखित यूआरएल के टुकड़े थे, और उन्हें शामिल करने के लिए एक सरल तरीका ढूंढ रहा था:

>>> 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 टुकड़ा पहचानकर्ता खाली स्ट्रिंग


5

रूण कागार्ड ने एक महान और कॉम्पैक्ट समाधान प्रदान किया जो मेरे लिए काम करता है, मैंने इस पर थोड़ा विस्तार किया:

def urljoin(*args):
    trailing_slash = '/' if args[-1].endswith('/') else ''
    return "/".join(map(lambda x: str(x).strip('/'), args)) + trailing_slash

यह सभी तर्कों को पीछे छोड़ते हुए अंतिम स्लैश को संरक्षित करते हुए ट्रैशिंग और स्लैश की परवाह किए बिना शामिल होने की अनुमति देता है।


आप एक सूची समझ का उपयोग करके उस अंतिम पंक्ति को थोड़ा छोटा और अधिक पाइथोनिक बना सकते हैं, जैसे:return "/".join([str(x).strip("/") for x in args]) + trailing_slash
Dan Coates

3

एलेक्स मार्टेली की प्रतिक्रिया पर थोड़ा सुधार करने के लिए, निम्नलिखित न केवल अतिरिक्त स्लैश को साफ करेगा, बल्कि ट्रेलिंग (समाप्त) स्लैश को भी संरक्षित करेगा, जो कभी-कभी उपयोगी हो सकता है:

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

हालांकि यह पढ़ना उतना आसान नहीं है, और कई अतिरिक्त ट्रेलिंग स्लैश को साफ नहीं करेगा।


3

मुझे उपरोक्त सभी समाधानों के बारे में पसंद नहीं करने वाली चीजें मिलीं, इसलिए मैं अपने साथ आया। यह संस्करण सुनिश्चित करता है कि पुर्जे एक ही स्लैश के साथ जुड़ते हैं और अकेले स्लैश का नेतृत्व करते हैं। नहीं 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/'

0

फ़र्ल और रेगेक्स (पायथन 3) का उपयोग करना

>>> 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'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.