如何设计一个爬行机器人?

时间:2012-01-20 01:24:23

标签: java scheme web-crawler racket

我正在开展一个小项目来分析我觉得有趣的网站上的内容;这是一个真正的DIY项目,我正在为我的娱乐/启蒙做,所以我想尽可能多地编写自己的代码。

显然,我将需要数据来提供我的应用程序,我想我会写一个小爬虫,可能需要20k页的html并将它们写入我的硬盘上的文本文件。但是,当我查看SO和其他网站时,我找不到有关如何执行此操作的任何信息。这可行吗?似乎有可用的开源选项(webpshinx?),但我想尽可能自己写这个。

Scheme是我唯一熟悉的语言,但我认为我会利用这个项目来学习一些Java,所以如果有任何racket或java库会对此有所帮助,我会感兴趣。

所以我想总结一下我的问题,有什么好的资源可以开始这个?如何让我的爬虫从其他服务器请求信息?我是否必须为此编写一个简单的解析器,或者这是不必要的,因为我想获取整个html文件并将其保存为txt?

6 个答案:

答案 0 :(得分:5)

这完全可行,你绝对可以使用Racket。您可能想看一下PLaneT库;尤其是Neil Van Dyke的HtmlPrag:

http://planet.racket-lang.org/display.ss?package=htmlprag.plt&owner=neil

..可能是开始的地方。您应该能够将一个网页的内容拉成一行或两行代码中的解析格式。

如果您对此有任何疑问,请与我们联系。

答案 1 :(得分:1)

我自己在Racket中完成了这个,这就是我的建议。

从“Unix工具”方法开始:

  • 使用curl执行下载每个页面的工作(您可以使用system从Racket执行它)并将输出存储在临时文件中。
  • 使用Racket从<a>标记中提取URI。
    • 您可以“作弊”并进行正则表达式字符串搜索。
    • 或者,用正确的HTML解析器做“正确的方式”,正如John Clements的精彩回答所解释的那样。
    • 首先考虑可能做作弊,然后稍后循环回来以正确的方式做。

此时您可以停止,或者,您可以返回并使用您自己的代码替换curl来执行下载。为此,您可以使用Racket的net/url模块。

为什么我建议尝试curl,首先,它可以帮助您做一些比看上去更复杂的事情:

  • 您想要关注30倍重定向吗?
  • 您是否想接受/存储/提供cookie(否则网站的行为可能不同)?
  • 您想使用HTTP keep-alive吗?
  • 等等。

使用curl例如:

(define curl-core-options
  (string-append
   "--silent "
   "--show-error "
   "--location "
   "--connect-timeout 10 "
   "--max-time 30 "
   "--cookie-jar " (path->string (build-path 'same "tmp" "cookies")) " "
   "--keepalive-time 60 "
   "--user-agent 'my crawler' "
   "--globoff " ))

(define (curl/head url out-file)
  (system (format "curl ~a --head --output ~a --url \"~a\""
                   curl-core-options
                   (path->string out-file)
                   url)))

(define (curl/get url out-file)
  (system (format "curl ~a --output ~a --url \"~a\""
                  curl-core-options
                  (path->string out-file)
                  url)))

表示代码是 lot ,否则您需要在Racket中从头开始编写代码。要做那些curl命令行标志为你做的所有事情。

简而言之:从最简单的使用现有工具开始。使用Racket几乎作为shell脚本。如果这对你来说足够好,请停下来。否则,请继续使用您的定制代码逐个更换工具。

答案 2 :(得分:0)

我建议查看java的开源网络抓取工具crawler4j

使用起来非常简单,它为您的抓取提供了非常好的资源和选项。

答案 3 :(得分:0)

如果您了解方案,并且想要轻松使用Java,为什么不从Clojure开始?

您可以利用您的lisp知识,并利用java html解析库*在那里获得一些有用的东西。然后,如果你想开始将它的一部分转换为Java来学习一点,你可以用Java编写一些功能并将其连接到Clojure代码中。

祝你好运!

*我已经看到了几个SO问题。

答案 4 :(得分:0)

如果我是你,我不会写一个抓取工具 - 我会使用许多免费工具之一在本地下载网站进行离线浏览(例如http://www.httrack.com/)来进行抓取。您可能需要调整选项以禁用下载图像等,但这些工具将比您自己编写的任何内容更加健壮和可配置。

一旦你这样做,你就会在本地拥有大量的HTML文件,你可以将它们提供给你的应用程序。

我对HTML文件进行了大量的文本分析;作为一个Java人,我将HTML提炼成文本的选择库(再次,不是你想要自己推出的东西)是优秀的Jericho解析器:http://jericho.htmlparser.net/docs/index.html

编辑:重新阅读您的问题,看来您确实在编写自己的抓取工具;如果是这样,我会建议Commons HttpClient进行下载,并且仍然会让Jericho取出链接并将它们处理成新的请求。

答案 5 :(得分:0)

我几年前在Perl中做过(更简单,即使没有webcrawler模块)。

我建议您阅读wget文档并使用该工具获取灵感。 Wget是webcrawling的netcat;它的功能集将激励你。

您的程序应接受一系列要开始使用的网址,并将其添加到要尝试的网址列表中。然后,您必须决定是要收集每个网址还是仅添加初始列表中提供的域(和子域?)中的网址。

我在Scheme中为你提供了一个相当强大的起点:

(define (crawl . urls)
  ;; I would use regular expressions for this unless you have a special module for this
  ;; Hint: URLs tend to hide in comments. referal tags, cookies... Not just links.
  (define (parse url) ...)
  ;; For this I would convert URL strings to a standard form then string=
  (define (url= x y) ...)
  ;; use whatever DNS lookup mecanism your implementation provides
  (define (get-dom) ...)
  ;; the rest should work fine on its own unless you need to modify anything
  (if (null? urls) (error "No URLs!")
      (let ([doms (map get-dom urls)])
        (let crawl ([done '()])
          (receive (url urls) (car+cdr urls)
            (if (or (member url done url=)
                      (not (member (get-dom url) doms url=)))
                (crawl urls done)
                (begin (parse url) (display url) (newline)
                  (crawl (cons url done)))))))))