NodeJS 使用 puppeteer 爬取百度文库免费文档

2019-08-24  本文已影响0人  了凡和纤风
所需环境

 
 

爬取前的一点分析

爬取一个东西首先要知道他是如何加载的

  1. 加载更多按钮


    加载更多

这个比较简单 使用 puppeteer 判断 然后模拟点击即可

  1. 滚动加载
    说滚动加载其实并不准确,百度文库的文章,类似于只显示 当前视口的范围 正负多一点。就算前面已经加载过了的内容,当你 将页面的滚动条向下 滚动时,如果离开先前视口的距离过多,那么上面的内容又会隐藏掉。


    图示

类似于这张图, 页面显示的内容只有 绿色的区域,随着 红色的区域(视口)的变化,绿色的区域也会变化。

所以这里的思路是,首先打开全部文档(点击加载更多按钮),其次,让滚动条滚动到顶部,然后定时每次向下滚动一定的距离(这样就可以获取当前这一段显示的文档),最后再见获取到的所有DOM结构进行 拼合 去重(获取会有重复的结构)

代码:
const puppeteer = require('puppeteer') // 加载模板

;(async () => {
  const browser = await puppeteer.launch({ // 创建 browser 实例
    // headless: false
  })
  const page = await browser.newPage() // 创建 page 实例



  await page.goto('https://wenku.baidu.com/view/9ec3d0e0571252d380eb6294dd88d0d233d43ce5.html') // 输入导航的网址(百度文库地址)

  console.log('go to https://....') 
  // 设置 屏幕视口
  await page.setViewport({ 
    width: 1024,
    height: 600,
    deviceScaleFactor: 3
  })
  
  
  if (await page.$('span.moreBtn')) { // 判断是否在加载更多按钮

    console.log('click loadMore')
    await page.waitForSelector('span.moreBtn') 
    await page.click('span.moreBtn')
    await page.waitFor(4000) // 等待文档加载,可根据网络环境更改 时间
    console.log('loading done, Crawling doc...')
  }

  const result = await page.evaluate(async () => { // 浏览器上下文环境
  
    const $ = window.$ // 获取 jQ 
    let items = []
    for(let i = 0; i < document.body.scrollHeight; i+=1000) { // 滚动加载,每次滚动 1000px
      console.log(document.body.scrollHeight) 
      window.scrollTo(0, i)
  
      await async function sleep() { // 每次滚动后 等待一秒
        return new Promise(reject => setTimeout(reject, 1000))
      }();

      // 拼合数组
      items = Array.prototype.concat.apply(items, $('p.reader-word-layer')) // 滚动加载 获取文本
    }

    // await async function sleep() {
    //   return new Promise(reject => setTimeout(reject, 1000))
    // }();

    const list = Array.from(new Set(items)) // 数组去重

    let html = ''
    for(let i = 0; i < list.length; i++){ // 迭代 获取文本
      html += list[i].innerText
    }

    // 返回获取的文本
    return html
  })
    
    // 输出
    console.log(result)
    await browser.close()
})();
输出结果

对应的文章越长需要等待的时间越久。

如果想更好的看到这个过程,可以将 headless 设置为 false,显示浏览器爬取的过程

  // ...
  const browser = await puppeteer.launch({ // 创建 browser 实例
    headless: false
  })
  // ...

至此一个简单的爬虫就书写完毕了。

上一篇 下一篇

猜你喜欢

热点阅读