Python实现抓取HTML网页并以PDF文件形式保存的方法


Posted in Python onMay 08, 2018

本文实例讲述了Python实现抓取HTML网页并以PDF文件形式保存的方法。分享给大家供大家参考,具体如下:

一、前言

今天介绍将HTML网页抓取下来,然后以PDF保存,废话不多说直接进入教程。

今天的例子以廖雪峰老师的Python教程网站为例:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000

二、准备工作

1. PyPDF2的安装使用(用来合并PDF):

PyPDF2版本:1.25.1

https://pypi.python.org/pypi/PyPDF2/1.25.1

https://github.com/mstamy2/PyPDF2

安装:

pip install PyPDF2

使用示例:

from PyPDF2 import PdfFileMerger
merger = PdfFileMerger()
input1 = open("hql_1_20.pdf", "rb")
input2 = open("hql_21_40.pdf", "rb")
merger.append(input1)
merger.append(input2)
# Write to an output PDF document
output = open("hql_all.pdf", "wb")
merger.write(output)

2. requests、beautifulsoup 是爬虫两大神器,reuqests 用于网络请求,beautifusoup 用于操作 html 数据。有了这两把梭子,干起活来利索。scrapy 这样的爬虫框架我们就不用了,这样的小程序派上它有点杀鸡用牛刀的意思。此外,既然是把 html 文件转为 pdf,那么也要有相应的库支持, wkhtmltopdf 就是一个非常的工具,它可以用适用于多平台的 html 到 pdf 的转换,pdfkit 是 wkhtmltopdf 的Python封装包。首先安装好下面的依赖包

pip install requests
pip install beautifulsoup4
pip install pdfkit

3. 安装 wkhtmltopdf

Windows平台直接在 http://wkhtmltopdf.org/downloads.html 下载稳定版的 wkhtmltopdf 进行安装,安装完成之后把该程序的执行路径加入到系统环境 $PATH 变量中,否则 pdfkit 找不到 wkhtmltopdf 就出现错误 “No wkhtmltopdf executable found”。Ubuntu 和 CentOS 可以直接用命令行进行安装

$ sudo apt-get install wkhtmltopdf # ubuntu
$ sudo yum intsall wkhtmltopdf   # centos

三、数据准备

1. 获取每篇文章的url

def get_url_list():
  """
  获取所有URL目录列表
  :return:
  """
  response = requests.get("http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000")
  soup = BeautifulSoup(response.content, "html.parser")
  menu_tag = soup.find_all(class_="uk-nav uk-nav-side")[1]
  urls = []
  for li in menu_tag.find_all("li"):
    url = "http://www.liaoxuefeng.com" + li.a.get('href')
    urls.append(url)
  return urls

2. 通过文章url用模板保存每篇文章的HTML文件

html模板:

html_template = """
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
</head>
<body>
{content}
</body>
</html>
"""

进行保存:

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_="x-wiki-content")[0]
    # 标题
    title = soup.find('h4').get_text()
    # 标题加入到正文的最前面,居中显示
    center_tag = soup.new_tag("center")
    title_tag = soup.new_tag('h1')
    title_tag.string = title
    center_tag.insert(1, title_tag)
    body.insert(1, center_tag)
    html = str(body)
    # body中的img标签的src相对路径的改成绝对路径
    pattern = "(<img .*?src=\")(.*?)(\")"
    def func(m):
      if not m.group(3).startswith("http"):
        rtn = m.group(1) + "http://www.liaoxuefeng.com" + m.group(2) + m.group(3)
        return rtn
      else:
        return m.group(1)+m.group(2)+m.group(3)
    html = re.compile(pattern).sub(func, html)
    html = html_template.format(content=html)
    html = html.encode("utf-8")
    with open(name, 'wb') as f:
      f.write(html)
    return name
  except Exception as e:
    logging.error("解析错误", exc_info=True)

3. 把html转换成pdf

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)

4. 把转换好的单个PDF合并为一个PDF

merger = PdfFileMerger()
for pdf in pdfs:
  merger.append(open(pdf,'rb'))
  print u"合并完成第"+str(i)+'个pdf'+pdf

完整源码:

# coding=utf-8
import os
import re
import time
import logging
import pdfkit
import requests
from bs4 import BeautifulSoup
from PyPDF2 import PdfFileMerger
html_template = """
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
</head>
<body>
{content}
</body>
</html>
"""
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_="x-wiki-content")[0]
    # 标题
    title = soup.find('h4').get_text()
    # 标题加入到正文的最前面,居中显示
    center_tag = soup.new_tag("center")
    title_tag = soup.new_tag('h1')
    title_tag.string = title
    center_tag.insert(1, title_tag)
    body.insert(1, center_tag)
    html = str(body)
    # body中的img标签的src相对路径的改成绝对路径
    pattern = "(<img .*?src=\")(.*?)(\")"
    def func(m):
      if not m.group(3).startswith("http"):
        rtn = m.group(1) + "http://www.liaoxuefeng.com" + m.group(2) + m.group(3)
        return rtn
      else:
        return m.group(1)+m.group(2)+m.group(3)
    html = re.compile(pattern).sub(func, html)
    html = html_template.format(content=html)
    html = html.encode("utf-8")
    with open(name, 'wb') as f:
      f.write(html)
    return name
  except Exception as e:
    logging.error("解析错误", exc_info=True)
def get_url_list():
  """
  获取所有URL目录列表
  :return:
  """
  response = requests.get("http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000")
  soup = BeautifulSoup(response.content, "html.parser")
  menu_tag = soup.find_all(class_="uk-nav uk-nav-side")[1]
  urls = []
  for li in menu_tag.find_all("li"):
    url = "http://www.liaoxuefeng.com" + li.a.get('href')
    urls.append(url)
  return urls
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()
  file_name = u"liaoxuefeng_Python3_tutorial"
  urls = get_url_list()
  for index, url in enumerate(urls):
   parse_url_to_html(url, str(index) + ".html")
  htmls =[]
  pdfs =[]
  for i in range(0,124):
    htmls.append(str(i)+'.html')
    pdfs.append(file_name+str(i)+'.pdf')
    save_pdf(str(i)+'.html', file_name+str(i)+'.pdf')
    print u"转换完成第"+str(i)+'个html'
  merger = PdfFileMerger()
  for pdf in pdfs:
    merger.append(open(pdf,'rb'))
    print u"合并完成第"+str(i)+'个pdf'+pdf
  output = open(u"廖雪峰Python_all.pdf", "wb")
  merger.write(output)
  print u"输出PDF成功!"
  for html in htmls:
    os.remove(html)
    print u"删除临时文件"+html
  for pdf in pdfs:
    os.remove(pdf)
    print u"删除临时文件"+pdf
  total_time = time.time() - start
  print(u"总共耗时:%f 秒" % total_time)
if __name__ == '__main__':
  main()

更多Python相关内容感兴趣的读者可查看本站专题:《Python文件与目录操作技巧汇总》、《Python编码操作技巧总结》、《Python数据结构与算法教程》、《Python函数使用技巧总结》、《Python字符串操作技巧汇总》及《Python入门与进阶经典教程》

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python常用列表数据结构小结
Aug 06 Python
python生成IP段的方法
Jul 07 Python
Python中的一些陷阱与技巧小结
Jul 10 Python
Python简单连接MongoDB数据库的方法
Mar 15 Python
python实现图书管理系统
Mar 12 Python
python中while和for的区别总结
Jun 28 Python
Python一键查找iOS项目中未使用的图片、音频、视频资源
Aug 12 Python
python sorted函数原理解析及练习
Feb 10 Python
Python文本文件的合并操作方法代码实例
Mar 31 Python
Python selenium模块实现定位过程解析
Jul 09 Python
Django配置跨域并开发测试接口
Nov 04 Python
python制作抽奖程序代码详解
Jan 15 Python
Python读写docx文件的方法
May 08 #Python
python docx 中文字体设置的操作方法
May 08 #Python
Python解析并读取PDF文件内容的方法
May 08 #Python
python-docx修改已存在的Word文档的表格的字体格式方法
May 08 #Python
对Python中gensim库word2vec的使用详解
May 08 #Python
用python处理MS Word的实例讲解
May 08 #Python
基于python批量处理dat文件及科学计算方法详解
May 08 #Python
You might like
[原创]PHP中通过ADODB库实现调用Access数据库之修正版本
2006/12/31 PHP
php实现无限级分类查询(递归、非递归)
2016/03/10 PHP
PHP中获取文件创建日期、修改日期、访问时间的方法
2016/11/05 PHP
如何利用预加载优化Laravel Model查询详解
2017/08/11 PHP
PHP实现的贪婪算法实例
2017/10/17 PHP
PHP实现网站访问量计数器
2017/10/27 PHP
关于jQuery UI 使用心得及技巧
2012/10/10 Javascript
JS可以控制样式的名称写法一览
2014/01/16 Javascript
js实现省市联动效果的简单实例
2014/02/10 Javascript
父页面显示遮罩层弹出半透明状态的dialog
2014/03/04 Javascript
jQuery 计算iframe 窗口大小的方法
2014/05/13 Javascript
Javascript判断文件是否存在(客户端/服务器端)
2014/09/16 Javascript
jQuery插件简单学习实例教程
2016/07/01 Javascript
Centos7 中安装 Node.js v4.4.4
2016/11/03 Javascript
浅析JS中的 map, filter, some, every, forEach, for in, for of 用法总结
2017/03/29 Javascript
vue 组件使用中的一些细节点
2018/04/25 Javascript
关于Vue组件库开发详析
2018/07/01 Javascript
js 实现watch监听数据变化的代码
2019/10/13 Javascript
vue中上传视频或图片或图片和文字一起到后端的解决方法
2019/12/01 Javascript
微信小程序实现点击导航条切换页面
2020/11/19 Javascript
对python中url参数编码与解码的实例详解
2019/07/25 Python
Python字符串的修改方法实例
2019/12/19 Python
python3实现往mysql中插入datetime类型的数据
2020/03/02 Python
opencv之颜色过滤只留下图片中的红色区域操作
2020/06/05 Python
Python Selenium操作Cookie的实例方法
2021/02/28 Python
How to spawning asynchronous work in J2EE
2016/08/29 面试题
电脑教师的教学自我评价
2013/11/26 职场文书
网上快餐厅创业计划书
2014/02/01 职场文书
会计求职信
2014/05/29 职场文书
网络营销策划方案
2014/06/04 职场文书
条幅标语大全
2014/06/20 职场文书
大雁塔导游词
2015/02/04 职场文书
公积金贷款承诺书
2015/04/30 职场文书
防溺水主题班会教案
2015/08/12 职场文书
react中props 的使用及进行限制的方法
2021/04/28 Javascript
英国数字版游戏销量周榜公布 《小缇娜的奇幻之地》登顶
2022/04/03 其他游戏