【问题标题】:How can I get the base of a URL in Python?如何在 Python 中获取 URL 的基础?
【发布时间】:2016-06-07 14:03:41
【问题描述】:

我正在尝试确定 URL 的基础,或者除页面和参数之外的所有内容。我尝试使用拆分,但有没有比将其拆分成块更好的方法?有没有办法可以从最后一个“/”中删除所有内容?

鉴于此: http://127.0.0.1/asdf/login.php

我想要: http://127.0.0.1/asdf/

【问题讨论】:

  • re.sub(r"[^/]*(\?.*)?$", "", x)
  • 这可能被视为作弊,但您可以使用os.path.dirname()。我不确定这是否适用于 Windows,但它适用于 Linux。
  • @zondo:我在 Windows 上,它肯定对我有用(在 Py 3.5.1 上)。
  • @ShadowRanger:我的想法不公平。 :( 我在乎什么?无论如何我都投了赞成票。
  • @zondo:我实际上是在您发表评论之前发布了我的答案。 :-) 此后我进行了编辑以添加一些替代项和说明(尽管没有显示编辑历史记录,奇怪),但这确实是我尝试的第一件事。我碰巧在 Windows 上确实有帮助,所以我可以很快确认它也可以在 Windows 上运行。

标签: python python-3.x


【解决方案1】:

同意最好的方法是使用urllib.parse

具体来说,你可以用urllib.parse.urlparse分解url,然后用空字符串替换除schemenetloc之外的所有属性。如果您想保留 path 属性(如您的问题),您可以通过额外的字符串解析步骤来实现。下面的示例函数:

import urllib.parse
def base_url(url, with_path=False):
    parsed = urllib.parse.urlparse(url)
    path   = '/'.join(parsed.path.split('/')[:-1]) if with_path else ''
    parsed = parsed._replace(path=path)
    parsed = parsed._replace(params='')
    parsed = parsed._replace(query='')
    parsed = parsed._replace(fragment='')
    return parsed.geturl()

例子:

>>> base_url('http://127.0.0.1/asdf/login.php', with_path=True)
'http://127.0.0.1/asdf'
>>> base_url('http://127.0.0.1/asdf/login.php')
'http://127.0.0.1'

【讨论】:

    【解决方案2】:

    当你使用 urlsplit 时,它会返回一个 SplitResult 对象:

    from urllib.parse import urlsplit
    split_url = urlsplit('http://127.0.0.1/asdf/login.php')
    print(split_url)
    
    >>> SplitResult(scheme='http' netloc='127.0.0.1' path='/asdf/login.php' query='' fragment='') 
    

    您可以创建自己的 SplitResult() 对象并通过 urlunsplit 传递它。只要你知道你想要的最后一个路径元素是什么,这段代码应该适用于多个 url 拆分,无论它们的长度如何。

    from urllib.parse import urlsplit, urlunsplit, SplitResult
    
    # splitting url:
    split_url = urlsplit('http://127.0.0.1/asdf/login.php')
    
    # editing the variables you want to change (in this case, path):    
    last_element = 'asdf'   # this can be any element in the path.
    path_array = split_url.path.split('/')
    
    # print(path_array)
    # >>> ['', 'asdf', 'login.php']
    
    path_array.remove('') 
    ind = path_array.index(last_element) 
    new_path = '/' + '/'.join(path_array[:ind+1]) + '/'
    
    # making SplitResult() object with edited data:
    new_url = SplitResult(scheme=split_url.scheme, netloc=split_url.netloc, path=new_path, query='', fragment='')
    
    # unsplitting:
    base_url = urlunsplit(new_url)
    

    【讨论】:

      【解决方案3】:

      使用 urllib 库的 Python3 有最短的解决方案(不知道是否最快):

      from urllib.parse import urljoin
      
      base_url = urljoin('http://127.0.0.1/asdf/login.php', '.')
      # output: http://127.0.0.1/asdf/
      

      请记住,urllib 库支持与 HTML 关键字兼容的 uri/url。这意味着以'/'结尾的uri / url意味着不同,没有像这里https://stackoverflow.com/a/1793282/7750840/

      base_url = urljoin('http://127.0.0.1/asdf/', '.')
      # output: http://127.0.0.1/asdf/
      
      base_url = urljoin('http://127.0.0.1/asdf', '.')
      # output: http://127.0.0.1/
      

      这是指向 python 的 urllib 的链接:https://pythonprogramming.net/urllib-tutorial-python-3/

      【讨论】:

        【解决方案4】:

        最好的方法是使用urllib.parse

        来自文档:

        该模块的设计符合 Internet RFC on Relative 统一资源定位器。它支持以下 URL 方案: file, ftp, gopher, hdl, http, https, imap, mailto, mms, nntp, @987654 prospero, rsync, rtsp, rtspu, sftp, shttp, sip, sips, snews, svn, svn+sshtelnetwaiswswss

        你想用urlspliturlunsplit 做这样的事情:

        from urllib.parse import urlsplit, urlunsplit
        
        split_url = urlsplit('http://127.0.0.1/asdf/login.php?q=abc#stackoverflow')
        
        # You now have:
        # split_url.scheme   "http"
        # split_url.netloc   "127.0.0.1" 
        # split_url.path     "/asdf/login.php"
        # split_url.query    "q=abc"
        # split_url.fragment "stackoverflow"
        
        # Use all the path except everything after the last '/' 
        clean_path = "".join(split_url.path.rpartition("/")[:-1])
        
        # "/asdf/"
        
        # urlunsplit joins a urlsplit tuple
        clean_url = urlunsplit(split_url)
        
        # "http://127.0.0.1/asdf/login.php?q=abc#stackoverflow"
        
        
        # A more advanced example 
        advanced_split_url = urlsplit('http://foo:bar@127.0.0.1:5000/asdf/login.php?q=abc#stackoverflow')
        
        # You now have *in addition* to the above:
        # advanced_split_url.username   "foo"
        # advanced_split_url.password   "bar"
        # advanced_split_url.hostname   "127.0.0.1"
        # advanced_split_url.port       "5000"
        

        【讨论】:

        • 您的拆分和重新加入可能应该使用'/'.join,否则您将去掉所有的斜线。另一种更聪明的方法可能是"".join(split_url.rpartition('/')[:-1],它只执行一次拆分,如果不存在斜线,则实际上变成了noop。
        • 很棒的提示ShadowRanger,我一直想知道您是否可以这样做,但从未想过要看看。恭喜你得到答案;)
        • 这应该是答案,主题和详尽的解释!
        【解决方案5】:

        如果你使用python3,你可以使用urlparse和urlunparse。

        In :from urllib.parse import urlparse, urlunparse
        
        In :url = "http://127.0.0.1/asdf/login.php"
        
        In :result = urlparse(url)
        
        In :new = list(result)
        
        In :new[2] = new[2].replace("login.php", "")
        
        In :urlunparse(new)
        Out:'http://127.0.0.1/asdf/'
        

        【讨论】:

          【解决方案6】:

          不需要使用正则表达式,你可以使用rsplit()

          >>> url = 'http://127.0.0.1/asdf/login.php'
          >>> url.rsplit('/', 1)[0]
          'http://127.0.0.1/asdf'
          

          【讨论】:

            【解决方案7】:

            获取最右边的斜线;使用字符串切片在原始字符串中的那个位置。 +1 让你得到最后的斜线。

            link = "http://127.0.0.1/asdf/login.php"
            link[:link.rfind('/')+1]
            

            【讨论】:

            • 使用rindex 可能更好;否则,如果您有一个没有斜杠的字符串,您将默默地返回空字符串(因为rfind 将返回 -1,您将添加 1,然后从 0 切片到 0)。至少使用rindex,你会得到一个异常,而不是继续直到有一个空字符串导致一切都崩溃。
            【解决方案8】:

            好吧,首先,你可以使用os.path.dirname

            >>> os.path.dirname('http://127.0.0.1/asdf/login.php')
            'http://127.0.0.1/asdf'
            

            它没有明确用于 URL,但它恰好适用于它们(即使在 Windows 上),它只是不会留下尾部斜杠(你可以自己添加回来)。

            您可能还想查看urllib.parse.urlparse 以获得更细粒度的解析;如果 URL 涉及查询字符串或哈希,您需要将其解析为多个片段,修剪解析返回的 path 组件,然后重新组合,以便修剪路径而不会丢失查询和哈希信息。

            最后,如果您只想在最后一个斜线之后拆分组件,您可以使用maxsplit1 执行rsplit,并保留第一个组件:

            >>> 'http://127.0.0.1/asdf/login.php'.rsplit('/', 1)[0]
            'http://127.0.0.1/asdf'
            

            【讨论】:

            • 你知道为什么os.path.dirname 也能很好地处理 URL 吗?
            • @dalanmiller:因为它们使用相同的分隔符。即使在 Windows 上,正斜杠也是合法的路径分隔符(只是 Windows 优先使用反斜杠),因此路径操作 API 旨在处理任何地方的正斜杠,并且 URL 以相同的方式使用它们。
            • 鉴于问题与 URL 有关,我会说 urllib.parse 应该是推荐使用的 stdlib 部分。
            • 确实,有一个优点...... URL 以及对它们的支持可能会相互一致地变化,而对新 URL 特性的支持(如果有的话)可能不会添加到文件处理功能中就像从那以后可能变得不必要的复杂性一样。虽然我个人仍然喜欢稍微生硬的解决方案,并通过几种方法整理出许多事情;)
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-11-24
            • 1970-01-01
            • 1970-01-01
            • 2012-09-04
            • 2013-03-08
            • 1970-01-01
            相关资源
            最近更新 更多