`Node`+`puppteer`实现网络图片爬取

1,581 阅读2分钟

Node+puppteer实现网络图片爬取

一、项目搭建

1. 初始化项目
npm init -y
2. 安装依赖
npm install -s puppeteer
3. 目录结构
├─node_modules
├─package-lock.json
├─package.json
├─README.md
└─src
    ├─index.js
    ├─imgs
    └─utils
      └─srcToImg.js

二、功能实现

1. 图片DOM元素获取
// src/index.jsconst puppeteer = require('puppeteer')
const path = require('path')
const srcToImg = require('./utils/srcToImg')
​
;(async function () {
  // 创建一个browser对象
  // const browser = await puppeteer.launch({
  //   slowMo: 50, // 延时500ms,方便观察
  //   devtools: true // 打开控制台
  // })
  const browser = await puppeteer.launch()
  // 创建page
  const page = await browser.newPage()
  // 跳转到对应网址
  await page.goto('https://image.baidu.com')
  // 通过当前网页中input标签的id选中改元素,然后聚焦
  await page.focus('#kw')
  // 模拟键盘输入关键字
  await page.keyboard.sendCharacter('雷姆 3840*1080')
  // 通过类名获取点击搜索按钮并触发点击事件进行搜索
  await page.click('.s_newBtn')
  // 页面完成加载时触发
  page.on('load', async function() {
    // 传入的回调可在页面实例上下文中执行
    const sources = await page.evaluate(async () => {
      // 通过类名获取所有image标签
      const images = document.getElementsByClassName('main_img')
      // 返回所有image标签的src属性数组
      return [...images].map(img => img.src)
    })
​
    for(let src of sources) {
      await srcToImg(src, path.resolve(__dirname, 'imgs'))
      // 关闭
    }
    await browser.close()
  })
})()
  • 首先引入所需模块
  • 使用puppteer创建一个browser对象
  • 利用browser对象创建一个page
  • 跳转到对应网址
  • 查询到input框的id,并通过id获取到该DOM元素并聚焦
  • 模拟键盘输入查询关键字
  • 查询到搜索按钮的类名,并通过类名获取到该DOM元素,同时触发点击搜索事件
  • 监听网页加载完成事件,并在网页加载完成之后,通过page.evaluate方法传入回调,该回调可在可在页面实例上下文中执行
  • 通过类名获取所有image标签,并返回包含所有image标签的src属性值的数组
  • 遍历数组,调用srcToImg方法下载图片到imgs文件夹下
  • 下载完毕后,关闭浏览器页面
2. 图片下载到本地
// src/utils/srcToImgconst http = require('http')
const https = require('https')
const path = require('path')
const { promisify } = require('util')
const { createWriteStream, writeFile } = require('fs')
​
const myWriteFile = promisify(writeFile)
​
module.exports = async function(src, dir) {
  // 匹配以jpg|jpeg|png|gif结尾的字符串
  const reg = /.(jpg|jpeg|png|gif)$/
  // 说明是图片地址
  if (reg.test(src)) {
    await urlToImg(src, dir)
  } else { // 说明是base64编码图片
    await base64ToImg(src, dir)
  }
}
// 将网络图片存在images文件夹
const urlToImg = async (url, dir) => {
  // 匹配以https开头的字符串
  const reg = /^https:/
  // 拿到url后缀名
  const ext= path.extname(url)
  const file = path.join(dir, `${ Date.now() }${ ext }`)
  const module= reg.test(url) ? https : http
​
  module.get(url, res => {
    res.pipe(createWriteStream(file))
       .on('finish', () => {
         console.log('写入完成')
       })
  })
}
// 将base64图片存在images文件夹
const base64ToImg = async (str, dir) => {
  // data:image/jpeg;base64,......................................
  const reg = /^data:(.+);base64,(.+)$/
  const matches = str.match(reg)
  try {
    // image/jpeg => jpeg => jpg
    const ext = matches[1].split('/')[1].replace('jpeg', 'jpg')
    const file = path.join(dir, `${ Date.now() }.${ ext }`)
  
    await myWriteFile(file, matches[2], 'base64')
  } catch (err) {
    console.log('非法的base64')
  }
}
  • 图片有两种类型,一种是图片链接,一种是base64编码图片,所以需要通过正则判断并分开处理
  • 如果是图片链接,则调用urlToImg方法,该方法会根据httphttps,分别调用该模块的get方法,获取图片资源,并写入到imgs文件夹
  • 如果是base64图片,则调用base64ToImg方法,该方法会使用正则匹配出base64图片的前缀和图片数据,并将图片数据写入到imgs文件夹