背景

很多人应该经常遇到在网上看到好的学习教程和资料但却没有电子档的,心里顿时痒痒,

下述指导一下大家,如何将网站上的各类教程转换成 PDF 电子书。

关键核心

  • 主要使用的是wkhtmltopdf的Python封装—【pdfkit】

环境安装

  • python3系列
  • pip install requests
  • pip install beautifulsoup4
  • pip install pdfkit
  • 如果是liunx系,则 sudo yum intsall wkhtmltopdf
  • 如果是windows系,则下载稳定版的 wkhtmltopdf 进行安装,安装完成之后把该程序的执行路径加入到系统环境 $PATH 变量中

牛刀小试

一个简单的例子:

  1. import pdfkit pdfkit.from_url('http://google.com', 'out.pdf')
  2. pdfkit.from_file('test.html', 'out.pdf')
  3. pdfkit.from_string('Hello!', 'out.pdf')

你也可以传递一个url或者文件名列表:

  1. pdfkit.from_url(['google.com', 'yandex.ru', 'engadget.com'], 'out.pdf')
  2. pdfkit.from_file(['file1.html', 'file2.html'], 'out.pdf')

也可以传递一个打开的文件:

  1. with open('file.html') as f:
  2. pdfkit.from_file(f, 'out.pdf')

实例代码实现

如将自强学堂中的django教程,生成一个pdf文件

  1. #coding=utf-8
  2. from __future__ import unicode_literals
  3. import os,sys,re,time
  4. import requests,codecs
  5. from bs4 import BeautifulSoup
  6. from urllib.parse import urlparse
  7. import pdfkit
  8. import platform
  9. requests.packages.urllib3.disable_warnings()
  10. system=platform.system()
  11. print(sys.getdefaultencoding())
  12. str_encode='gbk' if system is 'Windows' else 'utf-8'
  13. print(str_encode)
  14. html_template = """
  15. <!DOCTYPE html>
  16. <html lang="en">
  17. <head>
  18. <meta charset="UTF-8">
  19. </head>
  20. <body>
  21. {content}
  22. </body>
  23. </html>
  24. """
  25. if not os.path.exists(os.path.join(os.path.dirname(__file__),'html')):
  26. os.mkdir(os.path.join(os.path.dirname(__file__),'html'))
  27. url_list=[]
  28. start_url='http://www.ziqiangxuetang.com/django/django-tutorial.html'
  29. # s=requests.session()
  30. # html_doc=s.get('{}'.format(start_url),verify=False).content
  31. # soup = BeautifulSoup(html_doc,'html.parser')
  32. # print(soup.prettify())
  33. def get_url_list(url):
  34. """
  35. 获取所有URL目录列表
  36. :return:
  37. """
  38. last_position = find_last(url, "/") + 1
  39. tutorial_url_head = url[0:last_position]
  40. domain = get_domain(url) + "/"
  41. print(domain)
  42. response = requests.get(url)
  43. soup = BeautifulSoup(response.content, "html.parser")
  44. urls = []
  45. for a in soup.find_all("a"):
  46. href = str(a.get('href'))
  47. result = href.find('/')
  48. if result == -1:
  49. url = tutorial_url_head + href
  50. else:
  51. url = domain + href
  52. if 'django' in url:
  53. urls.append(url)
  54. return urls
  55. def find_last(string, char):
  56. last_position = -1
  57. while True:
  58. position = string.find(char, last_position + 1)
  59. if position == -1:
  60. return last_position
  61. last_position = position
  62. def get_domain(url):
  63. r = urlparse(url)
  64. return r.scheme + "://" + r.netloc
  65. def parse_url_to_html(url,name):
  66. """
  67. 解析URL,返回HTML内容
  68. :param url:解析的url
  69. :param name: 保存的html文件名
  70. :return: html
  71. """
  72. try:
  73. response = requests.get(url)
  74. soup = BeautifulSoup(response.content, 'html.parser')
  75. # 正文
  76. body = soup.find_all(class_="w-col l10 m12")
  77. h = str(body)
  78. html = h[1:-1]
  79. html = html_template.format(content=html)
  80. html = html.encode("utf-8")
  81. title=soup.title.get_text()
  82. print(url)
  83. with open('{}/{}'.format(os.path.join(os.path.dirname(__file__),'html'),name), 'wb') as f:
  84. f.write(html)
  85. return '{}/{}'.format(os.path.join(os.path.dirname(__file__),'html'),name)
  86. except Exception as e:
  87. print(e)
  88. def save_pdf(htmls, file_name):
  89. """
  90. 把所有html文件保存到pdf文件
  91. :param htmls: html文件列表
  92. :param file_name: pdf文件名
  93. :return:
  94. """
  95. options = {
  96. 'page-size': 'Letter',
  97. 'margin-top': '0.75in',
  98. 'margin-right': '0.75in',
  99. 'margin-bottom': '0.75in',
  100. 'margin-left': '0.75in',
  101. 'encoding': "UTF-8",
  102. 'custom-header': [
  103. ('Accept-Encoding', 'gzip')
  104. ],
  105. 'cookie': [
  106. ('cookie-name1', 'cookie-value1'),
  107. ('cookie-name2', 'cookie-value2'),
  108. ],
  109. 'outline-depth': 10,
  110. }
  111. pdfkit.from_file(htmls, file_name, options=options)
  112. def main():
  113. start = time.time()
  114. urls = get_url_list(start_url)
  115. htmls = [parse_url_to_html(url, str(index) + ".html") for index, url in enumerate(urls)]
  116. print(htmls)
  117. try:
  118. save_pdf(htmls, 'cralwer_{}.pdf'.format(time.strftime('%Y_%m_%d_%H_%M_%S')))
  119. except Exception as e:
  120. print(e)
  121. for html in htmls:
  122. os.remove(html)
  123. total_time = time.time() - start
  124. print(u"总共耗时:{0:.2f}秒".format(total_time))
  125. main()

大概思路

  • 先传入一个起始站点的url,本例以自强学堂为例,http://www.ziqiangxuetang.com/django/django-tutorial.html
  • 然后,通过爬虫获取所有含django的url地址,存放在一个列表中,然后再依次获取url,解析各个url中的正文body内容,通过人工分析,各个url正文Body对应的class为w-col l10 m12,所以只需要爬取w-col l10 m12的内容即可。
  • 将获取到的正文内容存放在html文件中,最终返回一个含所有html文件地址的列表htmls。
  • 通过pdfkit.from_file接收一个htmls列表,生成对应pdf文件。

常见问题

  • IOError: ‘No wkhtmltopdf executable found’

    确保 wkhtmltopdf 在你的系统路径中($PATH),会通过 configuration进行了配置 (详情看上文描述)。 在Windows系统中使用where wkhtmltopdf命令 或 在 linux系统中使用 which wkhtmltopdf 会返回 wkhtmltopdf二进制可执行文件所在的确切位置.

  • IOError: ‘Command Failed’

    如果出现这个错误意味着 PDFKit不能处理一个输入。你可以尝试直接在错误信息后面直接运行一个命令来查看是什么导致了这个错误 (某些版本的 wkhtmltopdf会因为段错误导致处理失败

  • 正常生成,但是出现中文乱码

    在html中加入

参考

志军的项目: https://github.com/lzjun567/crawler_html2pdf

欢迎订阅号

使用 Python 将 HTML 转成 PDF的更多相关文章

  1. 使用Python将HTML转成PDF

    主要使用的是wkhtmltopdf的Python封装--pdfkit 安装 1. Install python-pdfkit: $ pip install pdfkit 2. Install wkht ...

  2. python实现excel转换成pdf

    1.安装 需要安装pywin32包,以实现对Office文件的操作,可以批量转换为pdf文件.支持 doc, docx, ppt, pptx, xls, xlsx 等格式. pip install p ...

  3. 用python DIY一个图片转pdf工具并打包成exe

    最近因为想要看漫画,无奈下载的漫画是jpg的格式,网上的转换器还没一个好用的,于是乎就打算用python自己DIY一下: 这里主要用了reportlab.开始打算随便写几行,结果为若干坑纠结了挺久,于 ...

  4. Python 爬虫:把廖雪峰教程转换成 PDF 电子书

    写爬虫似乎没有比用 Python 更合适了,Python 社区提供的爬虫工具多得让你眼花缭乱,各种拿来就可以直接用的 library 分分钟就可以写出一个爬虫出来,今天尝试写一个爬虫,将廖雪峰老师的 ...

  5. 将python代码打印成pdf

    将python代码打印成pdf,打印出来很丑,完全不能看. mac下:pycharm 编辑器有print的功能,但是会提示: Error: No print service found. 所以需要一个 ...

  6. 使用python把html网页转成pdf文件

    我们看到一些比较写的比较好文章或者博客的时候,想保存下来到本地当一个pdf文件,当做自己的知识储备,以后即使这个博客或者文章的连接不存在了,或者被删掉,咱们自己也还有. 当然咱们作为一个coder,这 ...

  7. 爬虫:把廖雪峰的教程转换成 PDF 电子书

    写爬虫似乎没有比用 Python 更合适了,Python 社区提供的爬虫工具多得让你眼花缭乱,各种拿来就可以直接用的 library 分分钟就可以写出一个爬虫出来,今天就琢磨着写一个爬虫,将廖雪峰的 ...

  8. Python将html转化为pdf

    前言 前面我们对博客园的文章进行了爬取,结果比较令人满意,可以一下子下载某个博主的所有文章了.但是,我们获取的只有文章中的文本内容,并且是没有排版的,看起来也比较费劲... 咋么办的?一个比较好的方法 ...

  9. 我是如何将博客转成PDF的

    前言 只有光头才能变强 之前有读者问过我:"3y你的博客有没有电子版的呀?我想要份电子版的".我说:"没有啊,我没有弄过电子版的,我这边有个文章导航页面,你可以去文章导航 ...

随机推荐

  1. 4、Qt Project之串口数据传输

    串口数据传输: Step1:串口数据的发送和接收过程,我们需要单独的添加串口的相关模块进去,模块名称叫做serialport,我们需要建立的工程是QMainWindow的基类程序,不是QWidget程 ...

  2. python自带进程池

    注意:必须加 close() 和 join(),且 close 必须在 join 之前 代码: import multiprocessing #执行方法 def func(*args,**kwargs ...

  3. Supervisor进程管理&开机自启

    这几天在用supervisor管理爬虫和Flask, 每次都记不住命令,花点时间记录下. supervisor是一个进程管理工具,用来启动.停止.重启和监测进程.我用这个东西主要用来监测爬虫和Flas ...

  4. 整合django和bootstrap框架

    环境: python版本:2.7.8 django版本:1.7.1 bootstrap版本:3.3.0 首先github上面有两个开源的项目用来整合django和bootstrap. https:// ...

  5. Spring监听,ApplicationListener

    import java.util.HashMap; import java.util.Map; import org.apache.commons.lang3.StringUtils; import ...

  6. Java的运算符

    运算符用于执行程序代码运算,会针对一个以上操作数项目来进行运算.下面介绍JAVA中的运算符: (1)算术运算符: 单目:+(取正) -(取负) ++(自增1) --(自减1) 双目:+ - * / % ...

  7. BZOJ.5339.[TJOI2018]教科书般的亵渎(拉格朗日插值) & 拉格朗日插值学习笔记

    BZOJ 洛谷 题意的一点说明: \(k\)次方这个\(k\)是固定的,也就是最初需要多少张亵渎,每次不会改变: 因某个怪物死亡引发的亵渎不会计分. 不难发现当前所需的张数是空格数+1,即\(m+1\ ...

  8. Android强制关闭某个指定应用 “关闭应用”

    强制关闭指定的应用程序: // 传入应用的包名即可kill掉应用 private void forceStopApp(String packageName) { ActivityManager am ...

  9. Mybatis的延迟加载和缓存

    1. MyBatis中的延迟加载,也称为懒加载,是指在进行关联查询时,按照设置延迟加载规则推迟对关联对象的select查询.延迟加载可以有效的减少数据库压力.       注意:MyBatis的延迟加 ...

  10. 要过年啦,用canvas做了个烟火效果

    声明:本文为原创文章,如需转载,请注明来源WAxes,谢谢! 要过年了,过年想到的就是放烟火啦....于是就用canvas写了个放烟火的效果,鼠标点击也会产生烟火,不过不要产生太多烟火哦,一个烟火散出 ...