从 URL 获取协议 + 主机名

Posted

技术标签:

【中文标题】从 URL 获取协议 + 主机名【英文标题】:Get protocol + host name from URL 【发布时间】:2012-03-26 11:02:16 【问题描述】:

在我的 Django 应用程序中,我需要从 request.META.get('HTTP_REFERER') 中的引用者那里获取主机名及其协议,以便从以下 URL 获取:

https://docs.google.com/spreadsheet/ccc?key=blah-blah-blah-blah#gid=1 https://***.com/questions/1234567/blah-blah-blah-blah http://www.example.com https://www.other-domain.com/whatever/blah/blah/?v1=0&v2=blah+blah ...

我应该得到:

https://docs.google.com/ https://***.com/ http://www.example.com https://www.other-domain.com/

我查看了其他相关问题并找到了有关 urlparse 的信息,但此后并没有解决问题

>>> urlparse(request.META.get('HTTP_REFERER')).hostname
'docs.google.com'

【问题讨论】:

【参考方案1】:

您应该可以使用urlparse(文档:python2、python3):

from urllib.parse import urlparse
# from urlparse import urlparse  # Python 2
parsed_uri = urlparse('http://***.com/questions/1234567/blah-blah-blah-blah' )
result = 'uri.scheme://uri.netloc/'.format(uri=parsed_uri)
print(result)

# gives
'http://***.com/'

【讨论】:

这个答案添加一个/到第三个例子http://www.domain.com,但我认为这可能是问题的一个缺点,而不是答案。 @TokenMacGuy:是的,我的错...没有注意到丢失的 / 我认为这不是一个好的解决方案,因为netloc 不是域:尝试urlparse.urlparse('http://user:pass@example.com:8080') 并发现它提供了'user:pass@'':8080' 之类的部分 urlparse 模块在 Python 3 中被重命名为 urllib.parse。所以,from urllib.parse import urlparse 这回答了作者的意思,而不是实际陈述的内容。对于那些寻找域名而不是主机名的人(如本解决方案提供的那样),我建议查看 dm03514 目前在下面的答案。 Python 的 urlparse 不能给你域名。这似乎是一个疏忽。【参考方案2】:

https://github.com/john-kurkowski/tldextract

这是一个更详细的 urlparse 版本。它会为您检测域和子域。

来自他们的文档:

>>> import tldextract
>>> tldextract.extract('http://forums.news.cnn.com/')
ExtractResult(subdomain='forums.news', domain='cnn', suffix='com')
>>> tldextract.extract('http://forums.bbc.co.uk/') # United Kingdom
ExtractResult(subdomain='forums', domain='bbc', suffix='co.uk')
>>> tldextract.extract('http://www.worldbank.org.kg/') # Kyrgyzstan
ExtractResult(subdomain='www', domain='worldbank', suffix='org.kg')

ExtractResult 是一个命名元组,所以很容易访问你想要的部分。

>>> ext = tldextract.extract('http://forums.bbc.co.uk')
>>> ext.domain
'bbc'
>>> '.'.join(ext[:2]) # rejoin subdomain and domain
'forums.bbc'

【讨论】:

这是所写问题的正确答案,如何获取域名。选择的解决方案提供了 HOSTNAME,我相信这是作者首先想要的。【参考方案3】:

Python3 使用urlsplit:

from urllib.parse import urlsplit
url = "http://***.com/questions/9626535/get-domain-name-from-url"
base_url = "0.scheme://0.netloc/".format(urlsplit(url))
print(base_url)
# http://***.com/

【讨论】:

【参考方案4】:
>>> import urlparse
>>> url = 'http://***.com/questions/1234567/blah-blah-blah-blah'
>>> urlparse.urljoin(url, '/')
'http://***.com/'

【讨论】:

对于 Python 3,导入为 from urllib.parse import urlparse【参考方案5】:

纯字符串操作:):

>>> url = "http://***.com/questions/9626535/get-domain-name-from-url"
>>> url.split("//")[-1].split("/")[0].split('?')[0]
'***.com'
>>> url = "***.com/questions/9626535/get-domain-name-from-url"
>>> url.split("//")[-1].split("/")[0].split('?')[0]
'***.com'
>>> url = "http://foo.bar?haha/whatever"
>>> url.split("//")[-1].split("/")[0].split('?')[0]
'foo.bar'

就是这样,伙计们。

【讨论】:

不错且简单的选项,但在某些情况下会失败,例如foo.bar?haha @SimonSteinberger :-) 这个怎么样:url.split("//")[-1].split("/")[0].split('?')[0] :-))【参考方案6】:

标准库函数urllib.parse.urlsplit() 就是您所需要的。以下是 Python3 的示例:

>>> import urllib.parse
>>> o = urllib.parse.urlsplit('https://user:pass@www.example.com:8080/dir/page.html?q1=test&q2=a2#anchor1')
>>> o.scheme
'https'
>>> o.netloc
'user:pass@www.example.com:8080'
>>> o.hostname
'www.example.com'
>>> o.port
8080
>>> o.path
'/dir/page.html'
>>> o.query
'q1=test&q2=a2'
>>> o.fragment
'anchor1'
>>> o.username
'user'
>>> o.password
'pass'

【讨论】:

【参考方案7】:

如果您认为您的网址有效,那么这将一直有效

domain = "http://google.com".split("://")[1].split("/")[0] 

【讨论】:

最后一个split是错误的,没有更多的正斜杠可以分割。 不会有问题,如果没有更多的斜线,列表将返回一个元素。所以无论有没有斜线它都会起作用 我编辑了您的答案,以便能够删除反对票。很好的解释。谢了。【参考方案8】:

这是一个稍微改进的版本:

urls = [
    "http://***.com:8080/some/folder?test=/questions/9626535/get-domain-name-from-url",
    "***.com:8080/some/folder?test=/questions/9626535/get-domain-name-from-url",
    "http://***.com/some/folder?test=/questions/9626535/get-domain-name-from-url",
    "https://***.com:8080?test=/questions/9626535/get-domain-name-from-url",
    "***.com?test=questions&v=get-domain-name-from-url"]
for url in urls:
    spltAr = url.split("://");
    i = (0,1)[len(spltAr)>1];
    dm = spltAr[i].split("?")[0].split('/')[0].split(':')[0].lower();
    print dm

输出

***.com
***.com
***.com
***.com
***.com

小提琴:https://pyfiddle.io/fiddle/23e4976e-88d2-4757-993e-532aa41b7bf0/?i=true

【讨论】:

恕我直言最好的解决方案,因为它很简单,而且它考虑了各种罕见的情况。谢谢! 既不简单也不改进 这不是问题的解决方案,因为您没有提供协议(https:// 或 http://)【参考方案9】:

纯字符串操作有什么问题吗:

url = 'http://***.com/questions/9626535/get-domain-name-from-url'
parts = url.split('//', 1)
print parts[0]+'//'+parts[1].split('/', 1)[0]
>>> http://***.com

如果您更喜欢附加斜杠,请扩展此脚本,如下所示:

parts = url.split('//', 1)
base = parts[0]+'//'+parts[1].split('/', 1)[0]
print base + (len(url) > len(base) and url[len(base)]=='/'and'/' or '')

这大概可以优化一下...

【讨论】:

没有错,但我们有一个已经完成工作的工具,我们不要重新发明***;)【参考方案10】:

这有点迟钝,但在两个方向上都使用urlparse

import urlparse
def uri2schemehostname(uri):
    urlparse.urlunparse(urlparse.urlparse(uri)[:2] + ("",) * 4)

那个奇怪的 ("",) * 4 位是因为 urlparse 需要 完全 len(urlparse.ParseResult._fields) = 6

的序列

【讨论】:

【参考方案11】:

我知道这是一个老问题,但我今天也遇到了。 用单线解决了这个问题:

import re
result = re.sub(r'(.*://)?([^/?]+).*', '\g<1>\g<2>', url)

【讨论】:

【参考方案12】:

您可以简单地使用带有相对根“/”作为第二个参数的 urljoin:

import urllib.parse


url = 'https://***.com/questions/9626535/get-protocol-host-name-from-url'
root_url = urllib.parse.urljoin(url, '/')
print(root_url)

【讨论】:

【参考方案13】:

可以通过re.search()解决

import re
url = 'https://docs.google.com/spreadsheet/ccc?key=blah-blah-blah-blah#gid=1'
result = re.search(r'^http[s]*:\/\/[\w\.]*', url).group()
print(result)

#result
'https://docs.google.com'

【讨论】:

【参考方案14】:

获取域/主​​机名和来源*

url = 'https://***.com/questions/9626535/get-protocol-host-name-from-url'
hostname = url.split('/')[2] # ***.com
origin = '/'.join(url.split('/')[:3]) # https://***.com

*Origin 用于XMLHttpRequest 标头

【讨论】:

【参考方案15】:

这是获取任何域的根 URL 的简单方法。

from urllib.parse import urlparse

url = urlparse('https://***.com/questions/9626535/')
root_url = url.scheme + '://' + url.hostname
print(root_url) # https://***.com

【讨论】:

【参考方案16】:

如果它包含少于 3 个斜线,那么你就有了,如果没有,那么我们可以找到它之间的出现:

import re

link = http://forum.unisoftdev.com/something

slash_count = len(re.findall("/", link))
print slash_count # output: 3

if slash_count > 2:
   regex = r'\:\/\/(.*?)\/'
   pattern  = re.compile(regex)
   path = re.findall(pattern, url)

   print path

【讨论】:

以上是关于从 URL 获取协议 + 主机名的主要内容,如果未能解决你的问题,请参考以下文章

获取当前页面的url

python 如何获取url信息

获取当前 url 主机名 NODE

如何获取网页的url

如何解析 Postgresql JDBC url 以获取主机名、端口和 db_name

网络编程