使用docker puppeteer api 接口返回

梦想与她 提交于 2020-08-14 17:33:56

安装  安装docker,使用模拟手机访问

mkdir  /docker/puppeteer-renderer/src

目录中的代码有  index.js, renderer.js,wait-for-animations.js ,代码依次是 

'use strict'

const express = require('express')
const qs = require('qs')
const { URL } = require('url')
const contentDisposition = require('content-disposition')
const createRenderer = require('./renderer')

const port = process.env.PORT || 3000

const app = express()

let renderer = null

// Configure.
app.set('query parser', s => qs.parse(s, { allowDots: true }))
app.disable('x-powered-by')

// Render url.
app.use(async (req, res, next) => {
  let { url, type, filename, ...options } = req.query

  if (!url) {
    return res.status(400).send('Search with url parameter. For eaxample, ?url=http://yourdomain')
  }

  if (!url.includes('://')) {
    url = `http://${url}`
  }

  try {
    switch (type) {
      case 'pdf':
        const urlObj = new URL(url)
        if (!filename) {
          filename = urlObj.hostname
          if (urlObj.pathname !== '/') {
            filename = urlObj.pathname.split('/').pop()
            if (filename === '') filename = urlObj.pathname.replace(/\//g, '')
            const extDotPosition = filename.lastIndexOf('.')
            if (extDotPosition > 0) filename = filename.substring(0, extDotPosition)
          }
        }
        if(!filename.toLowerCase().endsWith('.pdf')) {
          filename += '.pdf';
        }
        const { contentDispositionType, ...pdfOptions } = options
        const pdf = await renderer.pdf(url, pdfOptions)
        res
          .set({
            'Content-Type': 'application/pdf',
            'Content-Length': pdf.length,
            'Content-Disposition': contentDisposition(filename, { type: contentDispositionType || 'attachment' }),
          })
          .send(pdf)
        break

      case 'screenshot':
        const { screenshotType, buffer } = await renderer.screenshot(url, options)
        res
          .set({
            'Content-Type': `image/${screenshotType}`,
            'Content-Length': buffer.length,
          })
          .send(buffer)
        break

      default:
        //自定义方法
        const html = await renderer.renderHtml(url)
        res.status(200).send(html)
    }
  } catch (e) {
    next(e)
  }
})

// Error page.
app.use((err, req, res, next) => {
  console.error(err)
  res.status(500).send('Oops, An expected error seems to have occurred.')
})

// Create renderer and start server.
createRenderer({
  ignoreHTTPSErrors: !!process.env.IGNORE_HTTPS_ERRORS,
})
  .then(createdRenderer => {
    renderer = createdRenderer
    console.info('Initialized renderer.')

    app.listen(port, () => {
      console.info(`Listen port on ${port}.`)
    })
  })
  .catch(e => {
    console.error('Fail to initialze renderer.', e)
  })

// Terminate process
process.on('SIGINT', () => {
  process.exit(0)
})

renderer.js

'use strict'

const puppeteer = require('puppeteer')
const waitForAnimations = require('./wait-for-animations')

class Renderer {
  constructor(browser) {
    this.browser = browser
  }

  async createPage(url, options = {}) {
    const { timeout, waitUntil, credentials, emulateMedia } = options
    const page = await this.browser.newPage()
    if (emulateMedia) {
      await page.emulateMedia(emulateMedia)
    }

    if (credentials) {
      await page.authenticate(credentials)
    }

    await page.goto(url, {
      timeout: Number(timeout) || 30 * 1000,
      waitUntil: waitUntil || 'networkidle2',
    })
    return page
  }

  async render(url, options = {}) {
    let page = null
    try {
      const { timeout, waitUntil, credentials } = options
      page = await this.createPage(url, { timeout, waitUntil, credentials })
      const html = await page.content()
      return html
    } finally {
      if (page) {
        await page.close()
      }
    }
  }
 //自定义模拟器手机访问
  async renderHtml(url, options = {}) {
	try{  
	    let browser = await puppeteer.launch({
            // 是否不显示浏览器, 为true则不显示
            'args': ['--no-sandbox', '--disable-setuid-sandbox']
        });
		   // 通过浏览器实例 Browser 对象创建页面 Page 对象
        let page = await browser.newPage();
		const UA = "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1";
		await Promise.all([
            page.setUserAgent(UA),
            // 允许运行js
            page.setJavaScriptEnabled(true),
            // 设置页面视口的大小
            page.setViewport({width: 1100, height: 1080}),
        ]);
		await page.goto(url);
		let content= await page.content();
		await browser.close();
		return content;
	}catch(err){
        console.log(err)
    }	
	  
  }
  
  
  

  async pdf(url, options = {}) {
    let page = null
    try {
      const { timeout, waitUntil, credentials, emulateMedia, ...extraOptions } = options
      page = await this.createPage(url, { timeout, waitUntil, credentials, emulateMedia: emulateMedia || 'print' })

      const { scale = 1.0, displayHeaderFooter, printBackground, landscape } = extraOptions
      const buffer = await page.pdf({
        ...extraOptions,
        scale: Number(scale),
        displayHeaderFooter: displayHeaderFooter === 'true',
        printBackground: printBackground === 'true',
        landscape: landscape === 'true',
      })
      return buffer
    } finally {
      if (page) {
        await page.close()
      }
    }
  }

  async screenshot(url, options = {}) {
    let page = null
    try {
      const { timeout, waitUntil, credentials, ...extraOptions } = options
      page = await this.createPage(url, { timeout, waitUntil, credentials })
      page.setViewport({
        width: Number(extraOptions.width || 800),
        height: Number(extraOptions.height || 600),
      })

      const { fullPage, omitBackground, screenshotType, quality, ...restOptions } = extraOptions
      let screenshotOptions = {
        ...restOptions,
        type: screenshotType || 'png',
        quality:
          Number(quality) || (screenshotType === undefined || screenshotType === 'png' ? 0 : 100),
        fullPage: fullPage === 'true',
        omitBackground: omitBackground === 'true',
      }

      const animationTimeout = Number(options.animationTimeout || 0)
      if (animationTimeout > 0) {
        await waitForAnimations(page, screenshotOptions, animationTimeout)
      }

      const buffer = await page.screenshot(screenshotOptions)
      return {
        screenshotType,
        buffer,
      }
    } finally {
      if (page) {
        await page.close()
      }
    }
  }

  async close() {
    await this.browser.close()
  }
}

async function create(options = {}) {
  const browser = await puppeteer.launch(
    Object.assign({ args: ['--no-sandbox'] }, options)
  )
  return new Renderer(browser)
}

module.exports = create

wait-for-animations.js

'use strict'

const PNG = require('pngjs').PNG
const pixelmatch = require('pixelmatch')

async function sleep(ms) {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

async function waitForAnimations(page, options, timeout = 10000) {
  const t0 = new Date().getTime()

  let previous = null
  while (new Date().getTime() - t0 < timeout) {
    const current = PNG.sync.read(await page.screenshot({ ...options, type: 'png' }))

    if (previous !== null) {
      const diff = pixelmatch(previous.data, current.data, null, previous.width, previous.height)
      if (diff === 0) {
        return true
      }
    }

    previous = current

    await sleep(100)
  }

  return false
}

module.exports = waitForAnimations

//下面是安装 

docker run -d --name renderer -v /docker/puppeteer-renderer/src:/app/src -p 8040:3000 zenato/puppeteer-renderer
//下面是访问 http://ip:8040/?url=http://m.xxx.com

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!