爬虫攻略(一)

互联网 Web 就是一个巨大无比的数据库,但是这个数据库没有一个像 SQL 语言可以直接获取里面的数据,因为更多时候 Web 是供肉眼阅读和操作的。如果要让机器在 Web 取得数据,那往往就是我们所说的“爬虫”了。现在项目需要,所以研究研究,把大概的过程和“坑”记录下来,也欢迎大渣批评和补充。

爬虫的思路十分简单:

  1. 按照一定的规律发送 HTTP 请求获得页面 HTML 源码(必要时需要加上一定的 HTTP 头信息,比如 cookie 或 referer 之类)
  2. 利用正则匹配或第三方模块解析 HTML 代码,提取有效数据
  3. 将数据持久化到数据库中。

上述过程虽描述得简单,但在实际过程遇到的问题还是不少的,世界上不存在完美的、一致的、通用的抓取工具。为了不同的目的,需要定制不同的代码。下面我们逐一分析。

解析 HTML

简单抓取

最基本的发送 HTTP 请求获得 HTML 代码,使用 node 自带的 http.request 功能即可。如果是爬简单的内容,比如获得某个指定 id 元素中的内容(常见于抓去商品价格),那么正则足以完成任务。但是对于复杂的页面,尤其是数据项较多的页面,使用 DOM 会更加方便高效。

而 node.js 最好的 DOM 实现非 cheerio莫属了。其实 cheerio 应该算是 jQuery 的一个针对 DOM 操作优化和精简的子集,包含了 DOM 操作的大部分内容,去除了其它不必要的内容。使用 cheerio 你就可以像用普通 jQuery 选择器那样选择你需要的内容。

cheerio 使用方法如下所示,首先引入 cheerio = require('cheerio')。

jsdom 也可以。

var jsdom = require("jsdom");

jsdom.env({
  url: "http://v.youku.com/v_show/id_XMTQ3Mzc1MTczNg==.html?from=y1.6-85.3.1.14b31ff68f3311e5a080&x",
//  ['http://static.youku.com/h5/player/embed/unifull/unifull_.js'],
//  {
	  userAgent:'Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25'
//  },
  ,done:function (err, window) {
	  console.log(err);
	  setTimeout(function(){

		  console.log("there have been", window.document.body.innerHTML);
	  }, 2000);
  }
});

使用 request.js

request.js 是对 http.request 更高级的封装。如果结合 cheerio 使用,是这样子的。

// 打开详情页
var request = require('request'), cheerio = require('cheerio');

function loadInfo(url){
	request({
	  url: url,
	  headers: {
	    'User-Agent': userAgent
	  }
	}, function fetch(error, response, body) {
		if (!error && response.statusCode == 200) {
			var $ = cheerio.load(body, {decodeEntities: false});

			var video = $('video');
			console.log(video);
		} else {
			console.log('解析 HTML 错误或通讯故障。');
		}
	});
}

详情参阅 request.js 文档以及教程

JS 生成页面(通过 Phantom.js 抓取)

某些页面的内容显示是通过 JavaScript 动态调用显示的,所以就没法通过普通的获取页面 HTML 然后通过正则或者 XPath 的方式获取到想到的信息了。所幸我们现在有了 Phantom.js 的库,它是一个服务器端的没用界面的 webkit 浏览器。某种程度讲,因为 Phantom.js 内置了一个完整的 JS 运行时,所以这时候是无须要 cheerio 的帮助的。

首先,Phantom.js 不是 node 的库,是可以独立运行的程序——怎么让 Phantom.js 与 Node “联婚”呢?开源的方案搜索一下有不少,例如:

  • https://github.com/SpookyJS/SpookyJS
  • https://github.com/Medium/phantomjs
  • https://github.com/alexscheelmeyer/node-phantom
  • 貌似 Nightmare.js + Electron 也很强大
  • https://github.com/amir20/phantomjs-node

发现只有 phantomjs-node 最近才在更新(最后的那個)。phantomjs-node 成功将 Phantom.js 作为 node 的一个模块来使用,其原理是通过 标准输出 sysin/sysout 来进行两者进程之通讯的(v2.x 改进),速度比较快。既然要依赖于 Phantom.js 那么就要下载 Phantom.js 并将 Phantom.js 配置进环境变量(PATH),命令行输入 phantomjs  如果有反应,那么就可以进行下一步了。

当前 Phantom.js 版本是 2.1,phantomjs-node 版本是 2.0.x。安装 phantomjs-node:

npm install phantom --save

测试是否安装正确(phantomjs.exe 加入 PATH 环境变量)

var phantom = require('phantom');

phantom.create().then(function(ph) {
  ph.createPage().then(function(page) {
    page.open('https://stackoverflow.com/').then(function(status) {
      console.log(status);
      page.property('content').then(function(content) {
        console.log(content);
        page.close();
        ph.exit();
      })
    })
  });
});

下面重点谈谈 Phantom.js 的使用。

Phantom.js

按照上面的例子就可以把 HTML 打印出来(content 内容)。对于 page 打开的页面,往往需要与其进行一些交互,也就是 DOM 方式操控 HTML。page.evaluate() 提供了在page 打开页面的上下文的操作,因此 page.evaluate(function(){...}) 第一个函数是在页面操作的。比如 console.log("foo"),不是在我们 phantomjs 那个控制台里面输出那个文本,而是浏览器的。

注意使用 page.evaluate() 的话一定先要将 JavaScript 激活!

phantomjs-node 提供的 API

phantom.createPage() 方法返回的 page 对象是 Phantom.js 的代理对象,一般情况下其所提供的方法与 Phantom.js 原生的一致。page 的方法为 Promise 异步调用方法,返回的总是一个 Promise 对象。

例如读取某个属性可以调用 page.property(),然后通过 Promise 的 then 异步返回,例如:

page.property('plainText').then(function(content) {
  console.log(content);
});

设置属性方法如下,then 可以省略。But beware that the next method to phantom will block until it is ready to accept a new message.

page.property('viewportSize', {width: 800, height: 600}).then(function() {
});

读取属性可以通过以下方法:

page.setting('javascriptEnabled').then(function(value){
    expect(value).toEqual(true);
});

事件也用通过 property 设置,因为其实它是 page 的一个成员。

page.property('onResourceRequested', function(requestData, networkRequest) {
    console.log(requestData.url);
})
时间: 2024-09-22 15:29:58

爬虫攻略(一)的相关文章

阿里巴巴大数据计算平台MaxCompute(原名ODPS)全套攻略(持续更新20171122)

  概况介绍 大数据计算服务(MaxCompute,原名ODPS,产品地址:https://www.aliyun.com/product/odps)是一种快速.完全托管的TB/PB级数据仓库解决方案.MaxCompute向用户提供了完善的数据导入方案以及多种经典的分布式计算模型,能够更快速的解决用户海量数据计算问题,有效降低企业成本,并保障数据安全.本文收录了大量的MaxCompute产品介绍.技术介绍,帮助您快速了解MaxCompute/ODPS. MaxCompute 2.0:阿里巴巴的大数

大数据时代商业银行数据挖掘攻略

大数据时代商业银行数据挖掘攻略 中国民生银行发展规划部   王彦博 大数据时代,对于商业银行而言,在不断完善计算机应用系统底层数据库群.操作数据存储.主数据存储.企业级数据仓库.数据集市等建设的基础上,网络爬虫.Hadoop.MapReduce.NoSQL.Lucene等技术拓宽了银行的数据掌控能力.当前,银行无论面对内部数据还是外部数据.结构性数据亦或非结构性数据,数据的产生.捕获.整合.存储.访问等技术均已日渐成熟.与此同时,数据的价值也随着数据生命周期的不断延伸而大幅提升. 大数据时代商业

jspSmartUpload上传下载全攻略

js|攻略|上传|下载 一.安装篇 jspSmartUpload是由www.jspsmart.com网站开发的一个可免费使用的全功能的文件上传下载组件,适于嵌入执行上传下载操作的JSP文件中.该组件有以下几个特点: 1.使用简单.在JSP文件中仅仅书写三五行JAVA代码就可以搞定文件的上传或下载,方便. 2.能全程控制上传.利用jspSmartUpload组件提供的对象及其操作方法,可以获得全部上传文件的信息(包括文件名,大小,类型,扩展名,文件数据等),方便存取. 3.能对上传的文件在大小.类

J2ME中的时间处理全攻略

攻略 时间处理在程序开发中相当常见,下面对于时间处理做一个简单的说明. 一.时间的表达方式时间在J2ME中有两种表达方式:1. 以和GMT1970年1月1号午夜12点和现在相差的毫秒数来代表这种方式适合比较两个时间之间的差值.2.  以对象的形式来表达二.时间处理的相关类时间处理在J2ME中涉及三个类:1.  System类long time = System. currentTimeMillis();使用该方法可以获得当前时间,时间的表达方式为上面提到的第一种. 2.  Date类Date d

jspSmartUpload上传下载全攻略(一)

js|攻略|上传|下载 一.安装篇 jspSmartUpload是由www.jspsmart.com 网站开发的一个可免费使用的全功能的文件上传下载组件,适于嵌入执行上传下载操作的JSP文件中.该组件有以下几个特点: 1.使用简单.在JSP文件中仅仅书写三五行JAVA代码就可以搞定文件的上传或下载,方便. 2.能全程控制上传.利用jspSmartUpload组件提供的对象及其操作方法,可以获得全部上传文件的信息(包括文件名,大小,类型,扩展名,文件数据等),方便存取. 3.能对上传的文件在大小.

jspSmartUpload上传下载全攻略(四)

js|攻略|上传|下载 四.文件下载篇 1.下载链接页面download.html 页面源码如下: <!--文件名:download.html作 者:纵横软件制作中心雨亦奇(zhsoft88@sohu.com)--><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>下载</title><meta

jspSmartUpload上传下载全攻略1

js|攻略|上传|下载 一.安装篇 jspSmartUpload是由www.jspsmart.com网站开发的一个可免费使用的全功能的文件上传下载组件,适于嵌入执行上传下载操作的JSP文件中.该组件有以下几个特点: 1.使用简单.在JSP文件中仅仅书写三五行JAVA代码就可以搞定文件的上传或下载,方便. 2.能全程控制上传.利用jspSmartUpload组件提供的对象及其操作方法,可以获得全部上传文件的信息(包括文件名,大小,类型,扩展名,文件数据等),方便存取. 3.能对上传的文件在大小.类

jspSmartUpload上传下载全攻略(三)

js|攻略|上传|下载 三.文件上传篇 ㈠ 表单要求 对于上传文件的FORM表单,有两个要求: 1.METHOD应用POST,即METHOD="POST". 2.增加属性:ENCTYPE="multipart/form-data" 下面是一个用于上传文件的FORM表单的例子: <FORM METHOD="POST" ENCTYPE="multipart/form-data" ACTION="/jspSmartU

jspSmartUpload上传下载全攻略2

js|攻略|上传|下载 C.下载文件常用的方法 1.setContentDisposition 作用:将数据追加到MIME文件头的CONTENT-DISPOSITION域.jspSmartUpload组件会在返回下载的信息时自动填写MIME文件头的CONTENT-DISPOSITION域,如果用户需要添加额外信息,请用此方法. 原型:public void setContentDisposition(String contentDisposition) 其中,contentDisposition