使用nodejs爬取圖片

在運行代碼前,請確保本機是否有nodejs環境html

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     fs.writeFileSync("./data.json", JSON.stringify(img), "utf-8")
 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 
 59         console.log(item + "開始下載");
 60         // const extname = path.extname(item) || '.jpg'
 61         // const filename = (i + 1) + extname
 62         let myUrl = new URL(item)  // node vision must v10 up! 
 63         let httpUrl = myUrl.origin + myUrl.pathname
 64         let filename = i + path.basename(httpUrl)
 65         const write = fs.createWriteStream(dirPath + "/" + filename)
 66         request.get(item).on('error', function (err) {
 67             console.log(item + "下載失敗", err);
 68         }).pipe(write)
 69         console.log(item + "本地下載結束");
 70     }
 71 }
 72 process.on("exit", () => {
 73     console.log("爬取結束");
 74 })
 75 /**
 76  * 處理img的src
 77  * @param {String} src 路徑
 78  * @param {String} pathurl url地址
 79  * @returns 返回圖片連接地址
 80  */
 81 function dealImgUrl(src, pathurl) {
 82     if (src.substr(0, 8) === 'https://' || src.substr(0, 7) === 'http://' || src.substr(0, 2) === "//" || src.substr(0, 5) === "data:") {
 83         return src
 84     }
 85     return url.resolve(pathurl, src)
 86 }
 87 
 88 /**
 89  * 
 90  * @param {String} str 百度返回的html字符 
 91  * @returns {Array} 返回圖片連接地址
 92  */
 93 function getBaiDuImg(str) {
 94     var reg = /app\.setData\(\'imgData\'\,\s+\{(.*?)\"data\":(.*?)\]\}/g
 95     var result = reg.exec(str)[2] + ']'
 96     result = result.replace(/\'/g, '"')
 97     result = JSON.parse(result)
 98     const img = []
 99     result.forEach(item => {
100         if (item.objURL) {
101             img.push(item.objURL)
102         }
103     })
104     return img
105 }
106 // const HTTPURL = "https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&sf=1&fmq=1605517415488_R&pv=&ic=0&nc=1&z=&hd=&latest=&copyright=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&hs=2&sid=&word=%E7%94%B5%E8%84%91%E5%A3%81%E7%BA%B8++%E6%A2%85%E8%A5%BF"
107 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"
108 // 開始調用start函數進行爬取圖片
109 start(HTTPURL, true)

 

仔細分析了一下,百度圖片並非在請求頁面的時候就把圖片的數據渲染到dom上了,而是經過js腳本建立出img的.因此使用正則匹配到img的數據,就能夠知道圖片連接地址了.

百度圖片表情包

 

百度圖片html代碼分析

 

如果通常常規的網站圖片 可使用cheerio來操做dom獲取圖片路徑地址

 

在代碼裏使用了一個sleep函數就是爲了屢次訪問網站防止被拉黑,請勿頻繁請求!

 

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

相關文章
相關標籤/搜索