Skip to content

四火的唠叨

一个纯正程序员的啰嗦

Menu
  • 所有文章
  • About Me
  • 关于四火
  • 旅行映像
  • 独立游戏
  • 资源链接
Menu

网络爬虫

Posted on 05/26/201306/23/2019 by 四火

最近在写一个程序,去爬热门事件和热门关键词网站上的数据。在这里介绍一下网络爬虫的种种。

基本组件

image

网络爬虫也叫做网络蜘蛛,是一种互联网机器人,把需要的网页撷取下来,组织成适当格式存储。它是搜索引擎的重要组成部分,虽然从技术实现上来说,它的难度往往要小于对于得到的网页信息的处理。

上面这张图来自维基百科,scheduler 调度多个多线程的下载器下载网页,并把信息和元数据存储起来。而通过解析下载网页的数据,找到链接,又把链接加入到工作队列中去准备下载。这看起来是一个迭代的过程。

网络爬虫相关的几项重要策略:

  • 选择策略:哪些网页是需要被抓取的;
  • 重访问策略:怎样的方式去检测网页是否被修改过;
  • 礼貌性策略:抓取网页的时候,需要方式网站过载;
  • 并行化策略:怎样组织分布式的网络爬虫。

选择策略

限定跟随链接。通常只需要 html 文本信息,所以根据 MIME 类型,如果不是文本信息,会被丢弃掉。所以,如果 URL 无法得知资源的二进制类型,爬虫可能会先发起一个 head 请求获知目标是不是文本,如果是的话,才发送一个 get 请求获取页面。

URL 标准化。它用来避免多次爬到相同的页面。有些 URL 包含 “../” 这样的相对路径信息,这也需要爬虫处理使之成为完整正确的 URL,而有些 URL 则需要在最后面加上斜杠。

路径升序。有些爬虫想尽可能爬多的信息,资源是有层级关系的,比如 http://llama.org/hamster/monkey/page.html 这样一个链接,它会尝试爬 “/hamster/monkey/”、“/hamster/” 和 “/” 这几个页面。

学术网页爬虫。专注于学术领域,比如 Google Scholar 等等。

重访问策略

网页总是在动态变化的,爬完整一个网站可能会花掉数周甚至一个月的时间,在爬完一个网页之后,网页可能就不在了,或者更新了。什么时候再爬这个网站呢?通常对于经常变化的网页,这个间隔时间应该短一些。

新鲜度:在一定时间 t 内,页面是否有变化。

freshness

Age: 本地网页拷贝有多么过时。

image

有一种常见的重访问策略是,先以一个默认的频度访问页面,如果发现页面持续不更新,就逐步降低这个频度;反之亦然。

礼貌性策略

爬虫当然可以尽可能快地爬取数据,但是我们需要考虑网站的性能压力,已经对网络资源的消耗。

有一个 robots exclusion 协议,指定了爬虫应该怎样访问网站的资源,哪些可以访问,哪些不可以访问。这个协议并不是强制的,但是已经是事实上的标准。比如,Crawl-delay 参数,就可以定义每连续两次的请求,至少需要间隔多少秒。

以本网站的 robots.txt 为例:

User-agent: *
Disallow: /wp-admin/
Disallow: /wp-includes/

Sitemap: /sitemap.xml.gz

其中的 User-agent 表示对爬虫类型没有限制,Disallow 两行指定了哪些 URL 是不允许搜索引擎抓取的;Sitemap 则是一个 xml 格式的网站地图:

<url>
  <loc>/</loc>
  <lastmod>2013-05-25T16:32:13+00:00</lastmod>
  <changefreq>daily</changefreq>
  <priority>1.0</priority>
</url>
<url>
  <loc>/1374</loc>
  <lastmod>2013-05-19T14:46:19+00:00</lastmod>
  <changefreq>monthly</changefreq>
  <priority>0.2</priority>
</url>

指定了网站有哪些页面,更新频率和权重各是多少。如果有些页面没有明显的直接链接抵达,通过 sitemap 的形式可以告知爬虫去抓取。如果你很讨厌某个搜索引擎,你可以这样指定(我只是举例而已,百度除了假药假广告侵权信息管制主观性过滤以外也是做了一些好事的 -_-~):

User-agent: Baiduspider

Disallow: /

网页深度

通常,越是深的链接,重要性越低,数量也越大。对于爬虫来说,越深的链接往往价值越小。在大多数情况下,我们不需要所有的信息,这时候需要控制合理的网页深度,价值高的网站可以深度适当大一些。

互联网即数据库

以前我曾经介绍过 YQL,一种像 SQL 查询数据库一样查询互联网网页数据的语言,你也可以在这个 YQL 控制台自己试试:

select * from flickr.photos.search where text="Cat" and api_key="your key here" limit 10

这是一个 “get 10 flickr “cat” photos” 的例子。

再比如:

select * from html where url="http://finance.yahoo.com/q?s=yhoo" and xpath='//div[@id="yfi_headlines"]/div[2]/ul/li/a'

如果你看得懂 XPATH 表达式的话,这一定很清楚。它可以以普通 HTTP API 的方式暴露出来:

http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22http%3A%2F%2Ffinance.yahoo.com%2Fq%3Fs%3Dyhoo%22%20and%20xpath%3D'%2F%2Fdiv%5B%40id%3D%22yfi_headlines%22%5D%2Fdiv%5B2%5D%2Ful%2Fli%2Fa'&format=json&diagnostics=true&callback=cbfunc

在很多情况下,我们需要的并不是宽泛的信息,而是明确地知道自己需要什么信息,譬如某网站总是显示自己关心的信息,那么就可以借用它来定时爬取特定的页面(比如我以前干过这样的事:一场 NBA 比赛结束了,我没有看,但是我很想尽快地看到比赛录像,于是每隔几分钟就去爬取一个论坛比赛下载的帖子汇总页面,当 “马刺” 那个关键词出现的时候,我就去看一下是不是有比赛下载了。当然,你可以做得更好,写一个脚本让整个下载过程自动化完成,这样你就可以安心上班了,等回到家的时候,比赛已经下载完毕等你去看了)。现在这样的事情可以通过上面的 HTTP API 链接更方便地完成了。

完成整个过程以后,你一定会有这样的体会,互联网其实就是一个硕大的数据库(不管 URI 的定义是否符合 RESTful 风格,它最多只能说是数据是不是能够以符合某种统一格式的方式来获取)。

  1. HTML、RSS、PDF……这些只是不同的数据格式而已,和内容无关,获取这些不同格式不同地址数据的组件可以叫做 requester;
  2. XPATH、CSSPath……这些是针对不同数据,去解析这些数据,指定有用信息的路径表达式,解析这些数据的组件被称为 parser;
  3. 存储每一内容条目使用哪个 requester 和哪个 parser 的配置,汇总在一个 configuration 的组件内;
  4. 现在,还需要一个调度器 scheduler 管理若干个线程(或进程)根据 configuration 去爬取数据了;
  5. 数据爬取完成后持久化到存储组件 storage 中。

有了上面这 5 个组件,一个特定信息的爬取程序就完成了,和一个传统意义上的网络爬虫相比,它更加简单,也不需要解析 HTML 链接含义的过程。

另外,值得注意的是,有时候网站会做反爬虫机制,与其去猜它反爬虫的规则,还不如通过脚本启动一个浏览器去请求页面。还有,页面之间的关联关系有时并不能够从<a href=”xxx”> 这样的链接中发现,有时是通过 JavaScript 的 Ajax 请求等等实现,这种情况下的链接关系对网络爬虫并不友好,也可以通过启动一个真实的浏览器请求去获取。

Java 有名的开源网络爬虫包括 Heritrix 和 Nutch,后续我再详细介绍一下。

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

×Scan to share with WeChat

你可能也喜欢看:

  1. 酒桌上的计算机网络
  2. Hadoop 的 Map-side join 和 Reduce-side join
  3. 数据挖掘学习笔记:分类、统计学习
  4. HTTP 劫持
  5. Spark 的性能调优

2 thoughts on “网络爬虫”

  1. C语言 says:
    05/28/2013 at 5:34 PM

    使用 PHP 下过电子树,很小的一个东西。没有博主说的这么大

    Reply
  2. Anonymous says:
    05/27/2013 at 11:20 AM

    在 muti-treads downloader 中读取 xml 定时下载,遇到一些问题。望博主指点一二。

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

订阅·联系

四火,啰嗦的程序员一枚,现居西雅图

Amazon Google Groovy Hadoop Haskell Java JavaScript LeetCode Oracle Python Spark 互联网 前端 华为 历史 同步 团队 图解笔记 基础设施 工作 工作流 工具 工程师 应用系统 异步 微博 思考 技术 数据库 曼联 测试 生活 程序员 管理 系统设计 缓存 编码 编程范型 英语 西雅图 设计 评审 问题 面试 项目

分类

  • Algorithm and Data Structure (30)
  • Concurrency and Asynchronization (6)
  • System Architecture and Design (43)
  • Distributed System (18)
  • Tools Frameworks and Libs (13)
  • Storage and Data Access (8)
  • Front-end Development (33)
  • Programming Languages and Paradigms (55)
  • Testing and Quality Assurance (4)
  • Network and Communication (6)
  • Authentication and Authorization (6)
  • Automation and Operation Excellence (13)
  • Big Data and Machine Learning (5)
  • Product Design (7)
  • Hiring and Interviews (14)
  • Project and Team Management (14)
  • Engineering Culture (17)
  • Critical Thinking (25)
  • Career Growth (57)
  • Life Experience and Thoughts (45)

推荐文章

  • 谈谈分布式锁
  • 常见分布式系统设计图解(汇总)
  • 系统设计中的快速估算技巧
  • 从链表存在环的问题说起
  • 技术面试中,什么样的问题才是好问题?
  • 从物理时钟到逻辑时钟
  • 近期面试观摩的一些思考
  • RSA 背后的算法
  • 谈谈 Ops(汇总 + 最终篇):工具和实践
  • 不要让业务牵着鼻子走
  • 倔强的程序员
  • 谈谈微信的信息流
  • 评审的艺术——谈谈现实中的代码评审
  • Blog 安全问题小记
  • 求第 K 个数的问题
  • 一些前端框架的比较(下)——Ember.js 和 React
  • 一些前端框架的比较(上)——GWT、AngularJS 和 Backbone.js
  • 工作流系统的设计
  • Spark 的性能调优
  • “残酷” 的事实
  • 七年工作,几个故事
  • 从 Java 和 JavaScript 来学习 Haskell 和 Groovy(汇总)
  • 一道随机数题目的求解
  • 层次
  • Dynamo 的实现技术和去中心化
  • 也谈谈全栈工程师
  • 多重继承的演变
  • 编程范型:工具的选择
  • GWT 初体验
  • java.util.concurrent 并发包诸类概览
  • 从 DCL 的对象安全发布谈起
  • 不同团队的困惑
  • 不适合 Hadoop 解决的问题
  • 留心那些潜在的系统设计问题
  • 再谈大楼扔鸡蛋的问题
  • 几种华丽无比的开发方式
  • 我眼中的工程师文化
  • 观点的碰撞
  • 谈谈盗版软件问题
  • 对几个软件开发传统观点的质疑和反驳
  • MVC 框架的映射和解耦
  • 编程的未来
  • DAO 的演进
  • 致那些自嘲码农的苦逼程序员
  • Java 多线程发展简史
  • 珍爱生命,远离微博
  • 网站性能优化的三重境界
  • OSCache 框架源码解析
  • “ 你不适合做程序员”
  • 画圆画方的故事

近期评论

  • + 1.943624 BTC.NEXT - https://graph.org/Ticket--58146-05-02?hs=9a9c6f8dfe3cdbe0074006e3e640b19b& on 所有文章
  • Anonymous on 闲聊投资:亲自体验和护城河
  • 四火 on 关于近期求职的近况和思考
  • YC on 关于近期求职的近况和思考
  • mafulong on 常见分布式基础设施系统设计图解(四):分布式工作流系统
  • 四火 on 常见分布式基础设施系统设计图解(八):分布式键值存储系统
  • Anonymous on 我裸辞了
  • https://umlcn.com on 资源链接
  • Anonymous on 我裸辞了
  • Dylan on 我裸辞了
© 2025 四火的唠叨 | Powered by Minimalist Blog WordPress Theme