Skip to content

js爬虫

js爬虫的原理

js爬虫的原理

  • 通过模拟浏览器(需要配置相应的请求头)发送请求,请求完整html文件,
  • 然后通过html文件的内容,解析出需要的数据。

TIP

可以通过node-fetchaxios库发送请求,cheerio库解析网页内容。

cheerio的原理

cheerio 是一个用于在服务器端解析 HTML 的库,它提供了类似 jQuery 的语法,可以方便地操作 DOM 元素。

cheerio 会将获取的网页数据(字符串-html文件)解析成类似浏览器dom对象的数据,然后通过类似jQuery的方式操作dom对象,从而获取到需要的数据。

相比python爬虫的优势

对于前端开发者来说,js解析网页内容具有先天优势(dom的操作,获取标签内部的数据),理论上在浏览器中可以看到的内容都可以使用js轻松获取到,并提取出来。

一个简单的爬虫

通过以下示例,可以实现一个简单的爬虫,爬取网站上的图片链接,并保存到本地json文件中。

目录结构:

first-clawler
├── node_modules
├── file.js
├── img.json
├── index.js
├── package.json
├── package-lock.json
└── preview.html

代码示例

index.js

js
import fetch from 'node-fetch';
import * as cheerio from 'cheerio';
import file from './file.js';


const baseUrl = "https://pic.netbian.com/4kdongman"
const filePath = "./img.json"
const imgList = []

/**
 * 
 * @param {number} num 获取的图片的页数
 */

function getImgList(num) {
  let i = 2
  let url = `${baseUrl}/index.html`
  requestData(url)
  while (i <= num) {
    url = `${baseUrl}/index_${i}.html`
    requestData(url)
    i++;
  }

}


/**
 * 
 * @param {string} url 请求地址 
 */

function requestData(url) {
  fetch(url)
    .then(res => res.text())
    .then(data => {
      const $ = cheerio.load(data)
      $('.slist ul li').each((index, element) => {
        const img = $(element).find('a img').attr('src')
        imgList.push("https://pic.netbian.com" + img)
        console.log(`正在获取第${index + 1}图片`)
      })
      file(filePath, imgList)
    })
}
getImgList(8)

file.js

js
import fs from 'fs'

/**
 * @param {string} path 文件路径
 * @param {Array} newData 新增的数据
 * @returns {boolean} 文件写入成功返回true,失败返回false
 * 
 * 先读取原内容,然后添加新的内容,最后再写回文件
 */
export default function file(path,newData){
  let oldData = [],resultData = []
  fs.readFile(path, 'utf-8', (err, data) => {
    if (err) {
      console.log(err)
      return false
    } else {
      if(data) oldData = JSON.parse(data)
    }
    if(oldData) resultData = [...oldData,...newData ]
    else resultData =[...newData]
    fs.writeFile(path, JSON.stringify(resultData) , (err) => {
      if (err) {
        console.log(err)
        return false
      } else {
        console.log('done')
      }
    })
  })
  return true
}

// file('./img.json',[])

preview.html

html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>预览图片</title>
</head>

<body>

  <script>
    fetch("./img.json")
      .then(response => response.json())
      .then(data => {
        const imgContainer = document.createElement('div');
        imgContainer.style.display = 'flex';
        imgContainer.style.flexWrap = 'wrap';
        imgContainer.style.maxWidth = '100%';
        imgContainer.style.overflow = 'auto';

        data.forEach(img => {
          const imgElement = document.createElement('img');
          imgElement.src = img;
          imgElement.style.width = '100px';
          imgElement.style.height = '100px';
          imgElement.style.margin = '5px';
          imgElement.style.objectFit = 'cover';
          imgContainer.appendChild(imgElement);
        })
        document.body.appendChild(imgContainer);
      })
  </script>
</body>

</html>

package.json

json
{
  "name": "first-clawler",
  "version": "1.0.0",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "start": "node index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": "",
  "dependencies": {
    "cheerio": "^1.0.0",
    "node-fetch": "^3.3.2"
  }
}