字典中的部分匹配

0 投票
4 回答
1269 浏览
提问于 2025-04-16 12:36

假设我有一个字典,这个字典把域名和它们的易懂描述对应起来。

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 个回答

1

看起来在Python 2.6的标准库里,urlparse.py这个文件在调用urlparse()函数的时候会做很多事情。我们可以通过写一个简单的URL解析器,只做最基本的事情,来加快速度。

更新:可以查看维基百科关于DNS的这一部分,了解域名的语法,这可能会给解析器一些灵感。

1

你可以利用一下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。

2

“对于大量操作来说太慢”是什么意思呢?其实每处理一个网址的时间是固定的,所以在这方面已经没有更好的办法了。上面的方法看起来是完全可行的。

如果你想让它快一点(不过不会快很多),你可以自己写一个正则表达式。比如说 "[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()

撰写回答