V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
这是一个专门讨论 idea 的地方。

每个人的时间,资源是有限的,有的时候你或许能够想到很多 idea,但是由于现实的限制,却并不是所有的 idea 都能够成为现实。

那这个时候,不妨可以把那些 idea 分享出来,启发别人。
ecmadao
V2EX  ›  奇思妙想

有什么将网页转换为 PDF 的方法?

  •  
  •   ecmadao · 2017-02-13 11:02:02 +08:00 · 7607 次点击
    这是一个创建于 2870 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,想请教 V 友们有什么办法可以将网页转换为 PDF 吗?

    经过调研,我目前发现的方法如下(使用 Node ):

    这是我尝试的目前效果最好的方法,可以直接自行封装一个脚本,由前端调用 API 后触发。但渲染速度不尽人意,不过也应该有一些优化的空间。

    // demo
    const phantom = require('phantom');
    
    (async function() {
        const instance = await phantom.create();
        const page = await instance.createPage();
    
        await page.property('viewportSize', {width: 1024, height: 600});
        const status = await page.open('https://stackoverflow.com/');
        console.log(`Page opened with status [${status}].`);
    
        await page.render('stackoverflow.pdf');
        console.log(`File created at [./stackoverflow.pdf]`);
    
        await instance.exit();
    }());
    

    生成网页截屏。但只能是 png 、 jpg 、 jpeg 形式,且无法滚屏截图,只能指定图片高度或者按照窗口大小截取(目前没有找到合适的方式)

    // demo
    var webshot = require('webshot');
    
    webshot('google.com', 'google.png', function(err) {
      // screenshot now saved to google.png
    });
    

    暂时还没有尝试,看见在 stackoverflow 上有人推荐,也有人反馈说该库有很奇怪的 bug

    相对于上面的方法,该库是在前端调用,将一个指定的 DOM 转为 base64 格式的图片,并可以保留其样式。但缺点很明显,由于是前端使用,在 DOM 数目较多时会有明显的卡顿,体验不好。

    // demo
    domtoimage.toJpeg(document.getElementById('my-node'))
        .then(function (dataUrl) {
            var link = document.createElement('a');
            link.download = 'my-image-name.jpeg';
            link.href = dataUrl;
            link.click();
        });
    

    目前为止,还没有发现什么用起来非常爽的方法,所以求广大 V 友共同讨论 Orz

    第 1 条附言  ·  2017-02-13 17:17:22 +08:00

    有很多 chrome 插件可以将页面转为 PDF,但无法完成自动化。我目前用的最好的插件是这个:FireShot,但是它是在自己的 server 上生成的 PDF ,无法查看具体实现,而官方的 API 的话使用是要收费的。

    第 2 条附言  ·  2017-02-13 18:29:54 +08:00
    的确会有很多方法,如果只是我自己使用的话是完全可行的,比如 `window.print()` 一下,或者使用 chrome 插件什么的。但是我想和大家讨论的是一种可以开发出来放到生产环节下的方法,能够让其他用户正常使用。
    35 条回复    2017-02-23 17:13:08 +08:00
    woshilala1988
        1
    woshilala1988  
       2017-02-13 11:32:08 +08:00
    php 有个类可以调用,我们公司一直在用,很稳定
    helloccav
        2
    helloccav  
       2017-02-13 11:34:28 +08:00 via Android
    @woshilala1988 求下载地址。对中文的支持好吗?
    shoaly
        3
    shoaly  
       2017-02-13 11:36:07 +08:00
    composer require barryvdh/laravel-dompdf:^0.6.0
    qooweds
        4
    qooweds  
       2017-02-13 11:51:49 +08:00   ❤️ 2
    自己用的话
    chrome 的话可以在打印里面另存为 PDF,或者找找插件
    chloerei
        5
    chloerei  
       2017-02-13 12:03:16 +08:00 via iPhone
    mmzer
        6
    mmzer  
       2017-02-13 13:07:47 +08:00
    chorme 的打印挺好用的
    irainsoft
        7
    irainsoft  
       2017-02-13 13:11:49 +08:00
    Chrome 各种网页截屏插件不行吗?
    LucasW
        8
    LucasW  
       2017-02-13 13:18:38 +08:00
    ecmadao
        9
    ecmadao  
    OP
       2017-02-13 13:44:47 +08:00
    @qooweds chrome 的打印对于以文本为主的页面来说挺好的,不过如果自定义的 DOM 很多页面偏复杂的话,布局会乱
    ecmadao
        10
    ecmadao  
    OP
       2017-02-13 13:45:09 +08:00
    @mmzer 对。。但是如果自定义的 DOM 很多页面偏复杂的话,布局会乱
    ecmadao
        11
    ecmadao  
    OP
       2017-02-13 13:47:11 +08:00
    @irainsoft 可以啊,但是插件无法完成自动化,也不能嵌入到自己的网站上,让别人来生产 PDF 。我目前用的最好的插件是这个:[FireShot]( https://chrome.google.com/webstore/detail/take-webpage-screenshots/mcbpblocgmgfnpjjppndjkmgjaogfceg),但是它是在自己的 server 上生成的 PDF ,无法查看具体实现,官方的 API 的话使用是要收费的
    ecmadao
        12
    ecmadao  
    OP
       2017-02-13 13:47:55 +08:00
    @chloerei 好像见过这个,但是没具体使用过,我去研究研究
    ecmadao
        13
    ecmadao  
    OP
       2017-02-13 13:48:10 +08:00
    @LucasW 好嘞我去看看
    lxrmido
        15
    lxrmido  
       2017-02-13 15:24:14 +08:00
    mark
    ecmadao
        16
    ecmadao  
    OP
       2017-02-13 17:07:10 +08:00
    @lzjun 看了你的文章,我觉得如果你的需求主要是获取 http 请求的 body 的话,就没必要用 BS4 了(因为匹配 DOM 的逻辑并不复杂),太重。不过我主要困惑的是,不知道 wkhtmltopdf 保存的结果能否保留页面上较复杂的 CSS 样式?
    wellsc
        17
    wellsc  
       2017-02-13 17:26:38 +08:00
    f12 打开 dev tools , console 里面输入 print();
    done
    hehe00
        18
    hehe00  
       2017-02-13 17:32:11 +08:00
    @woshilala1988 请问 word(.doc .docx)转 PDF 或 HTML,有什么办法吗
    ecmadao
        19
    ecmadao  
    OP
       2017-02-13 18:26:16 +08:00
    @LucasW

    看了下文档,它是将静态的 HTML 文件转为 PDF ,而且允许往 HTML 里面插入一个 CSS 和一个 JS 文件?
    但是有一个 issue 说它不能够插入多个资源文件,而且作者也表示确实不支持也没时间做 Orz
    ecmadao
        20
    ecmadao  
    OP
       2017-02-13 18:27:23 +08:00
    @wellsc 可惜对页面样式的支持很差,不然我也就采纳这种方法了。
    LucasW
        21
    LucasW  
       2017-02-14 12:16:51 +08:00
    @ecmadao 你的需求是什么样的?

    看我这边的项目, https://github.com/Lucassssss/Writer
    是直接转换 html 内容为 pdf ,而且可以给转换的内容自己定义不同的样式。
    boxz
        22
    boxz  
       2017-02-14 23:36:10 +08:00
    wkhtmltopdf 你可以试试
    goodryb
        23
    goodryb  
       2017-02-15 13:35:55 +08:00
    @wellsc #17 command+p 不是更快么
    dphdjy
        24
    dphdjy  
       2017-02-15 18:35:52 +08:00 via Android
    DOM 乱可以手动改啊,改完了再打印
    marsLeo
        25
    marsLeo  
       2017-02-16 01:37:05 +08:00
    刚好看到阮老师的微博,有相关内容
    http://weibo.com/1400854834/EvGeSvGFM
    hehe00
        26
    hehe00  
       2017-02-17 09:27:14 +08:00
    倒是有 word 转 PDF 的
    ecmadao
        27
    ecmadao  
    OP
       2017-02-20 08:38:24 +08:00
    @boxz 好的谢谢,好像很多人推荐。等忙完这段时间了我去好好研究一下
    ecmadao
        28
    ecmadao  
    OP
       2017-02-20 08:38:57 +08:00
    @marsLeo 打印功能的话,对于复杂度较高的 DOM 而言体验不好
    xiaoluoboding
        29
    xiaoluoboding  
       2017-02-20 14:03:48 +08:00
    不应该是 pdf.js 吗、。? https://github.com/mozilla/pdf.js
    ctftemp
        30
    ctftemp  
       2017-02-20 19:30:49 +08:00 via Android
    你直接用 node 调用 phantomjs 不就可以吗? phantomjs-node 的原理也是启动了一个 phantomjs 子进程与之交互。至于速度问题,你用别的浏览器不见得效率能更高。
    ctftemp
        31
    ctftemp  
       2017-02-20 19:33:07 +08:00 via Android
    @ecmadao wkhtmltopdf 的话,和 phantomjs 一样用的是 webkit 内核,按理说不会更快。我没对比过,你可以试试。
    oldj
        32
    oldj  
       2017-02-21 13:35:09 +08:00
    wkhtmltopdf 应该是一个很好的选择。

    和 phantomjs 相比,它的优点之一是输出的 PDF 支持目录( TOC )。
    20015jjw
        33
    20015jjw  
       2017-02-21 18:45:27 +08:00 via Android
    cmd + p ?
    Khlieb
        34
    Khlieb  
       2017-02-21 20:55:01 +08:00 via Android
    有些虚拟打印机也能把网页做成 PDF ,就是通过浏览器的打印功能来调用的,比如 CutePDF 、 doPDF 、 PDFCreator
    spice630
        35
    spice630  
       2017-02-23 17:13:08 +08:00
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3680 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 04:34 · PVG 12:34 · LAX 20:34 · JFK 23:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.