【问题标题】:How can I prepend the 'http://' protocol to a url when necessary? [duplicate]必要时如何将“http://”协议添加到 url? [复制]
【发布时间】:2011-09-14 18:11:12
【问题描述】:

我需要解析一个 URL。我目前正在使用 urlparse.urlparse() 和 urlparse.urlsplit()。

问题是当它不存在方案时,我无法从 URL 获取“netloc”(主机)。 我的意思是,如果我有以下网址:

www.amazon.com/Programming-Python-Mark-Lutz/dp/0596158106/ref=sr_1_1?ie=UTF8&qid=1308060974&sr=8-1

我无法获取 netloc:www.amazon.com

根据 python 文档:

遵循语法规范 RFC 1808,urlparse 识别 netloc 只有当它被正确地引入 '//'。否则假定输入 成为一个相对 URL 并因此开始 带有路径组件。

所以,这是故意的。但是,我仍然不知道如何从该 URL 获取 netloc。

我想我可以检查该方案是否存在,如果不存在,则添加它,然后解析它。但这个解决方案似乎不太好。

你有更好的主意吗?

编辑: 感谢所有的答案。但是,我不能做 Corey 和其他人提出的“startswith”事情。因为,如果我得到一个带有其他协议/方案的 URL,我会把它搞砸。见:

如果我得到这个网址:

ftp://something.com

使用建议的代码,我会在开头添加“http://”,然后会搞砸。

我找到的解决方案

if not urlparse.urlparse(url).scheme:
   url = "http://"+url
return urlparse.urlparse(url)

注意事项:

我先做一些验证,如果没有给出方案,我认为它是 http://

【问题讨论】:

  • 这是因为 URL 的协议部分 - http:// - 丢失了吗?
  • 是的,就是这个原因。但是,如果计划仍然缺失,我怎么能得到它?
  • 在您的解决方案中,我仍然会检查前导 //(可能只是 /),因为正确的 url 会包含它(即使缺少方案)
  • @TokenMacGuy 我这样做。它在“验证”部分。值得一提。检查史蒂夫的答案。
  • 现在,如果您在解决方案中提供了自我回答,您也可能会为此获得一些支持。 (或者您是否希望其他人发布您的答案,或者完全是其他内容?)

标签: python url url-parsing urlparse


【解决方案1】:

看来您需要指定协议才能获取 netloc。

如果它不存在,则添加它可能如下所示:

import urlparse

url = 'www.amazon.com/Programming-Python-Mark-Lutz'
if '//' not in url:
    url = '%s%s' % ('http://', url)
p = urlparse.urlparse(url)
print p.netloc

关于该问题的更多信息:https://bugs.python.org/issue754016

【讨论】:

    【解决方案2】:

    文档中有这个确切的示例,就在您粘贴的文本下方。添加'//'如果它不存在将得到你想要的。如果你不知道它是否会有协议和'//',你可以使用正则表达式(或者甚至只是看看它是否已经包含'//')来确定你是否需要添加它。

    您的另一个选择是使用 split('/') 并获取它返回的列表的第一个元素,这仅在 url 没有协议或 '//' 时才有效。

    编辑(为未来的读者添加):用于检测协议的正则表达式类似于re.match('(?:http|ftp|https)://', url)

    【讨论】:

    • 我仍然有不同的协议问题(请参阅对 Bryan 回答的评论)。谢谢
    • 然后你可以使用正则表达式 - 检查 (?:http|ftp|etc):// - 或者只检查字符串中是否存在 '://'。这取决于您希望它有多强大;完整的 URL 解析很复杂。
    • +1 你是对的 SteveMc。什么会更快?用您发布的协议列表或我提出的 urlparse 解析它?
    • urlparse 可能(虽然我没有看过)使用正则表达式进行解析(因为正如我所说,它很复杂)但是你这样做的方式似乎非常合理,所以我会离开它正如你所做的那样。如果您好奇,可以对其进行分析。
    • 感谢史蒂夫的回答。我做了类似的事情。评论中的正则表达式非常好。您应该将其添加到未来读者的回答中。
    【解决方案3】:

    如果协议是总是http,你只能使用一行:

    return "http://" + url.split("://")[-1]
    

    更好的选择是在协议通过时使用

    return url if "://" in url else "http://" + url
    

    【讨论】:

    • 你的意思是return url if "://" in url else "http://" + url
    • 感谢 Robert Dodd 的错误报告。
    【解决方案4】:

    来自文档:

    遵循 RFC 1808 中的语法规范,urlparse 仅当 netloc 由“//”正确引入时才识别它。否则,输入被假定为相对 URL,因此以路径组件开头。

    所以你可以这样做:

    In [1]: from urlparse import urlparse
    
    In [2]: def get_netloc(u):
       ...:     if not u.startswith('http'):
       ...:         u = '//' + u
       ...:     return urlparse(u).netloc
       ...: 
    
    In [3]: get_netloc('www.amazon.com/Programming-Python-Mark-Lutz/dp/0596158106/ref=sr_1_1?ie=UTF8&qid=1308060974&sr=8-1')
    Out[3]: 'www.amazon.com'
    
    In [4]: get_netloc('http://www.amazon.com/Programming-Python-Mark-Lutz/dp/0596158106/ref=sr_1_1?ie=UTF8&qid=1308060974&sr=8-1')
    Out[4]: 'www.amazon.com'
    
    In [5]: get_netloc('https://www.amazon.com/Programming-Python-Mark-Lutz/dp/0596158106/ref=sr_1_1?ie=UTF8&qid=1308060974&sr=8-1')
    Out[5]: 'www.amazon.com'
    

    【讨论】:

      【解决方案5】:

      您是否考虑过只检查网址开头是否存在“http://”,如果不存在则添加它?另一种解决方案,假设第一部分确实是 netloc 而不是相对 url 的一部分,是只抓取第一个“/”之前的所有内容并将其用作 netloc。

      【讨论】:

      • 是的,这就是我现在正在做的事情。但是不太喜欢。如果没有更好的情况出现,我会坚持下去。谢谢!
      • 我还有一个问题。如果使用其他协议/方案怎么办?如果我在此 URL 中检查 http://:“ftp://my.home.com”,那么我会认为它不存在。如果我添加它,我会搞砸的
      【解决方案6】:

      这一个班轮可以做到。

      netloc = urlparse('//' + ''.join(urlparse(url)[1:])).netloc
      

      【讨论】:

        猜你喜欢
        • 2014-08-30
        • 2015-07-31
        • 1970-01-01
        • 1970-01-01
        • 2020-05-08
        • 1970-01-01
        • 2012-12-12
        • 1970-01-01
        • 2020-04-16
        相关资源
        最近更新 更多