使用docker puppeteer api 接口返回

使用docker  puppeteer   api 接口返回

安装  安装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

 

 

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 使用docker puppeteer api 接口返回