Python爬蟲系列之四:利用Python爬取PyODPS頁面並整合成PDF文件
阿新 • • 發佈:2019-01-02
文章架構
開發場景
- 在日常開發過程中, 經常需要參考一些文件。對於線上文件,往往由於網速等原因,用起來總不是那麼(ma)順(fan)心。
- 開發工具
- 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]:
pd.DataFrame(hrefs_2)
3 根據連結,爬取頁面並轉換為 PDFs
# ### 參考子連結爬取HTML並轉換為PDF
# In[24]:
for name,href in hrefs_2:
pdfkit.from_url(href,'./tmp/'+name+'.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()