3

我构建/扩展了一个 Python 网络爬虫,它通过一个站点并构建一个字典来存储它找到的内容(如果有人感兴趣,这是我使用的模板,它非常好:http ://berrytutorials.blogspot.ca/2010/03 /simple-web-crawler-in-python-using.html)。字典比这多一点,但就这个问题而言,单个项目本质上是 form {page_url : html},其中 html 是字符串形式的页面的整个 html。

爬虫被构建为不会两次索引同一页面,但模板作者指出的一个潜在问题很容易出现,因为 url 参数不同,爬虫将相同的页面识别为不同的页面。例如,www.example.com/path?param=1 和 www.example.com/path?param=2 都将被添加到字典中,因为 url 在技术上是不同的,即使每个页面的内容可能相同,或几乎相同。我能想到解决这个问题的唯一方法是在抓取完成后将存储在字典中的大量 html 字符串相互比较,看看是否有任何匹配 - 基本上只是

    if html_str_1 == html_str_2:
        # eliminate one of them

对于每一个可能的配对。但显然这将非常耗费资源和时间。

有谁知道更好的方法来实现这一点?我还希望能够检测到几乎相同的 html,这些 html 可能仅相差几个微不足道的字符。我是 Python 新手,所以我对那里的各种库不是很熟悉。也许 BeautifulSoup 可以做这样的事情?

(注意:我知道对于我给出的示例,我可以在分析它们之前从 url 中解析出任何参数,但这只是重复 html 的一个可能原因,我想涵盖所有内容。此外,不同的参数可能会导致截然不同某些情况下的页面。)

4

4 回答 4

2

创建 HTML 的哈希值并进行比较。我会推荐hashlib.sha512()

In [1]: from hashlib import sha512

In [2]: html = '<p>This is a test</p>'

In [3]: sha512(html).digest()
Out[3]: '\xb4\xda\xc2\xcb\x16\xd3\\\xa1F\x8a\\\xe5-z\xc6\xd1\xf95\x0f\x13\xf6k\xb4\xfd\xb9I\xde\xf0\x8dQ\xff\xdb\x9d\xa2\x0f\x1b\x8al\xfe\xac\xce\xe4n*\xd3\xd8M\xf3E\x05\xc6\xc9\xeejV8\xf8\x9a:\x86|q\x1f\x1c'

您还应该更改字典以存储哈希;

{page_url : (hash, html)}

编辑:散列非常快。我创建了一个 10MB 的随机数据文件:

dd if=/dev/random of=random.dat bs=1M count=10

阅读并散列它:

In [6]: with open('random.dat') as infile:
    data = infile.read()
   ...:     

In [7]: %timeit sha512(data).digest()
10 loops, best of 3: 61.5 ms per loop

所以你可以在大约 60 毫秒内散列 10MB。

MD5 散列的速度是原来的两倍;

In [4]: %timeit md5(data).digest()
10 loops, best of 3: 24.1 ms per loop

不过,发生冲突(两个不同的文本产生相同的哈希值)的可能性要大一些。

于 2013-03-31T18:20:23.937 回答
2

使用 md5 之类的东西对 HTML 进行哈希处理,然后使用两个字典:一个将 URL 映射到内容哈希,另一个将内容哈希映射到实际内容。例如,而不是:

dict1[ url ] = html

采用:

import md5

h = md5.new()
h.update(html)
k = h.hexdigest()
dict1[ url ] = k
dict2[ k ] = html

这样,相同的页面将只存储一次。

于 2013-03-31T18:21:25.413 回答
2

散列是要走的路。我会选择 MD5,因为它速度很快——这对于加密目的来说是一个缺点,但是使用昂贵的哈希(如 SHA512)进行索引只会浪费你的周期。

由于网页通常包含基于其自己的请求选项的链接(如您的示例中),并且可能是显示获取时间的时间戳,因此您需要在散列它们之前清理/规范化获取的页面。删除您认为在相同页面之间可能会有所不同的任何内容,对结果进行散列,并将其用作字典键。这样,您可以检查一个新页面是否在名义上 O(1) 时间内已知散列 - 由 python 的 dict 管理提供。

于 2013-03-31T18:30:01.680 回答
1

有谁知道更好的方法来实现这一点?

一个理想的方法是首先

  • 比较内容的大小
  • 后跟一个随机的字符子集
  • 其次是全部内容

我还希望能够检测到几乎相同的 html,这些 html 可能仅相差几个微不足道的字符。

Python 的库 difflib 对此提供支持,但它占用大量资源。

于 2013-03-31T18:22:40.590 回答