使用 Python 将 HTML 转成 PDF
背景
很多人应该经常遇到在网上看到好的学习教程和资料但却没有电子档的,心里顿时痒痒,
下述指导一下大家,如何将网站上的各类教程转换成 PDF 电子书。
关键核心
- 主要使用的是wkhtmltopdf的Python封装—【pdfkit】
环境安装
- python3系列
- pip install requests
- pip install beautifulsoup4
- pip install pdfkit
- 如果是liunx系,则 sudo yum intsall wkhtmltopdf
- 如果是windows系,则下载稳定版的 wkhtmltopdf 进行安装,安装完成之后把该程序的执行路径加入到系统环境 $PATH 变量中
牛刀小试
一个简单的例子:
import pdfkit pdfkit.from_url('http://google.com', 'out.pdf')
pdfkit.from_file('test.html', 'out.pdf')
pdfkit.from_string('Hello!', 'out.pdf')
你也可以传递一个url或者文件名列表:
pdfkit.from_url(['google.com', 'yandex.ru', 'engadget.com'], 'out.pdf')
pdfkit.from_file(['file1.html', 'file2.html'], 'out.pdf')
也可以传递一个打开的文件:
with open('file.html') as f:
pdfkit.from_file(f, 'out.pdf')
实例代码实现
如将自强学堂中的django教程,生成一个pdf文件
#coding=utf-8
from __future__ import unicode_literals
import os,sys,re,time
import requests,codecs
from bs4 import BeautifulSoup
from urllib.parse import urlparse
import pdfkit
import platform
requests.packages.urllib3.disable_warnings()
system=platform.system()
print(sys.getdefaultencoding())
str_encode='gbk' if system is 'Windows' else 'utf-8'
print(str_encode)
html_template = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
{content}
</body>
</html>
"""
if not os.path.exists(os.path.join(os.path.dirname(__file__),'html')):
os.mkdir(os.path.join(os.path.dirname(__file__),'html'))
url_list=[]
start_url='http://www.ziqiangxuetang.com/django/django-tutorial.html'
# s=requests.session()
# html_doc=s.get('{}'.format(start_url),verify=False).content
# soup = BeautifulSoup(html_doc,'html.parser')
# print(soup.prettify())
def get_url_list(url):
"""
获取所有URL目录列表
:return:
"""
last_position = find_last(url, "/") + 1
tutorial_url_head = url[0:last_position]
domain = get_domain(url) + "/"
print(domain)
response = requests.get(url)
soup = BeautifulSoup(response.content, "html.parser")
urls = []
for a in soup.find_all("a"):
href = str(a.get('href'))
result = href.find('/')
if result == -1:
url = tutorial_url_head + href
else:
url = domain + href
if 'django' in url:
urls.append(url)
return urls
def find_last(string, char):
last_position = -1
while True:
position = string.find(char, last_position + 1)
if position == -1:
return last_position
last_position = position
def get_domain(url):
r = urlparse(url)
return r.scheme + "://" + r.netloc
def parse_url_to_html(url,name):
"""
解析URL,返回HTML内容
:param url:解析的url
:param name: 保存的html文件名
:return: html
"""
try:
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
# 正文
body = soup.find_all(class_="w-col l10 m12")
h = str(body)
html = h[1:-1]
html = html_template.format(content=html)
html = html.encode("utf-8")
title=soup.title.get_text()
print(url)
with open('{}/{}'.format(os.path.join(os.path.dirname(__file__),'html'),name), 'wb') as f:
f.write(html)
return '{}/{}'.format(os.path.join(os.path.dirname(__file__),'html'),name)
except Exception as e:
print(e)
def save_pdf(htmls, file_name):
"""
把所有html文件保存到pdf文件
:param htmls: html文件列表
:param file_name: pdf文件名
:return:
"""
options = {
'page-size': 'Letter',
'margin-top': '0.75in',
'margin-right': '0.75in',
'margin-bottom': '0.75in',
'margin-left': '0.75in',
'encoding': "UTF-8",
'custom-header': [
('Accept-Encoding', 'gzip')
],
'cookie': [
('cookie-name1', 'cookie-value1'),
('cookie-name2', 'cookie-value2'),
],
'outline-depth': 10,
}
pdfkit.from_file(htmls, file_name, options=options)
def main():
start = time.time()
urls = get_url_list(start_url)
htmls = [parse_url_to_html(url, str(index) + ".html") for index, url in enumerate(urls)]
print(htmls)
try:
save_pdf(htmls, 'cralwer_{}.pdf'.format(time.strftime('%Y_%m_%d_%H_%M_%S')))
except Exception as e:
print(e)
for html in htmls:
os.remove(html)
total_time = time.time() - start
print(u"总共耗时:{0:.2f}秒".format(total_time))
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的更多相关文章
- 使用Python将HTML转成PDF
主要使用的是wkhtmltopdf的Python封装--pdfkit 安装 1. Install python-pdfkit: $ pip install pdfkit 2. Install wkht ...
- python实现excel转换成pdf
1.安装 需要安装pywin32包,以实现对Office文件的操作,可以批量转换为pdf文件.支持 doc, docx, ppt, pptx, xls, xlsx 等格式. pip install p ...
- 用python DIY一个图片转pdf工具并打包成exe
最近因为想要看漫画,无奈下载的漫画是jpg的格式,网上的转换器还没一个好用的,于是乎就打算用python自己DIY一下: 这里主要用了reportlab.开始打算随便写几行,结果为若干坑纠结了挺久,于 ...
- Python 爬虫:把廖雪峰教程转换成 PDF 电子书
写爬虫似乎没有比用 Python 更合适了,Python 社区提供的爬虫工具多得让你眼花缭乱,各种拿来就可以直接用的 library 分分钟就可以写出一个爬虫出来,今天尝试写一个爬虫,将廖雪峰老师的 ...
- 将python代码打印成pdf
将python代码打印成pdf,打印出来很丑,完全不能看. mac下:pycharm 编辑器有print的功能,但是会提示: Error: No print service found. 所以需要一个 ...
- 使用python把html网页转成pdf文件
我们看到一些比较写的比较好文章或者博客的时候,想保存下来到本地当一个pdf文件,当做自己的知识储备,以后即使这个博客或者文章的连接不存在了,或者被删掉,咱们自己也还有. 当然咱们作为一个coder,这 ...
- 爬虫:把廖雪峰的教程转换成 PDF 电子书
写爬虫似乎没有比用 Python 更合适了,Python 社区提供的爬虫工具多得让你眼花缭乱,各种拿来就可以直接用的 library 分分钟就可以写出一个爬虫出来,今天就琢磨着写一个爬虫,将廖雪峰的 ...
- Python将html转化为pdf
前言 前面我们对博客园的文章进行了爬取,结果比较令人满意,可以一下子下载某个博主的所有文章了.但是,我们获取的只有文章中的文本内容,并且是没有排版的,看起来也比较费劲... 咋么办的?一个比较好的方法 ...
- 我是如何将博客转成PDF的
前言 只有光头才能变强 之前有读者问过我:"3y你的博客有没有电子版的呀?我想要份电子版的".我说:"没有啊,我没有弄过电子版的,我这边有个文章导航页面,你可以去文章导航 ...
随机推荐
- Linux 文件夹相关常用命令
Linux 文件夹相关常用命令 查看 ls -la -l 列出详细信息 -a 列出全部,包括.和.. 删除 rm <folder> -rf -r 就是向下递归,不管有多少级目录,一并删 ...
- MYSQL总览
第一,二,三范式解决的是非主属性的关系.BC 范式解决的是主属性的关系:第二范式:就是完全依赖,没有部分依赖([id,b]->c 即不能c即依赖id又依赖b):[非主属性不能依赖于主键的一部分, ...
- Nowcoder contest 370F Rinne Loves Edges (简单树形DP) || 【最大流】(模板)
<题目链接> 题目大意: 一个 $n$ 个节点 $m$ 条边的无向连通图,每条边有一个边权 $w_i$.现在她想玩一个游戏:选取一个 “重要点” S,然后选择性删除一些边,使得原图中所有除 ...
- hdu 3001 Travelling (三进制)【状压dp】
<题目链接> 题目大意: 给出n个点和m条边,求经过所有点所需的最小花费,每个点最多经过两次. 解题分析: TSP问题类型,由于此题每个点有三种状态,所以采用三进制状态压缩,0.1.2 分 ...
- 现代C++之理解模板类型推断(template type deduction)
理解模板类型推断(template type deduction) 我们往往不能理解一个复杂的系统是如何运作的,但是却知道这个系统能够做什么.C++的模板类型推断便是如此,把参数传递到模板函数往往能让 ...
- 一个完整的Java程序示例
(1) 第一个程序HelloWorld: package mypack; //相当于一个目录 public class HelloWorld{ public static void main(Stri ...
- linux学习笔记 其他常用命令
cd + 回车 = cd ~ 进入当前用户主目录 查看指定进程信息 *ps -ef |grep 进程名 *ps -查看属于自己的进程 *ps -aux 查看所有的用户的执行进程 换成 ps - ...
- Xamarin Essentials教程数据处理传输数据
Xamarin Essentials教程数据处理传输数据 在移动应用程序中,除了常规的数据处理,还涉及数据存储.数据传输.版本数据多个方面.Xamarin.Essentials组件提供了多个数据处理相 ...
- os模块、os.path模块、shutil模块、configparser模块、subprocess模块
一.os模块 os指的是操作系统 该模块主要用于处理与操作系统相关的操作,常用的是文件操作(读.写.删.复制.重命名). os.getcwd() 获取当前文件所在的文件夹路径 os.chdir() ...
- ;(function(){ //代码})(); 自执行函数开头为什么要加;或者!
我们有时候会在自执行函数中看到这样的代码;(function(){ //我们的代码.. alert('Hello!'); })(); !(function(){ //我们的代码.. alert('He ...