网页生成PDF文件应用

生成PDF的需求多么?

你没有碰到过要将网页转换为PDF文件的需求? 图片呢?
如何保存一个网页的快照? 截图? 页面过长怎办,系统自带的截图工具无法滚屏
海外网页被墙,经过在香港服部署一PDF生成服务能够免除无谓的浏览其它垃圾/非法网址。
公司管理层须要在公司集成办公系统上查看其它系统的资料,好比hr系统上员工简历,营销系统上的某报表...html

需求仍是很多的。前端

使用历史

我的前后使用过 wkhtmltopdf , phantomjs ,puppeteer。
wkhtmltopdf 使用起来最简单,功能比较单一,看名字就知道了,在windows下直接就是一个exe,可在本身的项目中fork/startProcess 开一个新进程,并传入网页和保存的路径地址,经过 wkhtmltopdf -h 能够查看各参数和说明。若是你要生成的页面是集团内部服务,那么使用它是最方便的。node

phantomjs ,一样经过名字就知道它和js 结合的很是紧密。它使用webkit内核,同pupp,用户在可在页面内注入js,像在浏览器上操做页面和元素同样操做它,但它已中止更新了。linux

puppeteer 是google 提供的 node 库用来操做chrome,有些人称之为无头浏览器,在linux上使用会配套下载chromium。功能上彻底能够做为phantomjs 替代品,正由于它操做的实际是chrome浏览器,对于分析页面数据,模拟和破解前端逻辑很是给力。web

除此以外,其实还有不少工具,网上能搜出一大把,这里就很少说了。chrome

使用puppeteer实现windows

'use strict'
 
const Service = require("egg").Service;
const puppeteer = require('puppeteer');

class pupp extends Service {
    async Create(tourl, savePath,ops) {
        ops = ops || {};
        //console.log("pupp.js ", tourl, savePath,ops);
        const browser = await puppeteer.launch({
                args : [
                    '--no-sandbox',
                    '--disable-setuid-sandbox',
                    '--disable-gpu',
                    '--disable-dev-shm-usage',
                    '--no-first-run',
                    '--no-zygote',
                    //'--single-process'
                ],
                ignoreHTTPSErrors:true
            });
        const page = await browser.newPage();
        // console.log("before go to:");
        await page.setUserAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36");
        /*
        await page.setExtraHTTPHeaders({
        "accept-language":"zh-CN,zh;q=0.9,en;q=0.8",
        "cookie":"csrfToken=V04e-JSpCtM_BEr_VH2-73N9",
        "cache-control":"max-age=0"
        });*/
         
        if(ops.cookies)
        {
          console.log("setcookies return :",await page.setCookie(...ops.cookies));
          await page.waitFor(200);
        }
        await page.goto(tourl, {
            waitUntil : 'networkidle2',
            timeout : 60000
        });
           
        if(ops.navigation)
          await page.waitForNavigation({waitUntil:'networkidle2'});//没有这个,weibo 相关页面会是空白
         
        //await page.screenshot({path: 'screenshot.png'});
        //否则会有href 显示在页面
        page.emulateMedia('screen');
 
        let scrollEnable = true;
        let scrollStep = 1000; //每次滚动的步长
        let scrollCount = 0;
        while (scrollEnable) {
            if (scrollCount++ > 5) //最多容许滚动5次
            {
                console.error("too many scroll, jumpout ", tourl);
                scrollEnable = false;
                break;
            }
 
            scrollEnable = await page.evaluate((scrollStep) => {
                        let scrollTop = document.scrollingElement.scrollTop;
                        document.scrollingElement.scrollTop = scrollTop + scrollStep;
                        return document.body.clientHeight > scrollTop + scrollStep ? true : false
                    }, scrollStep);
            await page.waitFor(200)
        }
        page.waitFor(2000);
 
        await page.pdf({
            path : savePath,
            width : "1280px",
            height : "1960px",
            printBackground:true
        });
        await browser.close();
 
    }
    /**
    将cookie string 转换为cookie object 的数组
    */
    cvtCookie(ck_line)
    {
        let arr = fs.readFileSync("./old_cookies.txt").toString().split(";");
        let objcks = arr.map(aline=>{
          let ind = aline.indexOf("=");
          return {name:aline.substr(0,ind),value:aline.substr(ind+1)};
        });
    }
}
 
//延时
function waitMs(ms) {
    if (typeof ms != "number")
        return Promise.resolve(0);
    return new Promise((resolve, rej) => {
            setTimeout(() => {
                    resolve(1);
                }, ms);
        });
}
 
module.exports = pupp;

以上是生成pdf文件的核心代码,使用的是egg框架,不熟悉并不影响阅读。有以下几点可留意一下数组

1:有些注释掉的代码没有去掉,有些代码也能够注释,取决于你真实的测试状况,许多网页的渲染方式不同,有些还混合着多种js异步渲染。浏览器

2:文中的一些具体参数都是通过反复屡次验证效果后添加或调整过的,官网上并不会有这些内容,有时一个默认参数就会让效果迥异。服务器

3:代码中有段cookie设置,这是由于不少网页用户不登录不能看,因此须要前置的用户登录,并获取登录成功后的cookie,进而在此步使用。须要留意模拟登录后的cookie(甚至手动在浏览器登录后保存cookie)使用的浏览器请求头应尽可能保持一致,以避免服务端将它区分为两个不一样用户。

4:文中有个滚动页面的逻辑,由于有些页面仅显示一屏,当用户滚动鼠标到文末时才会继续加载,就像一些手机app,最多往下拉五次,拉太多没多大意义还浪费时间。

一点废话

puppeteer用做生成pdf有些大材小用了,用做分析和操做页面元素获取数据都十分方便的。我的认为它不太适合大批量的爬取数据,效率较低。

另外,要获取别人的页面就绕不开须要登录和验证码,若是不是过于频繁的请求,如上文所述,直接用户手动在浏览器输入账密,而后再将浏览器的cookie保存下来,交由上面代码处理就够了。但若是是将服务部署在服务器,这种办法就失去了做用。笔者就用过一个网上下载的新浪微博登录库,并使用一种很“挫”的方式填充验证码,工做良好,有兴趣的同窗能够留言向我了解。

下一篇,将讲述使用 selinum 获取股票数据

相关文章
相关标签/搜索