Лучший способ проверить дублированный URL в Python? - PullRequest
1 голос
/ 24 марта 2012

Я придумываю лучший способ проверить, дублируются ли два или более URL-адреса в случае, если у них есть некоторые дополнительные параметры, такие как код ниже. На самом деле url1 и url2 одинаковы, но при запуске веб-паука он будет обрабатываться как два отдельных 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'

Короче говоря, я сгенерирую хеш md5 с помощью заголовка url, затем сохраню его в базе данных, затем при сканировании нового URL я могу проверить, дублирован ли он или нет. Но я не уверен, что это лучший способ для этой работы в Python.

Большое спасибо

Ответы [ 3 ]

3 голосов
/ 24 марта 2012

Результат веб-страницы может быть одинаковым или различным в зависимости от «дополнительных параметров».Таким образом, в общем, вы не можете определить правила, которые обнаруживают дублирующийся контент, только посмотрев на URL.

Я бы посоветовал рассматривать url1 и url2 как разные. Вычислить md5 для каждого блока, скажем, 1024 слова, полученных из URL.Сохраните хэш-карту этих md5sums, чтобы иметь возможность обнаруживать дубликаты.

Вероятно, некоторые инструменты веб-сканирования могут предлагать некоторые необходимые функции.


Обновлениеосновываясь на комментариях ОП: я написал некоторый код для улучшения своего ответа.Существует две версии: первая проще:

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()

Было бы наивно ожидать, что приведенный выше код обнаружит дубликаты ожидаемым образом: текущие веб-страницы слишком сложны.Следовательно, даже два URL-адреса, которые являются одинаковыми для пользователя, на самом деле имеют много различий из-за рекламы, хэш-тегов, включения имени собственного URL и т. Д.

Вторая версия более сложна.Он вводит ограниченный семантический анализ контента на основе 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()

Однако вторая версия тоже не работает.Причина остается той же.Действительно, разница между текстами заголовков двух URL-адресов была включенным значением хеш-функции, а разница между текстами основного текста двух URL-адресов представляла собой строку webhp.Я использовал difflib.context_diff для вычисления разницы.

Можно усовершенствовать код, включив в него третью версию, которая более интеллектуально анализирует веб-страницы и более разумно вычисляет различия.Например, объявление в качестве дубликатов даже текстов с разницей <5% (это соотношение может быть легко вычислено с использованием функции difflib).</p>

1 голос
/ 24 марта 2012

Нет способа узнать, указывают ли два URI на один и тот же ресурс без извлечения их обоих.И даже если они в основном имеют одинаковое содержимое, они могут содержать динамические элементы, такие как реклама, которые в любом случае меняются при каждом запросе, что затрудняет программное определение одинаковых двух URI.

0 голосов
/ 24 марта 2012

Может, попробуем так?

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...