前端爬数据当接口 你还在一个一个的写json数据吗?详细教学

3,764 阅读5分钟

会用node进行爬数据吗?

image.png

爬数据之前先浅聊一下Node.js

Node.js 是一个开源和跨平台的 JavaScript 运行时环境。 Node.js 在浏览器之外运行 V8 JavaScript 引擎(Google Chrome 的内核)。Node.js 应用程序在单个进程中运行,无需为每个请求创建新的线程。 Node.js 在其标准库中提供了一组异步的 I/O 原语,以防止 JavaScript 代码阻塞,通常,Node.js 中的库是使用非阻塞范式编写的,使得阻塞行为成为异常而不是常态。当 Node.js 执行 I/O 操作时(比如从网络读取、访问数据库或文件系统),Node.js 将在响应返回时恢复操作(而不是阻塞线程和浪费 CPU 周期等待)。

别急,再谈一下爬虫

网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定规则,自动的抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。

在生活中网络爬虫经常出现,搜索引擎就离不开网络爬虫。例如,百度搜索引擎的爬虫名字叫作百度蜘蛛(Baiduspider)。百度蜘蛛,是百度搜索引擎的一个自动程序。它每天都会在海量的互联网信息中进行爬取,收集并整理互联网上的网页、图片视频等信息。当用户在百度搜索引擎中输入对应的关键词时,百度将从收集的网络信息中找出相关的内容,按照一定的顺序将信息展现给用户。

开启实战,爬豆瓣网的数据

前端爬数据主要是通过爬取请求地址网页的html,然后将html进行解析,拿取我们的需要的数据的节点。

平常大家都是看到python爬虫,搞个请求头,模拟用户进行爬数据。

在node里,有个属于前端人的高科技,cheerio

cheerio:

cheerio是jquery核心功能的一个快速灵活而又简洁的实现,主要是为了用在服务器端需要对DOM进行操作的地方。 大家可以简单的理解为用来解析html非常方便的工具。

cheerio你可以使用该cheerio.load方法加载标记。该方法将标记作为参数。它还需要另外两个可选参数。如果你有兴趣,可以在文档中阅读有关它们的更多信息。

Cheerio 和 Web 浏览器之间的主要区别在于,cheerio 不生成视觉渲染、加载 CSS、加载外部资源或执行 JavaScript。它只是解析标记并提供用于操作生成的数据结构的 API。

我们在使用之前只需要在终端安装即可 npm i cheerio。不过在这之前,更重要的是拿到请求的url的数据。如果你想使用cheerio 来抓取网页,您需要首先使用axiosnode-fetch等包来获取标记。我这里使用request-promise,它是服务端发起请求的工具包

爬到了数据我们肯定要把它存起来,这里我采用了fs

写入文件最简单的方式是使用fs.writeFile() API

详情看node 官方 Node.js

这是官方文档
const fs = require('fs')

const content = '一些内容'

fs.writeFile('/Users/joe/test.txt', content, err => {
  if (err) {
    console.error(err)
    return
  }
  //文件写入成功。

正式开启爬数据的教程

1. 首先我们先初始化项目

利用npm init -y初始化项目,然后可以之后安装的依赖都放到这里。

npm init -y

2. 然后安装好我们之后所需要的依赖

安装好我们所要的依赖

npm i request-promise
npm i cheerio

3. 准备好所有引入

let request = require('request-promise')
let fs = require('fs') // 后端 操作系统 I/O 网络 硬件  前端 浏览器
const cheerio = require('cheerio')
let url = 'https://movie.douban.com/top250'

4. 请求数据

在这里我把所有东西都放在了main这个函数里。
同时在这里我定义了一个空数组 存取电影信息。
let movies = []
const main = async () => {
let html = await request({
        url
    })
}

5. 在Cheerio 中加载标记

我们传递第一个也是唯一需要的参数,并将返回值存储在$变量中。我们使用该变量是因为cheerio 与Jquery$的相似性。如果你愿意,可以使用不同的变量名。

 let $ = cheerio.load(html) // 内存中构造一个DOM树  VDOM

6.在 Cheerio 中选择元素

Cheerio 支持大多数常见的 CSS 选择器,例如classidelement选择器等。在下面的代码中,我们选择元素#content .article .grid_view 然后将所选元素记录到控制台。

image.png

我们要拿的数据就在这个item里,利用find找到所有#content .article .grid_view 下的item。

 let movieNodes = $('#content .article .grid_view').find('.item')

7. 开始拿取数据

image.png

for 循环 遍历 movieNodes 拿到每一个 item

 for (let movieNode of movieNodes) {
         // 将item 设置为加载标记
        let $ = cheerio.load(movieNode) 
        // 拿取 item 下的 info hd 下的 所有sapn
        let titles = $('.info .hd span ')
       
        // titles 不一定为数组,可能是类数组  无法调用map 用call 强制this
        titles = [].map.call(titles, t => {
             // 调用jQuery 里的方法text 拿取文字 
             // 同时调用正则表达式去掉换行和空格
            return $(t).text().replace(/[ ]|[\r\n]/g,"")
        })
        // console.log(titles);
        // 拿取 item 下的 info 的bd 元素
        let bd = $('.info .bd')
         // 拿取 item 下的 info 的bd 里的 p 中的文字
        let info = bd.find('p').text().replace(/[ ]|[\r\n]/g,"")
         // 拿取 .star下 .rating_num 中的评分文字
        let score = bd.find('.star .rating_num').text()
        if (titles.length) 
        // 将数据存取到 movies数组里
            movies.push(({titles, info, score}))
    }

8. 将数据存放起来

  1. 利用fs.writeFile方法将movies 中的数据存放起来 自动在根目录下生成一个output.json文件。

  2. 利用JSON.stringify将movies格式化一下满足json文档。

  3. utf-8确保汉字能够显示不会乱码

 fs.writeFile('./output.json', JSON.stringify(movies), 'utf-8', () => {
        console.log('生成json文件成功');
    })

9. 效果展示

[
    {
        "titles": [
            "肖申克的救赎",
            " / The Shawshank Redemption",
            " / 月黑高飞(港)  /  刺激1995(台)",
            "[可播放]"
        ],
        "info": "导演:弗兰克·德拉邦特FrankDarabont   主演:蒂姆·罗宾斯TimRobbins/...1994 / 美国 / 犯罪剧情希望让人自由。",
        "score": "9.7"
    },
    {
        "titles": [
            "霸王别姬",
            " / 再见,我的妾  /  Farewell My Concubine",
            "[可播放]"
        ],
        "info": "导演:陈凯歌KaigeChen   主演:张国荣LeslieCheung/张丰毅FengyiZha...1993 / 中国大陆中国香港 / 剧情爱情同性风华绝代。",
        "score": "9.6"
    },
  
    },
  ....
]

10. app.js完整代码

let request = require('request-promise')
let fs = require('fs') // 后端 操作系统 I/O 网络 硬件  前端 浏览器
const cheerio = require('cheerio')
let url = 'https://movie.douban.com/top250'
let movies = []
const main = async () => {
    let html = await request({
        url
    })
    // console.log(html);
    let $ = cheerio.load(html) // 内存中构造一个DOM树  VDOM
    let movieNodes = $('#content .article .grid_view').find('.item')
    // console.log(movieNodes);
    for (let movieNode of movieNodes) {
        let $ = cheerio.load(movieNode)
        let titles = $('.info .hd span ')
        // console.log(Object.prototype.toString.call(titles));
        // titles 不为数组 无法调用 map 用call
        titles = [].map.call(titles, t => {
            return $(t).text()
        })
        // console.log(titles);
        let bd = $('.info .bd')
        let info = bd.find('p').text().replace(/[ ]|[\r\n]/g,"")
        let score = bd.find('.star .rating_num').text()
        if (titles.length)
            movies.push(({titles, info, score}))
    }
    // console.log(movies);
    fs.writeFile('./output.json', JSON.stringify(movies), 'utf-8', () => {
        console.log('生成json文件成功');
    })
}

main()