从字符串或URL解析主机名和端口

30

我可以接收以下任意一种格式的字符串:

我想提取主机名和若存在则提取端口号。如果没有端口号,则默认为80。

我尝试使用urlparse,它对于URL格式的字符串可以正常工作,但无法处理其他格式。例如,在hostname:port上使用urlparse时,它将主机名放在协议中而非网络位置。

我希望有一个解决方案能够同时使用urlparse和正则表达式,或者只使用一个正则表达式来处理这两种格式的字符串。


你尝试过正则表达式吗?如果没有用正则表达式,你写的是什么代码? - dejjub-AIS
5个回答

54

您可以使用urlparse从URL字符串中获取主机名:

from urlparse import urlparse
print urlparse("http://www.website.com/abc/xyz.html").hostname # prints www.website.com

12
在Python3中使用:import urlliburllib.parse.urlparse('http://....') - user1156544

18
>>> from urlparse import urlparse   
>>> aaa = urlparse('http://www.acme.com:456')

>>> aaa.hostname  
'www.acme.com'

>>> aaa.port   
456
>>> 

我不知道为什么,但是当你运行aaa = urlparse('www.acme.com:456')时,aaa.hostname的值是None,你知道为什么吗?顺便说一下,这正是问题所问的。 - Rodrigo Laguna
2
@RodrigoLaguna 真的很晚才来参加派对,但这个问题仍然没有解决。urlparse('www.acme.com:456')urlparse('http://www.acme.com:456')之间存在差异。根据文档,urlparse假定一个符合RFC1808标准的URL,并且除非使用“//”引入网络位置,否则无法正确识别网络位置- https://docs.python.org/2/library/urlparse.html#urlparse.urlparse。 - ymbirtt
1
根据@user1156544的建议,在Python3中使用:import urllib和urllib.parse.urlparse('http://....')。 - VoteCoffee

8

我对urlparse并不是很熟悉,但是使用正则表达式,你可以做如下操作:

p = '(?:http.*://)?(?P<host>[^:/ ]+).?(?P<port>[0-9]*).*'

m = re.search(p,'http://www.abc.com:123/test')
m.group('host') # 'www.abc.com'
m.group('port') # '123'

或者,不需要指定端口号:

m = re.search(p,'http://www.abc.com/test')
m.group('host') # 'www.abc.com'
m.group('port') # '' i.e. you'll have to treat this as '80'

编辑:修正正则表达式以匹配'www.abc.com 123'


2
我认为这些负评是因为这个解决方案过于复杂了。我接受这一点,并同意@ntziolis的观点,即在可能的情况下应尽量使用标准功能。 - claesv
标准的urlparse不能处理字符串(不以http(s)或//开头),因此这个解决方案似乎很有帮助。为什么不解释就点踩呢? - James
2
这对于带有字面IPv6地址的URL(例如http://[2001:db8:85a3::8a2e:370:7334]:80/test)会失败。 - Anders Kaseorg

6

它失败的原因是:

www.acme.com 456

这是因为它不是一个有效的URI。您可以尝试以下操作:
  1. 将空格替换为:
  2. 使用标准的urlparse方法解析结果字符串。
尽可能利用默认功能,特别是在解析诸如URI等众所周知格式时。

4
使用urlparse对host:port进行解析时,它会将主机名放在scheme中而不是netloc中。 - TonyM
2
从手册中: "遵循RFC 1808中的语法规范,urlparse仅在其由'//'正确引入时才识别netloc。否则,输入被认为是相对URL,因此以路径组件开头。" - ntziolis
2
我并不是说这种方式是错的,但它似乎不是处理主机名:端口格式的最佳方式。而且添加前缀也不太优雅。 - TonyM
2
基本上可以归结为以下两点:1. 在解析之前是否进行规范化(使用标准函数),或者2. 尝试使用正则表达式或类似的方法来处理解析时的不同格式。根据我的经验,最好进行规范化,因为正则表达式的解决方案很容易出错,而且你正在复制现有的功能。 - ntziolis
目前,我打算在URL上使用urlparse,在主机名:端口格式上使用@claesv的正则表达式。 - TonyM

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接