如何设计一个网络爬虫?

5
我正在开展一个小项目,分析我觉得有趣的一些网站内容;这是一个让我自娱自乐/自我启发的真正DIY项目,因此我希望尽可能多地自己编写代码。
显然,我需要数据来供应我的应用程序,我想编写一个小爬虫,将大约20k个html页面写入我的硬盘上的文本文件中。 但是,当我在SO和其他网站上查看时,我找不到任何有关如何实现的信息。 这可行吗?似乎有可用的开源选项(webpshinx?),但如果可能的话,我想自己编写这个。
Scheme是我唯一熟悉的语言,但我想利用这个项目学习一些Java知识,所以如果有任何Racket或Java库对此有帮助,我会感兴趣。
因此,我想总结一下我的问题,有哪些好的资源可以开始这个项目?我的爬虫如何请求其他服务器的信息?我是否必须编写简单的解析器进行解析,还是因为我想将整个html文件保存为txt而不必要?

如果你不打算解析,就不需要解析器,但是解析会使提取链接变得更容易。不确定你遇到了什么问题;有许多示例可用——你目前有什么进展? - Dave Newton
你打算自己完成所有的套接字工作并直接使用原始HTTP与服务器通信吗?还是你愿意使用更高级别的工具来请求特定的URL?(你更关心网络方面还是HTML解析方面?) - sarnold
Dave,你能给个例子吗?那会非常有帮助。Sarnold,我从未真正做过任何网络编程——只是在 racket 的 web-server/insta 模块中做了一些东西,它接收请求并生成响应。所以我甚至不知道如何编写一个发送响应的程序。 - Pseudo-Gorgias
6个回答

5

然后使用sxpath(XPath的实现)来提取这些部分;请参阅此答案作者维护的SXML2软件包:http://planet.racket-lang.org/display.ss?package=sxml2.plt&owner=clements - Ryan Culpepper
谢谢你指引我去看这些,我一定会去了解一下。 - Pseudo-Gorgias

1

在Racket中自己完成了这个任务后,我想提出以下建议。

首先采用“Unix工具”方法:

  • 使用curl来下载每个页面(您可以使用system从Racket中执行它),并将输出存储在临时文件中。
  • 使用Racket从<a>标签中提取URI。
    • 你可以通过正则表达式字符串搜索来“作弊”。
    • 或者,按照John Clements的非常好的答案所解释的正确方式,使用真正的HTML解析器来处理。
    • 考虑先做“作弊”,然后再回过头来用正确的方式。

到这一步,您可以停止,或者您可以回去并用自己的代码替换curl进行下载。为此,您可以使用Racket的net/url模块。

我为什么建议先尝试curl呢?因为它可以帮助您完成看起来比较复杂的任务:

  • 您是否想要跟随30x重定向?
  • 您是否想要接受/存储/提供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)))

represents 是在 Racket 中代表了很多代码,否则你需要从头开始编写。它可以为你完成所有那些 curl 命令行标志所做的事情。

简而言之:从使用现有工具的最简单情况开始。将 Racket 用作几乎像 shell 脚本一样的方式。如果这对你来说已经足够好了,就停止。否则,逐个替换工具,使用你自己定制的代码。


0

我多年前用Perl做过这个(甚至没有使用webcrawler模块,更容易)。

我建议你阅读wget的文档,并借鉴该工具。Wget是网络爬虫中的netcat;它的功能集会给你灵感。

你的程序应该接受一个URL列表作为起点,并将它们添加到要尝试的URL列表中。然后,你需要决定是收集每个URL还是只添加初始列表中提供的域名(和子域名?)。

我在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)))))))))

0
我建议你研究一下名为crawler4j的Java开源网络爬虫。
这个工具非常简单易用,提供了很多出色的资源和选项来进行爬取。

0
如果你懂scheme,并且想逐步转向Java,为什么不从Clojure开始呢?
你可以利用你的lisp知识,并利用外部的Java html解析库来得到一个工作原型。然后,如果你想要将部分功能转换成Java来学习一些东西,可以在Java中编写一些代码,然后将其与Clojure代码连接起来。
祝好运!
*我看到了几个SO上关于这个问题的问答。

我对这个想法的担忧是,Clojure 的语法与 Scheme 差异足够大,以至于我最终可能会像 Java 一样频繁查阅 Clojure 文档,并且需要同时学习两种语言。我是否过分夸大了这些差异? - Pseudo-Gorgias
这是一种Lisp语言,其中有一些形式可能不在Scheme中,一旦你掌握了它们的要点,就只需要参考哪些函数做什么。http://clojuredocs.org(快速参考)非常适合这个。我认为你会很快学会它。我也认为这可能是一个很好的可市场化技能。 - BillRobertson42

0
如果我是你,我不会写爬虫——我会使用许多免费工具之一来下载网站以供离线浏览(例如http://www.httrack.com/)来进行爬取。您可能需要调整选项以禁用下载图像等内容,但这些工具将比您自己编写的任何东西更加强大和可配置。
一旦完成,您就会在本地拥有大量HTML文件,可以将其提供给您的应用程序。
我已经对HTML文件进行了很多文本分析;作为Java开发人员,我选择将HTML转换为文本(同样不是您想要自己编写的东西)的库是优秀的Jericho解析器:http://jericho.htmlparser.net/docs/index.html 编辑:重新阅读您的问题,似乎您已经决定编写自己的爬虫;如果是这样,我建议使用Commons HttpClient进行下载,并仍然使用Jericho提取链接并将其处理为新请求。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接