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 02 Python
python之wxPython应用实例
Sep 28 Python
python 把文件中的每一行以数组的元素放入数组中的方法
Apr 29 Python
python实现NB-IoT模块远程控制
Jun 20 Python
numpy返回array中元素的index方法
Jun 27 Python
python正则爬取某段子网站前20页段子(request库)过程解析
Aug 10 Python
Django 请求Request的具体使用方法
Nov 11 Python
利用django model save方法对未更改的字段依然进行了保存
Mar 28 Python
如何搭建pytorch环境的方法步骤
May 06 Python
python 使用cycle构造无限循环迭代器
Dec 02 Python
Jupyter Notebook 远程访问配置详解
Jan 11 Python
python热力图实现的完整实例
Jun 25 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边学边教》(01.开篇――准备工作)
2006/12/13 PHP
php checkbox 取值详细说明
2010/08/19 PHP
ThinkPHP单字母函数(快捷方法)使用总结
2014/07/23 PHP
分享PHP-pcntl 实现多进程代码
2016/09/30 PHP
PHP后台微信支付和支付宝支付开发
2017/04/28 PHP
锋利的jQuery 要点归纳(二) jQuery中的DOM操作(下)
2010/03/23 Javascript
基于jquery的一个浮动框(扩展性比较好 )
2010/08/27 Javascript
关于JavaScript的with 语句的使用方法
2011/05/09 Javascript
JS正则表达式获取分组内容的方法详解
2013/11/15 Javascript
Jquery简单分页实现方法
2015/07/24 Javascript
JS刷新父窗口的几种方式小结(推荐)
2016/11/09 Javascript
基于jQuery Easyui实现登陆框界面
2017/07/10 jQuery
JQuery中queue方法用法示例
2019/01/31 jQuery
vue组件数据传递、父子组件数据获取,slot,router路由功能示例
2019/03/19 Javascript
vuex存储复杂参数(如对象数组等)刷新数据丢失的解决方法
2019/11/05 Javascript
js实现拖动缓动效果
2020/01/13 Javascript
python利用装饰器进行运算的实例分析
2015/08/04 Python
使用python将大量数据导出到Excel中的小技巧分享
2018/06/14 Python
python在openstreetmap地图上绘制路线图的实现
2019/07/11 Python
Python word文本自动化操作实现方法解析
2020/11/05 Python
CSS3中动画属性transform、transition和animation属性的区别
2016/09/25 HTML / CSS
浅谈Html5中视频 音频标签 进度条的问题
2016/07/26 HTML / CSS
尼克松手表官网:Nixon手表
2019/03/17 全球购物
英国计算机商店:Technextday
2019/12/28 全球购物
敏捷开发的主要原则都有哪些
2015/04/26 面试题
优秀女职工事迹材料
2014/02/06 职场文书
学校元旦晚会方案
2014/02/19 职场文书
党旗在我心中演讲稿
2014/09/15 职场文书
2014年教师工作总结
2014/11/10 职场文书
自主招生自荐信格式范文
2015/03/25 职场文书
2015年音乐教研组工作总结
2015/07/22 职场文书
图书馆义工感想
2015/08/07 职场文书
毕业设计工作总结
2015/08/14 职场文书
2016教师学习党章心得体会
2016/01/15 职场文书
Python获取江苏疫情实时数据及爬虫分析
2021/08/02 Python
CSS使用Flex和Grid布局实现3D骰子
2022/08/05 HTML / CSS