网页爬虫抓取百度图片( Control的异步和回调知识的逻辑 )

优采云 发布时间: 2022-01-18 12:10

  网页爬虫抓取百度图片(

Control的异步和回调知识的逻辑

)

  Node.js写爬虫的基本思路及抓取百度图片的例子分享

  更新时间:2016-03-12 17:32:27 作者:qiaolevip

  本篇文章主要介绍Node.js编写爬虫的基本思路和抓取百度图片的例子分享。作者提到了GBK转码需要特别注意的转码问题。有需要的朋友可以参考以下

  其实写爬虫的思路很简单:

  但是当我真正写这个爬虫的时候,还是遇到了很多问题(和我基础不够扎实,也没有认真研究过node.js有很大关系)。主要原因是node.js的异步和回调知识没有完全掌握,导致在编写代码的过程中走了不少弯路。

  模块化的

  模块化对于 node.js 程序非常重要。不能像写PHP一样把所有代码都扔到一个文件里(当然这只是我个人的恶习),所以有必要一开始就分析一下这个爬虫需要实现的功能。,大致分为三个模块。

  主程序,调用爬虫模块和持久化模块,实现完整的爬虫功能

  爬虫模块根据传入的数据发送请求,解析HTML并提取有用数据,返回一个对象

  持久性模块,接受一个对象并将其内容存储在数据库中

  模块化也带来了一个困扰我一个下午的问题:模块之间的异步调用导致数据错误。其实我还是不太明白是什么问题,因为脚本语言的调试功能不方便,所以还没有深入研究过。

  还有一点需要注意的是,在模块化的时候,尽量谨慎的使用全局对象来存储数据,因为可能你的模块的某个功能还没有结束,而全局变量已经被修改了。

  控制流

  这个东西很难翻译,直译就叫控制流(?)。众所周知,node.js的核心思想是异步,但是如果异步多了,就会有好几层嵌套,代码真的很难看。此时,您需要借助一些控制流模块重新排列逻辑。这里我们推荐 async.js(),它在开发社区中非常活跃且易于使用。

  async提供了很多实用的方法,我主要在写爬虫的时候使用

  这些控制流方式给爬虫的开发带来了极大的便利。考虑这样一个应用场景,需要向数据库中插入多条数据(属于同一个学生),并且需要在插入所有数据后返回结果,那么如何保证所有的插入操作都结束了? 它只能通过回调层来保证。使用 async.parallel 要方便得多。

  这里还要提一件事,本来是为了保证所有的insert都完成,这个操作可以在SQL层实现,也就是transaction,但是node-mysql在我使用的时候还是不能很好的支持transaction,所以只能用代码手动保证。

  解析 HTML

  解析过程中也遇到了一些问题,记录在这里。

  发送 HTTP 请求获取 HTML 代码最基本的方法是使用 node 自带的 http.request 函数。如果是抓取简单的内容,比如获取指定id元素的内容(常用于抓取商品价格),那么正则就足够完成任务了。但是对于复杂的页面,尤其是数据项很多的页面,使用 DOM 会更加方便和高效。

  node.js 的最佳 DOM 实现是cheerio()。其实,cheerio 应该算是 jQuery 的一个子集,针对 DOM 操作进行了优化和精简,包括了 DOM 操作的大部分内容,去掉了其他不必要的内容。使用cheerio,您可以像使用普通的jQuery 选择器一样选择您需要的内容。

  下载图片

  在爬取数据时,我们可能还需要下载图片。其实下载图片的方式和普通网页没有太大区别,但是有一点让我很苦恼。

  请注意下面代码中的起泡注释,这是我年轻时犯的错误......

  

var req = http.request(options, function(res){

//初始化数据!!!

var binImage = '';

res.setEncoding('binary');

res.on('data', function(chunk){

binImage += chunk;

});

res.on('end', function(){

if (!binImage) {

console.log('image data is null');

return null;

}

fs.writeFile(imageFolder + filename, binImage, 'binary', function(err){

if (err) {

console.log('image writing error:' + err.message);

return null;

}

else{

console.log('image ' + filename + ' saved');

return filename;

}

});

});

res.on('error', function(e){

console.log('image downloading response error:' + e.message);

return null;

});

});

req.end();

  GBK转码

  另一个值得解释的问题是node.js爬虫爬取GBK编码内容时的转码问题。其实这个问题很容易解决,只是新手可能会走弯路。这是所有的源代码:

  

var req = http.request(options, function(res) {

res.setEncoding('binary');

res.on('data', function (chunk) {

html += chunk;

});

res.on('end', function(){

//转换编码

html = iconv.decode(html, 'gbk');

});

});

req.end();

  我这里使用的转码库是iconv-lite(),完美支持GBK、GB2312等双字节编码。

  示例:爬虫批量下载百度图片

<p>

var fs = require('fs'),

path = require('path'),

util = require('util'), // 以上为Nodejs自带依赖包

request = require('request'); // 需要npm install的包

// main函数,使用 node main执行即可

patchPreImg();

// 批量处理图片

function patchPreImg() {

var tag1 = '摄影', tag2 = '国家地理',

url = 'http://image.baidu.com/data/imgs?pn=%s&rn=60&p=channel&from=1&col=%s&tag=%s&sort=1&tag3=',

url = util.format(url, 0, tag1, tag2),

url = encodeURI(url),

dir = 'D:/downloads/images/',

dir = path.join(dir, tag1, tag2),

dir = mkdirSync(dir);

request(url, function(error, response, html) {

var data = JSON.parse(html);

if (data && Array.isArray(data.imgs)) {

var imgs = data.imgs;

imgs.forEach(function(img) {

if (Object.getOwnPropertyNames(img).length > 0) {

var desc = img.desc || ((img.owner && img.owner.userName) + img.column);

desc += '(' + img.id + ')';

var downloadUrl = img.downloadUrl || img.objUrl;

downloadImg(downloadUrl, dir, desc);

}

});

}

});

}

// 循环创建目录

function mkdirSync(dir) {

var parts = dir.split(path.sep);

for (var i = 1; i

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线