【问题标题】:What languages are good for writing a web crawler? [closed]哪些语言适合编写网络爬虫? [关闭]
【发布时间】:2010-09-08 01:27:21
【问题描述】:

我有丰富的 PHP 经验,尽管我意识到 PHP 可能不是大型网络爬虫的最佳语言,因为进程不能无限期地运行。人们建议使用哪些语言?

【问题讨论】:

    标签: php c++ python web-crawler


    【解决方案1】:

    大多数语言可能都比较合适,关键组件是

    1. 处理 Internet 协议的库
    2. 处理正则表达式的库
    3. 用于解析 HTML 内容的库

    如今,大多数语言都有对上述内容提供良好支持的库,当然您需要一些方法来保存可能是某种数据库的结果。

    比语言更重要的是理解你需要处理的所有概念。以下是一些 Python 示例,可能有助于您入门。

    http://www.example-code.com/python/pythonspider.asp

    【讨论】:

      【解决方案2】:

      您可以轻松使用的任何语言都具有良好的网络库并支持解析您要抓取的格式。这些确实是唯一的资格。

      【讨论】:

      • 这些是它可能的条件,但我认为它是一种语言的条件是更严格一点(尤其是速度)。
      • @peachykeen:没有后两者是可能的——它只会做更多的工作。至于速度,我认为 INTERCAL 对于爬虫来说可能是一个糟糕的选择,但我不明白为什么速度对于网络爬虫来说比任何其他类型的程序都更重要(特别是考虑到 Web-anything 极有可能是 IO -边界)。您的爬虫必须非常慢才能使其执行时间超过 Web 的延迟。
      • 可能,但我仍然会考虑。我不会在自己的服务器上运行爬虫,所以它需要与我的桌面或服务器共享时间。另外,我看到一些讨厌的页面在大多数 HTML 解析器中加载需要相当长的时间,所以你必须小心。网络可能是您的瓶颈,但 IMO 速度值得一提。 :)
      • 而且,同样重要的是,另一个条件是“一种让您可以轻松地做除爬行以外的所有事情的语言”。无论您是在收集、处理、大量处理还是在处理数据,这都会有所不同。
      【解决方案3】:

      您可以考虑使用 python 和 PyGtkMozEmbed 或 PyWebKitGtk 加上 javascript 的组合来创建您的蜘蛛。

      在页面和所有其他脚本加载后,可以在 javascript 中进行爬取。

      您将拥有少数支持 javascript 的网络蜘蛛之一,并且可能会拾取一些其他人看不到的隐藏内容 :)

      【讨论】:

        【解决方案4】:

        C++ - 如果你知道你在做什么。您将不需要 Web 服务器和 Web 应用程序,因为 Web 爬虫毕竟只是一个客户端。

        【讨论】:

        • 真的!我想我只需要将它与各种数据库接口...对 Python 有什么想法吗?
        • PHP 不需要 Web 服务器来使用它的 CLI 版本。只是一个“额外的信息”花絮。
        • 嗯.. PHP 可以在 CLI 中运行,但它仍然会很快溢出内存,不是吗?
        • 不知道,从来没有尝试过用 PHP 创建这样的应用程序。不过,我想是这样的。
        • 我认为 PHP 会很好用,真的。您可以提高进程允许使用的内存量、允许运行的时间等。您可以让线程在一段时间后终止,只需跟踪数据库中仍需要索引的内容或其他内容,并拥有新线程从旧线程停止的地方开始。
        【解决方案5】:

        既然可以复制http://code.activestate.com/recipes/576551-simple-web-crawler/,为什么还要自己写

        您可能需要在这里和那里修复一些问题,例如使用 htmlentities 而不是将 & 替换为 &

        【讨论】:

          【解决方案6】:

          在编写多核/线程爬虫时,C 是最重要的,但它也有其自身的复杂性。在 C 之后,一些人选择了 JAVA(由于广泛的探索和使用),而另一些人则选择了 Python。如果你有很好的架构,我可以向你保证这三种语言真的不会限制你的效率。

          这个 python 代码是一个 C Curl 实现,可以在一个不错的服务器上在 300 秒内爬取大约 10,000 个页面

          #! /usr/bin/env python
          # -*- coding: iso-8859-1 -*-
          # vi:ts=4:et
          # $Id: retriever-multi.py,v 1.29 2005/07/28 11:04:13 mfx Exp $
          
          #
          # Usage: python retriever-multi.py <file with URLs to fetch> [<# of
          #          concurrent connections>]
          #
          
          import sys
          import pycurl
          
          # We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
          # the libcurl tutorial for more info.
          try:
              import signal
              from signal import SIGPIPE, SIG_IGN
              signal.signal(signal.SIGPIPE, signal.SIG_IGN)
          except ImportError:
              pass
          
          
          # Get args
          num_conn = 10
          try:
              if sys.argv[1] == "-":
                  urls = sys.stdin.readlines()
              else:
                  urls = open(sys.argv[1]).readlines()
              if len(sys.argv) >= 3:
                  num_conn = int(sys.argv[2])
          except:
              print "Usage: %s <file with URLs to fetch> [<# of concurrent connections>]" % sys.argv[0]
              raise SystemExit
          
          
          # Make a queue with (url, filename) tuples
          queue = []
          for url in urls:
              url = url.strip()
              if not url or url[0] == "#":
                  continue
              filename = "doc_%03d.dat" % (len(queue) + 1)
              queue.append((url, filename))
          
          
          # Check args
          assert queue, "no URLs given"
          num_urls = len(queue)
          num_conn = min(num_conn, num_urls)
          assert 1 <= num_conn <= 10000, "invalid number of concurrent connections"
          print "PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM)
          print "----- Getting", num_urls, "URLs using", num_conn, "connections -----"
          
          
          # Pre-allocate a list of curl objects
          m = pycurl.CurlMulti()
          m.handles = []
          for i in range(num_conn):
              c = pycurl.Curl()
              c.fp = None
              c.setopt(pycurl.FOLLOWLOCATION, 1)
              c.setopt(pycurl.MAXREDIRS, 5)
              c.setopt(pycurl.CONNECTTIMEOUT, 30)
              c.setopt(pycurl.TIMEOUT, 300)
              c.setopt(pycurl.NOSIGNAL, 1)
              m.handles.append(c)
          
          
          # Main loop
          freelist = m.handles[:]
          num_processed = 0
          while num_processed < num_urls:
              # If there is an url to process and a free curl object, add to multi stack
              while queue and freelist:
                  url, filename = queue.pop(0)
                  c = freelist.pop()
                  c.fp = open(filename, "wb")
                  c.setopt(pycurl.URL, url)
                  c.setopt(pycurl.WRITEDATA, c.fp)
                  m.add_handle(c)
                  # store some info
                  c.filename = filename
                  c.url = url
              # Run the internal curl state machine for the multi stack
              while 1:
                  ret, num_handles = m.perform()
                  if ret != pycurl.E_CALL_MULTI_PERFORM:
                      break
              # Check for curl objects which have terminated, and add them to the freelist
              while 1:
                  num_q, ok_list, err_list = m.info_read()
                  for c in ok_list:
                      c.fp.close()
                      c.fp = None
                      m.remove_handle(c)
                      print "Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL)
                      freelist.append(c)
                  for c, errno, errmsg in err_list:
                      c.fp.close()
                      c.fp = None
                      m.remove_handle(c)
                      print "Failed: ", c.filename, c.url, errno, errmsg
                      freelist.append(c)
                  num_processed = num_processed + len(ok_list) + len(err_list)
                  if num_q == 0:
                      break
              # Currently no more I/O is pending, could do something in the meantime
              # (display a progress bar, etc.).
              # We just call select() to sleep until some more data is available.
              m.select(1.0)
          
          
          # Cleanup
          for c in m.handles:
              if c.fp is not None:
                  c.fp.close()
                  c.fp = None
              c.close()
          m.close()
          

          【讨论】:

            【解决方案7】:

            C# 和 C++ 可能是这方面最好的两种语言,只是你更了解哪种语言更快(C# 可能更容易)的问题。

            我不推荐 Python、Javascript 或 PHP。与 C 系列语言相比,它们的文本处理速度通常较慢。如果您希望抓取网络的任何重要部分,您将需要尽可能快的速度。

            我之前使用过 C# 和 HtmlAgilityPack,它的效果相对较好,而且很容易上手。能够像使用 XML 一样使用许多相同的命令来处理 HTML,这让它变得很好(我曾在 C# 中使用过 XML)。

            您可能想要测试可用的 C# HTML 解析库与 C++ 解析库的速度。我知道在我的应用程序中,我每秒要浏览 60-70 个相当混乱的页面,并从每个页面中提取大量数据(但那是一个布局相当稳定的网站)。

            编辑:我注意到您提到访问数据库。 C++ 和 C# 都有可用于大多数常见数据库系统的库,从 SQLite(这对于在几个站点上的快速爬虫来说非常有用)到 MySQL 和 MSSQL 等中端引擎,再到更大的 DB 引擎(我从未使用过 Oracle或来自任一语言的 DB2,但这是可能的)。

            【讨论】:

            • -1。 webcrawler 主要是一个 IO 绑定应用程序。用 C++ 编写不会使网络运行得更快。
            • [需要引用] 关于 Javascript 和 Python 在此任务中的过度缓慢。 Googlebot 是用 Python 编写的,那时 Python 和计算机硬件都比现在慢很多。
            • @aaronasterling:但是用 PHP 编写会使其运行比 C++ 慢。根据需要完成的处理的复杂性以及需要将哪些数据保存到磁盘(假设您必须遍历 DOM 并将每个 img src 保存到数据库),C++/C# 可以为您带来相当大的性能提升。实际的解析是所有的文本操作,而且很多。总体而言,无论网络速度如何,C++ 或 C# 都能提供更好的处理性能。
            • 实际上有历史上用“慢”语言编写的代码最终击败了用 C 编写的代码的例子。以 Apache(不是 Apache2,用 C 编写)和 Tclhttpd(用 Tcl 编写,它本身在时间甚至比 Perl 还要慢)。 Tclhttpd 在静态文件传输方面击败了 Apache。 Apache2 从中吸取了教训,他们改变了他们的 I/O 算法,使其更像 tcl 解释器的工作方式。因此,C/C++ 可能不是最快的,因为它在加数方面速度很快。
            • @peachykeen:另一方面,很多解释器(尤其是对于像 Perl 和 Tcl 这样的旧语言)已经优化了字符串操作例程。另一方面,C/C++ 有非常非常慢的字符串操作例程。将 C 中的 strlen() 与时间线性的 C 中的 string length 进行比较,tcl 中的 string length 是恒定时间。这是因为高级语言中的“字符串”通常在后端实现为适当的数据结构,而不是原始 C 字符串。当然,没有任何保证。例如,Microsoft 的 javascript 的行为就好像 String 对象只是 C 字符串的一个薄包装器。
            猜你喜欢
            • 1970-01-01
            • 2011-07-07
            • 1970-01-01
            • 2011-06-26
            • 2011-01-13
            • 1970-01-01
            • 2023-04-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多