字典中的部分匹配

时间:2011-02-27 01:25:58

标签: python url dictionary

假设我有以下字典映射域名到它的人类可读描述

domain_info = {"google.com" : "A Search Engine", 
               "facebook.com" : "A Social Networking Site", 
               "stackoverflow.com" : "Q&A Site for Programmers"}

我想从response.url获取描述,该描述返回绝对路径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 个答案:

答案 0 :(得分:2)

“大量操作太慢”是什么意思?它仍然会在恒定的时间内工作(对于每个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()应用于域。

答案 1 :(得分:1)

似乎Python 2.6标准库中的urlparse.py在调用urlparse()函数时会做很多事情。有可能通过编写一个小的URL解析器来加快速度,这个解析器只执行绝对必要的操作,而不是更多。

更新:有关域名语法的信息,请参阅this part of Wikipedia's page about DNS,它可能会为解析器提供一些想法。

答案 2 :(得分:1)

您可以考虑使用正则表达式提取没有子域的域:

'http:\/\/([^\.]+\.)*([^\.][a-zA-Z0-9\-]+\.[a-zA-Z]{2,6})(\/?|\/.*)'

import re
m = re.search('http:\/\/([^\.]+\.)*([^\.][a-zA-Z0-9\-]+\.[a-zA-Z]{2,6})(\/?|\/.*)', 'http://www.google.com/asd?#a')
print m.group(2)

答案 3 :(得分: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]

缓存lib的相同之处:

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 )

也许它有点帮助,但它实际上取决于你拥有的各种网址。

相关问题