接上篇文章,導(dǎo)出html文件,我對(duì)這部分代碼進(jìn)行優(yōu)化,提交到github上,為初始版本,后面根據(jù)用戶需求與討論,會(huì)不斷更新優(yōu)化功能
導(dǎo)出Html 表格文件,簡(jiǎn)單易用
https://github.com/CollectBugs/EasyHtml
開(kāi)發(fā)此項(xiàng)目的靈感來(lái)源于一次項(xiàng)目開(kāi)發(fā),發(fā)現(xiàn)導(dǎo)出html表格文件需求,比較常見(jiàn),市面上開(kāi)源、成熟、免費(fèi)的方案沒(méi)有,如果每一家公司,都從零開(kāi)始開(kāi)發(fā),耗時(shí)又費(fèi)力,導(dǎo)致開(kāi)發(fā)周期變長(zhǎng),不如大家開(kāi)源共建此項(xiàng)目,讓后來(lái)人站在巨人的肩膀上進(jìn)行開(kāi)發(fā)與維護(hù),共享資源,其樂(lè)而不為,希望大家多多給與關(guān)注與討論哦!
每天不斷更,精彩不停止,明天見(jiàn),我是行者
記得留個(gè)關(guān)注、點(diǎn)贊、評(píng)論喲,讓我們一起去看星辰大海,品味代碼人生
持原創(chuàng),共同進(jìn)步!請(qǐng)關(guān)注我,后續(xù)分享更精彩!
項(xiàng)目中經(jīng)常有生成圖表報(bào)告的需求。實(shí)現(xiàn)的方式有很多,下面幾種方案,各有優(yōu)缺點(diǎn)。
純java后端實(shí)現(xiàn):后端JFreeChart等繪制庫(kù)畫(huà)好圖表,再通過(guò)itext庫(kù)導(dǎo)出為pdf。該方案能實(shí)現(xiàn)簡(jiǎn)單的圖表功能,樣式、格式調(diào)整等可能會(huì)花大量時(shí)間。適合中小型報(bào)表開(kāi)發(fā)項(xiàng)目。
前端繪制圖表,后端運(yùn)行時(shí)命令調(diào)用wkhtmltopdf生成pdf:后端通過(guò)運(yùn)行時(shí)命令調(diào)用node js,js使用wkhtmltopdf庫(kù)動(dòng)態(tài)訪問(wèn)報(bào)表url地址,HTML內(nèi)容渲染完成后生成pdf文件。該方案,使用純前端js繪制圖表,能實(shí)現(xiàn)復(fù)雜需求。但wkhtmltopdf庫(kù)對(duì)不同瀏覽器的js存在兼容性問(wèn)題,導(dǎo)出成pdf文件時(shí)存在各種坑,在單頁(yè)面技術(shù)支持還不太成熟。適合豐富報(bào)表的pdf導(dǎo)出,但兼容性問(wèn)題維護(hù)成本太高。
前端繪制圖表,后端運(yùn)行時(shí)命令調(diào)用puppeteer生成pdf:后端通過(guò)運(yùn)行時(shí)命令調(diào)用node js,js使用puppeteer庫(kù)動(dòng)態(tài)訪問(wèn)報(bào)表url地址,HTML內(nèi)容渲染完成后生成pdf文件。該方案和wkhtmltopdf方案類(lèi)似,但兼容性更好。puppeteer是 Chrome 開(kāi)發(fā)團(tuán)隊(duì)在 2017 年發(fā)布的一個(gè) Node.js 包,用來(lái)模擬 Chrome 瀏覽器的運(yùn)行。可以在無(wú)界面的環(huán)境中運(yùn)行Chrome或通過(guò)命令行、程序語(yǔ)言操作 Chrome。理論上Chrome中顯示的圖表,就能通過(guò)該庫(kù)生成一致的pdf文件內(nèi)容,不用浪費(fèi)很多時(shí)間在頁(yè)面樣式和兼容性問(wèn)題上。
本文選擇puppeteer方案介紹如何生成一個(gè)pdf報(bào)表。細(xì)心的小伙伴可能注意到了,既然puppeteer是js庫(kù),為什么不直接前端導(dǎo)出pdf,干嘛這么麻煩還通過(guò)后端繞一圈來(lái)實(shí)現(xiàn)?
這主要出于需求和用戶體驗(yàn)的考慮,有些業(yè)務(wù)場(chǎng)景需要通過(guò)api接口動(dòng)態(tài)生成pdf報(bào)表,不需要用戶訪問(wèn)界面。如果生成的pdf的報(bào)表很大,直接在用戶端生成,可能占用大量客戶端資源,導(dǎo)致頁(yè)面崩潰或假死,從而影響使用體驗(yàn)。
1.先安裝NodeJs,網(wǎng)上教程很多,本文不再贅述。
2.安裝puppeteer依賴(lài),如果npm下載不成功就使用cnpm命令(cnpm需要先安裝)
npm install puppeteer --save
3.在安裝puppeteer依賴(lài)的目錄下創(chuàng)建page2pdf.js
const puppeteer = require('puppeteer');
const options = process.argv;
var siteUrl;
//執(zhí)行 node page2pdf.js https://www.baidu.com
(async() => {
if(options.length>=3){
siteUrl=options[2];
//types=options[3];
//console.log(siteUrl);
}
const browser = await puppeteer.launch();
const page = await browser.newPage();
//console.log(options.length);
//console.log(options[0]);
//console.log(options[1]);
//console.log(options[2]);
//console.log(options[3]);
const userAgent = "Mozilla/5.0 (Linux; Android 8.1.0; MI 8 Build/OPM1.171019.011; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/62.0.3202.84 Mobile Safari/537.36";
page.setUserAgent(userAgent);
await page.setViewport({ width: 1000, height: 1080 });
//await page.setViewport({ width: 480, height: 800,isMobile: true});
//通過(guò)css樣式可見(jiàn),動(dòng)態(tài)設(shè)置站點(diǎn)加載完成標(biāo)識(shí)。
//page.waitForSelector('img').then(() => console.log('siteUrl with page load success: ' + siteUrl));
await page.goto(siteUrl, {timeout: 10*60000, waitUntil: 'networkidle2'});
/**await page.goto(siteUrl, {timeout: 10*60000, waitUntil: 'networkidle2'})
.catch(e => {
console.log(siteUrl+" is error:"+e);
browser.close()
});*/
const pdf = await page.pdf({
path: 'page.pdf', //便于測(cè)試驗(yàn)證,實(shí)際使用時(shí)可屏蔽
format: 'A4'
});
await browser.close();
process.stdout.write(pdf);
})();
page2pdf.js文件引入puppeteer依賴(lài)庫(kù),通過(guò)傳入siteUrl參數(shù)訪問(wèn)HTML page頁(yè)面,page.pdf生成文件,再通過(guò)process.stdout.write(pdf)返回java后臺(tái)。
4.創(chuàng)建java PuppeteerHtmlToPdf.java文件
/**
* 用谷歌提供的node實(shí)現(xiàn)的Puppeteer,實(shí)現(xiàn)網(wǎng)頁(yè)生成pdf文件
*/
public class PuppeteerHtmlToPdf {
/**
* html轉(zhuǎn)pdf,直接通過(guò)流輸出到瀏覽器
* @param response 瀏覽器響應(yīng)
* @param fileName 文件名稱(chēng)
* @param puppeteerjs 要采用哪個(gè)js文件執(zhí)行
* @param webSiteUrl 要生成pdf的網(wǎng)頁(yè)
*/
public static void parseHtml2Pdf(HttpServletResponse response, String fileName, String puppeteerjs, String webSiteUrl) {
try {
Runtime rt = Runtime.getRuntime();
Process p = rt.exec("node "+puppeteerjs+" "+webSiteUrl);
InputStream is = p.getInputStream();
BufferedInputStream bf=new BufferedInputStream(is);
byte[] data = IOUtils.toByteArray(bf);
fileName = URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
response.addHeader("Content-Length", "" + data.length);
response.setContentType("application/octet-stream;charset=UTF-8");
OutputStream outputStream = new BufferedOutputStream(response.getOutputStream());
outputStream.write(data);
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
5.報(bào)表生成
page2pdf.js頁(yè)面目錄打開(kāi)命令行,執(zhí)行指令。
運(yùn)行指令,生成pdf
node page2pdf.js https://www.baidu.com
查看對(duì)應(yīng)目錄,已動(dòng)態(tài)生成了一個(gè)page.pdf文件
打開(kāi)pdf文件,對(duì)應(yīng)HTML內(nèi)容已生成。
本文介紹了報(bào)表導(dǎo)出pdf的3種方式,通過(guò)優(yōu)缺點(diǎn)分析,詳細(xì)闡述了puppeteer的實(shí)現(xiàn)方式。并通過(guò)百度頁(yè)面的pdf導(dǎo)出做了演示。
希望本文對(duì)有類(lèi)似報(bào)表pdf導(dǎo)出需求的小伙伴有所參考和幫助。若存在不足或更好方案,請(qǐng)留言討論。
數(shù)據(jù)分析中,將數(shù)據(jù)以表格的形式呈現(xiàn)出來(lái)是必不可少的環(huán)節(jié),Pandas 是一個(gè)非常強(qiáng)大的數(shù)據(jù)分析庫(kù),提供了很多方便的方法來(lái)處理和展示數(shù)據(jù)。今天,我們將學(xué)習(xí)如何使用 Pandas 自定義表格樣式并將其導(dǎo)出為 HTML 格式。
通過(guò)這種方式,我們可以更好地組織和展示數(shù)據(jù),并在網(wǎng)頁(yè)上共享我們的分析結(jié)果,并且,掌握Pandas數(shù)據(jù)存儲(chǔ)和表格樣式自定義的方式,在日常工作過(guò)程中有更多應(yīng)用和實(shí)踐意義,將拓展我們的數(shù)據(jù)分析思路。
首先,導(dǎo)入pandas庫(kù),并為其設(shè)置別名pd,使用pandas的read_excel函數(shù)讀取指定路徑下的Excel文件,并將其內(nèi)容存儲(chǔ)在DataFrame對(duì)象df中。
import pandas as pd
df = pd.read_excel(r'C:\Users\shangtianqiang\Desktop\2023年胡潤(rùn)百富榜.xlsx')
#默認(rèn)顯示DataFrame的前五行。
df.head()
df.info()顯示DataFrame的簡(jiǎn)要信息,包括索引、列名、數(shù)據(jù)類(lèi)型和每列的非空值數(shù)量,這里顯示該數(shù)據(jù)表含有1241行數(shù)據(jù)。
#數(shù)據(jù)預(yù)覽
df.info()
使用iloc方法篩選DataFrame的前100行數(shù)據(jù)。
df=df.iloc[:100,:]#篩選前100行數(shù)據(jù)
df
定義一個(gè)樣式對(duì)象style,該對(duì)象用于生成HTML的樣式,這里對(duì)篩選出來(lái)的前100行的數(shù)據(jù)進(jìn)行了樣式設(shè)置,它定義了一個(gè)居中的標(biāo)題(h1標(biāo)簽),一個(gè)表格(table標(biāo)簽),以及表格中的表頭(th標(biāo)簽)和單元格(td標(biāo)簽)。
# 定義CSS樣式,添加標(biāo)題“2023年胡潤(rùn)百富榜”
style = """
<style>
h1 {
text-align: center;
font-size: 24px;
margin-bottom: 10px;
}
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid black;
padding: 8px;
text-align: center;
}
th {
background-color: #f2f2f2;
}
</style>
<head><title>2023年胡潤(rùn)百富榜</title></head>
<h1>2023年胡潤(rùn)百富榜</h1>
"""
將DataFrame轉(zhuǎn)換為HTML代碼,并添加樣式,index=False來(lái)去除行索引 。
# 將DataFrame轉(zhuǎn)換為HTML代碼,并添加樣式
html = style + df.to_html(index=False) # 使用index=False來(lái)避免顯示行索引
將生成的HTML內(nèi)容寫(xiě)入到名為'2023年胡潤(rùn)百富榜.html'的文件中。
# 將HTML代碼寫(xiě)入文件或打印到控制臺(tái)
with open('2023年胡潤(rùn)百富榜.html', 'w') as file:
file.write(html) # 將HTML代碼寫(xiě)入文件output.html
完整版的代碼如下所示。
import pandas as pd
df = pd.read_excel(r'C:\Users\shangtianqiang\Desktop\2023年胡潤(rùn)百富榜.xlsx')
df=df.iloc[:100,:]#篩選前100行數(shù)據(jù)
# 定義CSS樣式,添加標(biāo)題“2023年胡潤(rùn)百富榜”
style = """
<style>
h1 {
text-align: center;
font-size: 24px;
margin-bottom: 10px;
}
table {
border-collapse: collapse;
width: 100%;
}
th, td {
border: 1px solid black;
padding: 8px;
text-align: center;
}
th {
background-color: #f2f2f2;
}
</style>
<head><title>2023年胡潤(rùn)百富榜</title></head>
<h1>2023年胡潤(rùn)百富榜</h1>
"""
# 將DataFrame轉(zhuǎn)換為HTML代碼,并添加樣式
html = style + df.to_html(index=False) # 使用index=False來(lái)避免顯示行索引
# 將HTML代碼寫(xiě)入文件或打印到控制臺(tái)
with open('2023年胡潤(rùn)百富榜.html', 'w') as file:
file.write(html) # 將HTML代碼寫(xiě)入文件output.html
導(dǎo)出的HTML表格樣式如下所示,整體圖表風(fēng)格較為簡(jiǎn)潔。
html的格式數(shù)據(jù)也是數(shù)據(jù)存儲(chǔ)的一種方式,使用read_html命令可以將其很便捷地導(dǎo)入,從而進(jìn)行接下來(lái)的數(shù)據(jù)分析。
import pandas as pd
df_html=pd.read_html('2023年胡潤(rùn)百富榜.html',encoding='gbk')[0]
df_html
通過(guò)學(xué)習(xí)如何使用 Pandas 自定義表格樣式并將其導(dǎo)出為 HTML 格式,我們掌握了更豐富的數(shù)據(jù)處理和展示技巧,并且,還可以根據(jù)實(shí)際業(yè)務(wù)需求來(lái)自定義表格樣式,實(shí)現(xiàn)與他人共享數(shù)據(jù)的目的。
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。