我正在找出如何检查两个或多个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工作的最好方法。
非常感谢
答案 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