在Spidering中存储URL

时间:2010-04-11 02:19:53

标签: python database url storage web-crawler

我在Python中创建了一个小网页蜘蛛,我用它来收集网址。我对内容不感兴趣。现在我将所有访问过的URL保存在内存中,因为我不希望我的蜘蛛两次访问URL。当然,这是实现这一目标的一种非常有限的方式。

那么跟踪我访问过的网址的最佳方式是什么?

我应该使用数据库吗?

  • 哪一个? MySQL,SQLite,PostgreSQL?
  • 我应该如何保存网址?作为尝试在访问之前插入每个URL的主键?

或者我应该将它们写入文件?

  • 一个档案?
  • 多个文件?我该如何设计文件结构?

我确信有关于这个或类似主题的书籍和大量论文。你能给我一些我应该阅读的建议吗?

6 个答案:

答案 0 :(得分:9)

我写了很多蜘蛛。对我来说,比内存耗尽更大的问题是,如果代码或计算机崩溃或您决定需要调整代码,则可能会丢失已经抓过的所有URL。如果你的RAM耗尽,那么现在大多数机器和操作系统都会打开页面,这样你就会放慢速度但仍能运行。由于不再可用,因此必须重建一组在数小时和数小时运行时收集的URL,这可能会对生产力产生真正的打击。

在RAM中保存您不想丢失的信息是不好的。显然,数据库是此时的方法,因为您需要快速随机访问才能查看您是否已找到URL。当然,内存中查找速度更快,但是计算WHICH url保留在内存中的权衡会增加开销。我没有尝试编写代码来确定我需要/不需要哪些URL,而是将其保存在数据库中,并专注于使我的代码清洁和可维护,并且我的SQL查询和模式是明智的。使您的URL字段成为唯一索引,DBM将能够立即找到它们,同时自动避免冗余链接。

您与互联网和您正在访问的网站的连接可能比您在内部网络上的计算机上连接数据库要慢得多。同一台机器上的SQLite数据库可能是最快的,尽管DBM本身并不像Postgres那样复杂,这是我最喜欢的。我发现将数据库放在与我的蜘蛛机相同的交换机上的另一台机器上非常快;让一台机器处理spidering,解析,然后数据库读/写非常密集,所以如果你有一个旧盒子扔Linux,安装Postgres,然后去城里。如果你需要更快的速度,请在盒子里加一些额外的RAM。拥有用于数据库使用的单独框可以非常好。

答案 1 :(得分:7)

这些似乎是我的重要方面:

  1. 由于RAM太高,您无法将URL保留在内存中
  2. 您需要快速查找至少O(logn)
  3. 您需要快速插入
  4. 有很多方法可以做到这一点,这取决于数据库的大小。我认为SQL数据库可以为您的问题提供一个很好的模型。

    您可能只需要一个SQLite数据库。通常,存在检查的字符串查找是一个缓慢的操作。为了加快速度,您可以创建URL的CRC哈希并将CRC和URL存储在数据库中。您将在该CRC字段上有一个索引。

    • 插入时:插入URL和哈希
    • 当您想要进行存在查找时:您可以获取潜在新URL的CRC并检查它是否已存在于您的数据库中。

    URL哈希当然有可能发生冲突,但如果100%跨越对您不重要,那么当发生冲突时,您可以在数据库中获取没有URL的命中。

    您还可以通过多种方式减少碰撞。例如,您可以增加CRC的大小(CRC8而不是CRC4)并使用更大尺寸的散列算法。或者使用CRC以及URL长度。

答案 2 :(得分:4)

这取决于你将要做的蜘蛛的规模,以及你正在做的机器的种类。假设典型的URL是一个大约60个字节的字符串,内存集将占用每个URL超过100个字节(出于速度原因,Python中的集合和dicts永远不会超过60%。)如果你有一台64位机器(和Python发行版),可用的内存大约为16 GB,那么你肯定可以将超过10 GB的内容投入到这个关键的设置中,让你轻松地抓住大约1亿个网址;但另一方面,如果你有一台拥有3GB内存的32位机器,你显然不能在关键设备上投入比GB更多的内容,这限制了大约1000万个URL。 Sqlite可以帮助大约相同的大小,32位机器无法做到这一点但是一个慷慨的64位可以说 - 或者说100或2亿个URL。

除此之外,我还推荐PostgreSQL,它还具有能够在不同机器(快速LAN)上运行的优势,基本上没有任何问题,让您可以将主机专用于蜘蛛网。我猜MySQL& c也可以,但我喜欢PostgreSQL标准兼容性和稳健性;-)。例如,这将允许几十亿个没有问题的URL(只需要一个快速的磁盘,或者更好的RAID安排,以及尽可能多的RAM来加快速度,当然)。

尝试通过使用固定长度哈希来代替可能很长的网址来节省内存/存储空间很好如果你可以偶尔出现误报,这会阻止你抓取什么是新的URL。这样的“冲突”根本不可能是这样的:即使你只使用8个字节作为哈希,当你查看数十亿个URL时,你应该只有很大的冲突风险(“平方根启发式”)众所周知的问题)。

使用8字节的字符串来表示URL,如上所述,内存集架构应该可以轻松地在天赋良好的机器上支持十亿个URL或更多URL。

那么,大概你想要蜘蛛网的数量,以及你可以节省多少内存? - )

答案 3 :(得分:2)

您只是存储网址吗?你应该看看mongoDB。这是一个非常容易实现的NoSQL数据库。

http://try.mongodb.org/

它也有python绑定:

http://api.mongodb.org/python/1.5.2%2B/index.html

答案 4 :(得分:1)

由于您可能会在相似的时间看到类似的网址(例如,在抓住网站时,您会看到很多指向网站主页的链接)我建议您将网址保存在字典中直到你的记忆力变得有限(只需硬编码一个合理的数字,如10M网址或类似名称),然后当它变得太大时,将字典刷新到CDB database file

这样,你的大部分URL检查都将在内存中(速度很快),而不在内存中的那些检查仍然只需要从磁盘读取1-2次来验证你是否已经访问过它们。 / p>

答案 5 :(得分:0)

现在考虑Pickling:简单的结构化存储。

里程会有所不同,因为正如其他响应者所说,你很快就会耗尽你的RAM。