字典中的部分匹配
假设我有一个字典,这个字典把域名和它们的易懂描述对应起来。
domain_info = {"google.com" : "A Search Engine",
"facebook.com" : "A Social Networking Site",
"stackoverflow.com" : "Q&A Site for Programmers"}
我想从一个返回绝对路径的链接中获取描述,比如这个链接 http://www.google.com/reader/view/
。
我现在的做法是:
url = urlparse.urlparse(response.url)
domain = url.netloc # 'www.google.com'
domain = domain.split(".") # ['www', 'google', 'com']
domain = domain[-2:] # ['google', 'com']
domain = ".".join(domain) # 'google.com'
info = domain_info[domain]
但是这种方法在调用次数很多的时候似乎太慢了,有没有人能建议一个更快的办法呢?
理想的解决方案应该能够处理任何子域名,并且不区分大小写。
4 个回答
看起来在Python 2.6的标准库里,urlparse.py这个文件在调用urlparse()函数的时候会做很多事情。我们可以通过写一个简单的URL解析器,只做最基本的事情,来加快速度。
更新:可以查看维基百科关于DNS的这一部分,了解域名的语法,这可能会给解析器一些灵感。
你可以利用一下urlparse这个工具的功能。试着直接用它返回的netloc
来查找东西,如果实在不行再用分割和连接的方法:
def normalize( domain ):
domain = domain.split(".") # ['www', 'google', 'com']
domain = domain[-2:] # ['google', 'com']
return ".".join(domain) # 'google.com'
# caches the netlocs that are not "normal"
aliases = {}
def getinfo( url ):
netloc = urlparse.urlparse(response.url).netloc
if netloc in aliases:
return domain_info[aliases[netloc]]
if netloc in domain_info:
return domain_info[netloc]
main = normalize(netloc)
if main in domain_info:
aliases[netloc] = main
return domain_info[netloc]
用缓存库也是一样的道理:
from beaker.cache import CacheManager
netlocs = CacheManager(namespace='netloc')
@netlocs.cache()
def getloc( domain ):
try:
return domain_info[domain]
except KeyError:
domain = domain.split(".")
domain = domain[-2:]
domain = ".".join(domain)
return domain_info[domain]
def getinfo( url ):
netloc = urlparse.urlparse(response.url).netloc
return getloc( netloc )
这可能会有一点帮助,但其实还是要看你有多少种不同的url。
“对于大量操作来说太慢”是什么意思呢?其实每处理一个网址的时间是固定的,所以在这方面已经没有更好的办法了。上面的方法看起来是完全可行的。
如果你想让它快一点(不过不会快很多),你可以自己写一个正则表达式。比如说 "[a-zA-Z]+://([a-zA-Z0-9.]+)"
。这个可以获取完整的域名,而不是子域名。不过你还是需要分割域名,除非你能在正则表达式中使用前瞻功能来只获取最后两个部分。记得用 re.compile
来加快正则表达式的速度。
需要注意的是,使用 domain[-2]
可能不是你想要的结果。找出合适的“公司级域名”的逻辑其实挺复杂的。比如,如果域名是 google.com.au,这样会得到“com.au”,这可能不是你想要的结果——你可能更想要“google.com.au”。
正如你所说,理想的解决方案应该能处理任何子域名,所以你可能需要遍历所有的分割结果。
url = urlparse.urlparse(response.url)
domain = url.netloc # 'www.google.com'
domain = domain.split(".") # ['www', 'google', 'com']
info = None
for i in range(len(domain)):
subdomain = ".".join(domain[i:]) # 'www.google.com', 'google.com', 'com'
try:
info = domain_info[subdomain]
break
except KeyError:
pass
使用上面的代码,你可以找到任何匹配的子域名。至于大小写问题,这很简单。确保字典里的所有键都是小写,并在其他处理之前对域名使用 .lower()
。