扯淡
本文来源于视频 从零开始写一个 nodejs 爬虫
逻辑
- 声明起始 Url
- 获取页面数组
- 遍历页面数组,在每个页面获取所有图链数组
- 遍历图链数组,下载图片
关键 API
页面请求响应
request 函数可以发出网址,接收响应字符串
request(网址, function(err, response) {
console.log(response) // response 就是响应字符串
})
下载图片
注:图片地址如果包含文件夹,必须是存在的文件夹
request.pipe(fs).on注 2:此处最好分离 request(网络地址),以监听错误
request(网络地址).pipe(fs.createWriteStream(图片地址))
.on('close', function() {
console.log(`${name} 下载成功`)
callback()
})
cheerio 解析页面元素
cheerio 可以把响应字符串用 jQuery 解读
var $ = cheerio.load(response.body) // request 函数中的 response.body 是字符串
var imgs = $('img')
imgs.each(function() {
console.log($(this).attr('src'))
})
async.mapLimit
遍历请求页面,图片下载
async(目标数组, 最大请求并发数, 回调)
这个函数类似于 for, forEach,用它的目的是控制请求并发数,以免被限制 ip
async.mapLimit(pageUrl, 5, function(page, cb) {
request(page, function(err, response) {})
})
async.mapLimit(imgArr, 5, function(src, callback) {
request(src).pipe(...).on('close', ...)
})
细节
图片网址解析图片名
注1:正则表达式的值不是字符串
注2:字符串.match(reg) 的结果如果不存在,值为 null(不为[])
function getName(src) {
var reg = /(\w)+.(jpg|png|gif)/g
var result = src.match(reg)
if(result) {
return result[0]
}
return parseInt(Math.random() * 100000000) + '.jpg'
}
代码
var fs = require('fs')
var cheerio = require('cheerio')
var request = require('request')
var async = require('async')
var startUrl = 'https://danbooru.donmai.us/posts'
function getName(src) {
var reg = /(\w)+.(jpg|gif|png)/g
var result = src.match(reg)
if(result) {
return result[0]
}
return parseInt(Math.random() * 1000) + '.jpg'
}
request(startUrl, function(err, response) {
if(err) {
console.log(err)
}
var $ = cheerio.load(response.body)
var amount = parseInt($('.more').prev().text() || $('.arrow').prev().text())
var pageUrl = []
for(var i=1; i<=amount; i++) {
pageUrl.push(`https://danbooru.donmai.us/posts?page=${i}`)
}
async.mapLimit(pageUrl, 5, function(page, callback) {
request(page, function(err, response) {
if(err) {
console.log(err)
}
var $ = cheerio.load(response.body)
var imgs = $('picture >img')
var imgArr = []
imgs.each(function() {
imgArr.push($(this).attr('src'))
})
async.mapLimit(imgArr, 5, function(src, callback) {
var name = getName(src)
request(src).pipe(fs.createWriteStream('./img/' + name))
.on('close', function() {
console.log(name + '下载成功')
callback()
})
})
callback()
})
})
})
补充
爬取 anime-share 的图片时遇到了 unhandled xx 的问题
解决办法在这里找到:stackoverflow
更改原来的图片下载语句,分离出 request() 语句监听错误即可
var readStream = request(src)
readStream.on('error', function(err) {
console.log(src, err)
})
readStream.pipe(fs.createWriteStream('./hentai/' + name))
.on('close', function() {
console.log(name + '下载成功')
callback()
})
暂无评论