字节笔记本字节笔记本

使用puppeteer爬取百度新闻

2021-06-28

Puppeteer 是一个由谷歌官方开发的 Node 库,用于通过 DevTools 协议控制 headless Chrome 或 Chromium,支持页面截图、PDF 生成、表单自动提交、UI 测试、性能分析等功能,适用于自动化测试和爬虫开发。

简介

puppeteer 是谷歌官方出品的一个通过 DevTools 协议控制 headless Chrome 的 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome,执行常见的操作,就像在真实的浏览器中一样,可以用来实现浏览器自动化测试或爬虫

puppeteer能做什么

  • 页面截图,生成页面 PDF

  • 抓取 SPA(单页应用)并生成预渲染内容(即“SSR”服务器端渲染)

  • 自动提交表单,进行 UI 测试,键盘输入等

  • 创建一个时时更新的自动化测试环境, 使用最新的 JavaScript 和浏览器功能直接在最新版本的 Chrome 中执行测试

  • 捕获网站的 timeline trace,用来帮助分析性能问题

  • 测试浏览器扩展

一些概念

headless模式:不显示浏览器界面控制浏览器

为什么要使用headless模式? 在一些本身就没有安装桌面应用程序的操作系统可以使用headless模式进行浏览器的控制,而不需要界面的支持

实例

1.初始化项

mkdir baidu-news-spider
cd baidu-news-spider
npm init -y

2.安装相关的依赖

npm install puppeteer

3.创建index.js,编写爬虫代码

//引入puppeteer
const puppeteer = require('puppeteer');
//引入node文件系统模块(fs)
const fs = require('fs');
//引入node文件路径模块(path)
const path = require('path');
//创建爬取数据的函数
let getNewList = async () => {
  //创建一个Browser(浏览器)实例
  const browser = await puppeteer.launch();
  //在浏览器中创建一个新的页面
  const page = await browser.newPage();
  //打开百度新闻页面
  await page.goto('http://news.baidu.com/');
  //等待“国内”导航按钮出现
  await page.waitForSelector('#channel-all > div > ul > li:nth-child(3) > a');
  //点击“国内”导航按钮,进入国内新闻页面
  await page.click('#channel-all > div > ul > li:nth-child(3) > a');
  //等待“即时新闻列表”出现
  await page.waitForSelector('#instant-news > ul');
  //通过evaluate函数执行自定义的js代码获取要爬取的数据
  const newList = await page.evaluate(() => {
    //创建一个空数组接收爬取的数据
    let data = [];
    //获取所有即时新闻列表li元素
    let elements = document.querySelectorAll('#instant-news > ul > li');
    //利用循环将即时新闻列表的标题和链接地址添加到一个数组中
    for (let i = 0; i < elements.length; i++) {
      //获取新闻的标签
      let title = elements[i].innerText;
      //获取新闻的链接地址
      let url = elements[i].firstChild.getAttribute('href');
      //将获取到的标题和链接地址添加到数组中
      data.push({
        title,
        url,
      });
    }
    //返回数组
    return data;
  });
  //关闭浏览器实例
  await browser.close();
  //返回爬取的数据
  return newList;
};
//执行函数获取爬取的数据
getNewList().then((res) => {
  //将爬取的数据转为json格式
  let list = JSON.stringify(res);
  //指定存储数据的json文件
  let file = path.join(__dirname, 'newList.json');
  //将爬取的数据写入json文件
  fs.writeFile(file, list, (err) => {
    if (err) {
      console.log(err);
    } else {
      console.log('success');
    }
  });
});

4.运行

node index.js