开发者社区> sp42> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

爬虫攻略(一)

简介: 互联网 Web 就是一个巨大无比的数据库,但是这个数据库没有一个像 SQL 语言可以直接获取里面的数据,因为更多时候 Web 是供肉眼阅读和操作的。如果要让机器在 Web 取得数据,那往往就是我们所说的“爬虫”了。
+关注继续查看

互联网 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);
})

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
新浪微博小爬虫
一直琢磨着写个爬虫玩,上学期都没实行,于是花了大概一天写了这个东西。其实半天就把程序调试好了,可是在往mysql数据库里保存数据的时候出了问题。 python的中文编码实在是非常麻烦,不光如此,因为有些用户的简介里有一些特殊符号,®或者笑脸之类的,于是在这里纠结了很久,好歹最后是成功了(其实也就是过...
2891 0
关于爬虫,首篇
补充基础知识 爬虫,毋庸置疑就是爬去互联网的网页,理论上,只要是互联网中存在的web页面,都可以爬取。用来做数据采集非常合适,尤其是现在大数据领域,爬虫必不可少。
969 0
网络爬虫的实现
作者:Gupta, P. ; Johari, K. ; Linagay's Univ., India 文章发表在:  Emerging Trends in Engineering and Technology (ICETET), 2009 2nd International Conference on            pages 838~844 摘要-万维网是一个通过HTML格式使数十亿的文件产生联系的集合 ,然后如此规模庞大的数据已经成为信息检索的障碍,用户为了查找自己想要的资料可能要翻转数页。
685 0
网络爬虫基本原理(一)
网络爬虫是捜索引擎抓取系统的重要组成部分。爬虫的主要目的是将互联网上的网页下载到本地形成一个或联网内容的镜像备份。这篇博客主要对爬虫以及抓取系统进行一个简单的概述。 一、网络爬虫的基本结构及工作流程     一个通用的网络爬虫的框架如图所示:     网络爬虫的基本工作流程如下:     1.首先选取一部分精心挑选的种子URL;     2.将这些URL放入待抓取URL队列;     3.从待抓取URL队列中取出待抓取在URL,解析DNS,并且得到主机的ip,并将URL对应的网页下载下来,存储进已下载网页库中。
820 0
网络爬虫-原理篇(一)
  引入:我们在百度首页输入关键字,百度一下,相关的内容就会立马呈现出来,这个动作的背后到底隐藏着哪些操作?   其实百度的核心搜索引擎就是一个大型的分布式网络爬虫程序。   什么是网络爬虫? 详见:   1.百度百科   2. 维基百科   网络爬虫的主要目的是将互联网上的网页下载到本地形成一个或联网内容的镜像备份。
1380 0
+关注
sp42
移动项目技术负责人。多年全栈经验,熟悉 Java 和 JS,CSDN 博客技术专家,著有《ExtJS 详解与实践》等书。
294
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载