1. 程式人生 > 實用技巧 >使用nodejs爬取圖片

使用nodejs爬取圖片

在執行程式碼前,請確保本機是否有nodejs環境

1 D:\ > node -v
2 v12.1.0 //版本號

需要用到的包

axios //請求頁面
cheerio // 把get請求的頁面 可以使用jq的方法來獲取dom
fs // 檔案讀寫模組
request  // 請求模組 用來請求下載地址
path // 路徑模組
url // 路由模組

爬蟲遵循的規則

  1. 遵守 Robots 協議,謹慎爬取
  2. 限制你的爬蟲行為,禁止近乎 DDOS 的請求頻率,一旦造成伺服器癱瘓,約等於網路攻擊
  3. 對於明顯反爬,或者正常情況不能到達的頁面不能強行突破,否則是 Hacker 行為
  4. 如果爬取到別人的隱私,立即刪除,降低進局子的概率。另外要控制自己的慾望

本次案例百度圖片表情包

  1 const axios = require("axios")
  2 const cheerio = require("cheerio")
  3 const fs = require('fs');
  4 const request = require("request");
  5 const path = require('path');
  6 const url = require("url")
  7 
  8 /**
  9  * 休眠方法,因為一次訪問太多次目標網址會被拉黑
 10  * @param {Number} time 休眠時間以毫秒為單位
11 * @returns Promise 12 */ 13 const sleep = time => { 14 return new Promise(function (resolve, reject) { 15 setTimeout(function () { 16 resolve(); 17 }, time); 18 }) 19 } 20 21 /** 22 * 爬取某個地址下的img 圖片 23 * @param {String} httpUrl 目標地址 24 * @param {Boolean} isBaidu 是否為百度圖片地址
25 */ 26 async function start(httpUrl, isBaidu) { 27 28 // 獲取目標網址的dom節點,使用jq的方法來獲取dom節點 29 const { data } = await axios.get(httpUrl) 30 let img = []; 31 // 針對百度 進行爬取資料 32 if (isBaidu) { 33 img = getBaiDuImg(data) 34 } else { 35 const $ = cheerio.load(data) 36 // 根據dom獲取img src 37 $(".imgbox img").each(function () { 38 let src = dealImgUrl($(this).attr("src"), httpUrl) 39 img.push(src) 40 }) 41 } 42 43 // 檢測當前資料夾是否存在儲存圖片的資料夾 44 const random = parseInt(Math.random() * 100) 45 const dirPath = "./img" + random 46 if (!fs.existsSync(dirPath)) { 47 fs.mkdirSync(dirPath) 48 } 49 50 51 /** 52 * 在這裡為什麼不使用forEach遍歷? 答案在下方連結 53 * https://blog.csdn.net/yumikobu/article/details/84639025 54 */ 55 for (let i = 0; i < img.length; i++) { 56 const item = img[i] 57 await sleep(1500) 58 const extname = path.extname(item) || '.jpg' 59 console.log(item + "開始下載"); 60 const filename = (i + 1) + extname 61 const write = fs.createWriteStream(dirPath + "/" + filename) 62 const read = request(item) 63 read.pipe(write) 64 console.log(item + "本地下載結束"); 65 } 66 67 68 console.log("爬取結束"); 69 } 70 71 /** 72 * 處理img的src 73 * @param {String} src 路徑 74 * @param {String} pathurl url地址 75 * @returns 返回圖片連結地址 76 */ 77 function dealImgUrl(src, pathurl) { 78 if (src.substr(0, 8) === 'https://' || src.substr(0, 7) === 'http://' || src.substr(0, 2) === "//" || src.substr(0, 5) === "data:") { 79 return src 80 } 81 return url.resolve(pathurl, src) 82 } 83 84 /** 85 * 86 * @param {String} str 百度返回的html字元 87 * @returns {Array} 返回圖片連結地址 88 */ 89 function getBaiDuImg(str) { 90 var reg = /app\.setData\(\'imgData\'\,\s+\{(.*?)\"data\":(.*?)\]\}/g 91 var result = reg.exec(str)[2] + ']' 92 result = result.replace(/\'/g, '"') 93 result = JSON.parse(result) 94 const img = [] 95 result.forEach(item => { 96 if (item.thumbURL) { 97 img.push(item.thumbURL) 98 } 99 }) 100 return img 101 } 102 103 const HTTPURL = "https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&sf=1&fmq=1389861203899_R&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&ala=6&ori_query=%E8%A1%A8%E6%83%85%E5%8C%85&fr=ala&ala=1&alatpl=adress&pos=2&oriquery=%E8%A1%A8%E6%83%85%E5%8C%85&alaTag=0&&word=%E8%A1%A8%E6%83%85%E5%8C%85%20%E6%90%9E%E7%AC%91&hs=2&xthttps=111111" 104 105 // 呼叫start 函式 開始進行爬取 106 start(HTTPURL, true)

仔細分析了一下,百度圖片並不是在請求頁面的時候就把圖片的資料渲染到dom上了,而是通過js指令碼創建出img的.所以使用正則匹配到img的資料,就可以知道圖片連結地址了.

若是一般常規的網站圖片 可以使用cheerio來操作dom獲取圖片路徑地址

在程式碼裡使用了一個sleep函式就是為了多次訪問網站防止被拉黑,請勿頻繁請求!

在爬取個別頁面需要配置請求頭或者https證書還須自行網上查閱方法.