原文連結:Node JS爬蟲:爬取瀑布流網頁高清圖
靜態為主的網頁往往用get方法就能獲取頁面所有內容。動態網頁即非同步請求資料的網頁則需要用瀏覽器載入完成後再進行抓取。本文介紹瞭如何連續爬取瀑布流網頁。
在知乎提到python
就必有一大幫人提起爬蟲,我們Node JS
爬蟲也是非常簡單的,和python
相比僅僅是“非同步”和“多執行緒”的效能對比而已。對python
瞭解不多,故對此不做評價。
phantomjs是一個‘無殼’的chrome
,具體安裝方法檢視phantomjs.org。phantomjs
提供命令列工具執行,執行需使用命令phantom xxx.js
。使用phantom-node
這個庫可以在Node Js
中把玩phantomjs
,這樣就可以使用pm2
進行程式守護和負載均衡了。
目標
爬取200張以上的1920*1080
解析度的動漫桌布,網頁是百度瀑布流圖片
方式
瀑布流是根據頁面滾動位置來判斷是否繼續往下載入,故要利用phantomjs
滾動頁面來獲取更多圖片連結。單個圖片詳細頁面剛進入時是壓縮過的圖片,這是百度優化訪問速度的措施,等待幾秒圖片src就會替換成大圖的連結。因此,進入圖片詳細頁時應延遲幾秒再獲取圖片src,具體延遲幾秒視你網速而定。
步驟
獲取連結
首先利用phantom開啟網頁
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
})
}())
複製程式碼
獲取連結數量,不足200則滾動網頁
// 新增一個延時函式,等待頁面載入後再滾動
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'))
})
複製程式碼
儲存圖片
定義儲存圖片的函式
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
,建議用遞迴遍歷,迴圈遍歷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)
複製程式碼
最後爬取結果如圖,都是高解析度的,部分圖片做了防爬處理
完整程式碼
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,歡迎前來尬聊。