文章架构
开发场景
- 在日常开发过程中, 经常需要参考一些文档。对于在线文档,往往由于网速等原因,用起来总不是那么(ma)顺(fan)心。
- 博文以爬取PyODPS Docs 为例,整理页面爬取、转换(PDFKit)、文档整合(PyPDF2)的过程。
- 开发工具
- Anaconda
- Python 2
实现方案
- 基于 bs4 模块标签解析
- 爬取页面,逐层获取获取子链接
- 弃用!未能有效获取到当前主题以及子主题 href 并且不能保证获取到的hrefs的顺序与目录层次结构相对应。
- 基于 正则 定位获取链接
- 有效获取所有 hrefs 并 保证其顺序与目录层次结构的一致性。
代码实现
1 获取主页链接
# coding: utf-8
# ## 爬取 PyODPS[latest] 并转换为 PDF
# - 爬取主链接
# - 根据主链接爬取子连接
# - 参考子链接爬取HTML并转换为PDF
# - 将所有 PDF 整合为一个PDF
# ---
# - 注 :
# - PyOdps PDF在线最新版本
# - 0.3.12
# In[15]:
import re
import pdfkit
import pandas as pd
from urllib import urlopen
from bs4 import BeautifulSoup
# 设置 pandas 显示参数
pd.set_option('display.width',200)
pd.set_option('display.max_rows',1000)
pd.set_option('display.max_columns',50)
pd.set_option('display.max_colwidth',500)
# ### 爬取主链接
# #### 爬取PyODPS Docs主页面
# In[9]:
url='http://pyodps.readthedocs.io/zh_CN/latest/index.html'
html=urlopen(url).read().decode('utf8')
soup=BeautifulSoup(html,'lxml')
# #### 取值最新文档首页 API及标题
# In[10]:
# 主链接 (API)
api=soup.find(name='link', attrs={'rel':'canonical'}).get('href')
# 获取文档标题
title=soup.find('link',attrs={"href":"#","rel":"top"}).get('title').replace(' ','_')
# 获取首页超链接 (href)
hrefs=[]
div_s=soup.find_all(name='div',attrs={'aria-label':'main navigation','role':'navigation'})[0]
for tag_a in div_s.find_all(name='a',attrs={'class':'reference internal'}):
content_name=tag_a.get_text()
url=api+tag_a.get('href')
hrefs.append([content_name,url])
# #### 美化 DataFrame 显示效果函数
# In[20]:
'''
设置悬停效果
'''
def hover(hover_color="#ffff99"):
return dict(selector="tr:hover",
props=[("background-color", "%s" % hover_color)])
'''
美化DataFrame显示效果
'''
def display_prettify(df):
from IPython.display import HTML
styles = [
hover(),
dict(selector="th", props=[("font-size", "100%"),
("text-align", "center")]),
dict(selector="td", props=[("text-align", "left")]),
dict(selector="caption", props=[("caption-side", "left")])
]
return df.style.set_table_styles(styles).set_caption("Hover to highlight.")
# #### 首页超连接(href)打印显示
# In[13]:
df=pd.DataFrame(hrefs, columns=['content_name','href'])
display_prettify(df)
2 参考主链接,获取子链接
# ### 根据主链接爬取子连接
# In[ ]:
hrefs_2=[] # 有序列表,存储主、子链接并与文档目录层次结构保持一致性
for name,url in hrefs:
if url not in [hf[1] for hf in hrefs_2]: # href 不在 hrefs_2中,则追加
hrefs_2.append([name,url])
t_html=urlopen(url).read().decode('utf8')
# 根据正则表达式 查找当前目录主题
f_re='<a class="current reference internal".*?</a><ul>(.*?)</ul>'
if len(re.findall(f_re, t_html, re.I|re.S|re.M)) !=0 :
target_s = re.findall(f_re, t_html, re.I|re.S|re.M)[0]
# 根据正则表达式 获取当前子主题链接
t_re='<a class="reference internal" href="(.*?)">(.*?)</a>'
for href,name in re.findall(t_re, target_s, re.I|re.S|re.M):
if href.strip().endswith('.html'):
hrefs_2.append([name,api+href])
# In[22]:
display_prettify(pd.DataFrame(hrefs_2))
# #### 显示PyODPS 所有链接
# In[105]:
3 根据链接,爬取页面并转换为 PDFs
# ### 参考子链接爬取HTML并转换为PDF
# In[24]:
for name,href in hrefs_2:
pdfkit.from_url(href,'./tmp/'+name+'.pdf')
4 通过 PdfFileMerger 整合 PDF
from PyPDF2 import PdfFileMerger
# 创建 PdfFileMerger 对象,合并PDFs
merger = PdfFileMerger()
for name, url in hrefs_2:
t_input = open('./tmp/'+name+'.pdf', 'rb')
merger.append(t_input)
# 流输出
output = open(title+".pdf", "wb")
merger.write(output)
# 关闭文件流
output.close()
merger.close()
脚本链接
- Python_PyODPS_HTML_to_PDF
Reference Links
- PyODPS
- The OnlinePyODPS PDF 0.3.12
- But the latest is0.7.14
- PyPDF2.utils.PdfReadError:Unexpected destination ‘/WKANCHOR_2’
- Python将HTML转PDF
- pdfkit 0.6.1
- Home page for the PyPDF2 project
- wkhtmltopdf’s github link