在Python中检查重复URL的最佳方法是什么?

时间:2012-03-24 06:28:10

标签: python web-crawler

我正在找出如何检查两个或多个url是否重复的最佳方法,如果他们有一些额外的参数,如下面的代码。在fac中,url1和url2是相同的,但是当运行webspider时,它将被视为两个单独的url,结果将被复制。

from urllib2 import urlopen
import hashlib

url1 = urlopen('http://www.time.com/time/nation/article/0,8599,2109975,00.html?xid=gonewssedit')
u1 = hashlib.md5(u1).hexdigest() 
url2 = urlopen('http://www.time.com/time/nation/article/0,8599,2109975,00.html')
u2 = hashlib.md5(u2).hexdigest() 
if u1 == u2:
    print 'yes'
else:
    print 'no'

简而言之,我将使用url标头生成md5哈希,然后将其存储在数据库中,然后当我抓取新url时,我可以检查它是否重复。但我不确定这是用Python工作的最好方法。

非常感谢

3 个答案:

答案 0 :(得分:3)

网页的结果可能相同或不同,具体取决于'额外参数'。因此,通常,您无法仅通过查看网址来定义检测重复内容的规则。

我建议将url1和url2视为不同。计算从网址收到的1024个单词的每个块的md5sum。维护这些md5sums的哈希映射,以便能够检测重复项。

可能有些web crawling tools可能会提供您需要的一些功能。


根据OP的评论更新:我写了一些代码来增强我的答案。有两个版本:第一个更简单:

def find_matches():
    """
        Basic version: reads urls, but does not consider the semantic information of
        HTML header, body, etc. while computing duplicates.
    """

    from urllib2 import urlopen
    import hashlib

    urls = [ 'http://www.google.com', 'http://www.google.com/search']

    d = {}
    url_contents = {}
    matches = []
    for url in urls:
        c = urlopen(url)
        url_contents[url] = []
        while 1:
            r = c.read(4096)
            if not r: break
            md5 = hashlib.md5(r).hexdigest()
            url_contents[url].append(md5)
            if md5 in d:
                url2 = d[md5]
                matches.append((md5, url, url2))
            else:
                d[md5] = []
            d[md5].append(url)
    #print url_contents
    print matches

if __name__ == '__main__':
    find_matches()

期望上面的代码以预期的方式检测重复项是天真的:当前的网页太复杂了。因此,即使两个与用户眼睛相同的网址实际上也会因广告,哈希标记,自我网址名称等而存在很多差异。

第二个版本更复杂。它引入了基于BeautifulSoup的内容的有限语义分析:

def find_matches():
    """
        Some consideration of the HTML header, body, etc. while computing duplicates.
    """

    from urllib2 import urlopen
    import hashlib
    from BeautifulSoup import BeautifulSoup
    import pprint

    urls = [ 'http://www.google.com', 'http://www.google.com/search'] # assuming all distinct urls

    def txt_md5(txt):
        return hashlib.md5(txt).hexdigest()

    MAX_FILE_SIZE = 1024*1024*1024 
    d = {}
    url_contents = {}
    matches = []
    for url in urls:
        try:
            c = urlopen(url)
            url_contents[url] = []
            r = c.read(MAX_FILE_SIZE)
            soup = BeautifulSoup(r)
            header = soup.find('head').text
            body = soup.find('body').text 
            # More fine-grained content options 
            # like h1, h2, p, etc., can be included.
            # Common CSS tags like page, content, etc.
            # can also be included.
            for h in [header, body]:
                print h
                md5 = txt_md5(h)
                url_contents[url].append((md5, h))
                if md5 in d:
                    url2 = d[md5]
                    matches.append((md5, url, url2))
                else:
                    d[md5] = []
                d[md5].append(url)
        except Exception as e:
            print "Exception", e
    print '---------------'
    #pprint.pprint(url_contents)
    print matches

if __name__ == '__main__':
    find_matches()

但是,第二个版本也不起作用。原因仍然相同。实际上,两个网址的头文本之间的差异是包含的哈希值,两个网址的正文之间的差异是字符串webhp。我使用difflib.context_diff来计算差异。

可以增强代码以包含第三个版本,该版本更智能地解析网页并更智能地计算差异。例如,即使是具有< 5%diff的文本也声明为重复(可以使用difflib函数轻松地计算该比率)。

答案 1 :(得分:1)

无法知道两个URI是否指向同一资源而不检索它们。即使它们基本上是相同的内容,它们也可能具有动态元素,例如广告随着每个请求而变化,从而难以以编程方式检测这两个URI是否相同。

答案 2 :(得分:0)

也许这样试试?

from urlparse import urlparse 

websites = set()

def is_unique(website):
    # Strip of the last bit
    parsed = urlparse(website)
    url = parsed.hostname + parsed.path
    if url in websites:
        return False
    websites.add(url)
    return True