原文鏈接:[Node JS爬蟲:爬取瀑布流網(wǎng)頁高清圖]https://www.bougieblog.cn/blog/2018/05/16%20-%20Node%20JS%E7%88%AC%E8%99%AB%EF%BC%9A%E7%88%AC%E5%8F%96%E7%80%91%E5%B8%83%E6%B5%81%E7%BD%91%E9%A1%B5%E9%AB%98%E6%B8%85%E5%9B%BE.html)
靜態(tài)為主的網(wǎng)頁往往用get方法就能獲取頁面所有內(nèi)容。動(dòng)態(tài)網(wǎng)頁即異步請(qǐng)求數(shù)據(jù)的網(wǎng)頁則需要用瀏覽器加載完成后再進(jìn)行抓取。本文介紹了如何連續(xù)爬取瀑布流網(wǎng)頁。
在知乎提到python就必有一大幫人提起爬蟲,咱Node JS爬蟲也是非常簡(jiǎn)單的,和python相比僅僅是“異步”和“多線程”的性能對(duì)比而已。對(duì)python了解不多,故對(duì)此不做評(píng)價(jià)。
phantomjs是一個(gè)‘無殼’的chrome,具體安裝方法查看phantomjs.org。phantomjs提供命令行工具運(yùn)行,運(yùn)行需使用命令phantom xxx.js。使用phantom-node這個(gè)庫(kù)可以在Node Js中把玩phantomjs,這樣就可以使用pm2進(jìn)行進(jìn)程守護(hù)和負(fù)載均衡了。
目標(biāo)
爬取200張以上的1920*1080分辨率的動(dòng)漫壁紙,網(wǎng)頁是百度瀑布流圖片

方式
瀑布流是根據(jù)頁面滾動(dòng)位置來判斷是否繼續(xù)往下加載,故要利用phantomjs滾動(dòng)頁面來獲取更多圖片鏈接。單個(gè)圖片詳細(xì)頁面剛進(jìn)入時(shí)是壓縮過的圖片,這是百度優(yōu)化訪問速度的措施,等待幾秒圖片src就會(huì)替換成大圖的鏈接。因此,進(jìn)入圖片詳細(xì)頁時(shí)應(yīng)延遲幾秒再獲取圖片src,具體延遲幾秒視你網(wǎng)速而定。
步驟
獲取鏈接
首先利用phantom打開網(wǎng)頁
const phantom = require('phantom')
(async function() {
const instance = await phantom.create();
const page = await instance.createPage();
const status = await page.open(url);
const size = await page.property('viewportSize', {
width: 1920,
height: 1080
})
}())
獲取鏈接數(shù)量,不足200則滾動(dòng)網(wǎng)頁
// 添加一個(gè)延時(shí)函數(shù),等待頁面加載后再滾動(dòng)
function delay(second) {
return new Promise((resolve) => {
setTimeout(resolve, second * 1000);
});
}
async function pageScroll(i) {
await delay(5)
await page.property('scrollPosition', {
left: 0,
top: 1000 * i
})
let content = await page.property('content')
let $ = cheerio.load(content)
console.log($('.imgbox').length)
if($('.imgbox').length < 200) {
await pageScroll(++i)
}
}
await pageScroll(0)
提取圖片鏈接
let urlList = []
$('.imgbox').each(function() {
urlList.push('https://image.baidu.com'+$(this).find('a').attr('href'))
})
保存圖片
定義保存圖片的函數(shù)
const request = require('request')
const fs = require('fs')
function save(url) {
let ext = url.split('.').pop()
request(url).pipe(fs.createWriteStream(`./image/${new Date().getTime()}.${ext}`));
}
遍歷urlList,建議用遞歸遍歷,循環(huán)遍歷delay不起作用
async function imgSave(i) {
let page = await page.open(urlList[i])
delay(1)
let content = await page.property('content')
$ = cheerio.load(content)
let src = $('#currentImg').attr('src')
save(src)
if(i<urlList.length) {
await imgSave(++i)
}
}
await imgSave(0)
最后爬取結(jié)果如圖,都是高分辨率的,部分圖片做了防爬處理

完整代碼
const phantom = require('phantom')
const cheerio = require('cheerio')
const request = require('request')
const fs = require('fs')
function delay(second) {
return new Promise((resolve) => {
setTimeout(resolve, second * 1000);
});
}
let url = 'https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=index&fr=&hs=0&xthttps=111111&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E5%8A%A8%E6%BC%AB+%E5%A3%81%E7%BA%B8&oq=%E5%8A%A8%E6%BC%AB+%E5%A3%81%E7%BA%B8&rsp=-1'
function save(url) {
let ext = url.split('.').pop()
request(url).pipe(fs.createWriteStream(`./image/${new Date().getTime()}.${ext}`));
}
(async function() {
let instance = await phantom.create();
let page = await instance.createPage();
let status = await page.open(url);
let size = await page.property('viewportSize', {
width: 1920,
height: 1080
})
let $
async function pageScroll(i) {
await delay(1)
await page.property('scrollPosition', {
left: 0,
top: 1000 * i
})
let content = await page.property('content')
$ = cheerio.load(content)
if($('.imgbox').length < 200) {
await pageScroll(++i)
}
}
await pageScroll(0)
let urlList = []
$('.imgbox').each(function() {
urlList.push('https://image.baidu.com'+$(this).find('a').attr('href'))
})
async function imgSave(i) {
let status = await page.open(urlList[i])
await delay(1)
let content = await page.property('content')
$ = cheerio.load(content)
let src = $('#currentImg').attr('src')
save(src)
if(i<urlList.length) {
await imgSave(++i)
}
}
await imgSave(0)
await instance.exit()
}());
我的博客:www.bougieblog.cn,歡迎前來尬聊。