第三方平台輸出的 .xls 實為 MHTML (MIME HTML) 格式,內容為 Content-Transfer-Encoding: quoted-printable 編碼的 HTML 表格(如 =E4=B8=AD 代表「中」)。POI/JXL 無法直接解析。
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j</artifactId>
<version>0.8.7</version>
</dependency>
// 1. 解析 MIME 結構
MimeMessageParser parser = new MimeMessageParser(new MimeStreamParser().parse(new FileInputStream("fake.xls")));
parser.parse();
// 2. 取得 text/html 部分
String html = parser.getHtmlContent(); // 或遍歷 body parts 找 text/html
// 3. Quoted-Printable 解碼
String decoded = MimeUtility.decodeText(html.replace("=\r\n", "")); // 移除軟換行
// 4. 解析 HTML 表格 → POI 寫入真實 .xlsx
Document doc = Jsoup.parse(decoded);
Element table = doc.select("table").first();
Workbook wb = new XSSFWorkbook();
Sheet sh = wb.createSheet();
int r = 0;
for (Element row : table.select("tr")) {
Row xr = sh.createRow(r++);
int c = 0;
for (Element cell : row.select("td,th")) {
xr.createCell(c++).setCellValue(cell.text());
}
}
try (FileOutputStream fos = new FileOutputStream("real.xlsx")) { wb.write(fos); }
// Linux/Mac/Windows 均可
libreoffice --headless --convert-to xlsx:"Calc MS Excel 2007 XML" --outdir /output /input/*.xls
--headless 已解決)。import quopri, re, pandas as pd
from bs4 import BeautifulSoup
def mhtml_to_xlsx(src, dst):
with open(src, 'rb') as f: raw = f.read()
# 簡易提取 HTML 部分(實際建議用 email.parser)
html_part = re.search(b'Content-Type: text/html.*?\r\n\r\n(.*?)\r\n--', raw, re.DOTALL)
if not html_part: return
html = quopri.decodestring(html_part.group(1)).decode('utf-8', errors='ignore')
tables = pd.read_html(html)
if tables:
tables[0].to_excel(dst, index=False)
# 批量
for f in glob.glob('input/*.xls'):
mhtml_to_xlsx(f, f.replace('input', 'output').replace('.xls', '.xlsx'))
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| Java + mime4j + Jsoup + POI | 純 Java、嵌入服務、可定製清洗邏輯 | 代碼量大、需處理 MIME 邊界情況 | Java 微服務、需在線轉換 |
| LibreOffice headless | 零代碼、兼容性極強、保留樣式 | 啟動慢、佔記憶體、需安裝辦公套件 | 離線批量、定時任務、格式複雜 |
| Python 腳本 | 輕量、開發快、生態豐富 | 需額外運行時、大文件效能一般 | 運維腳本、一次性遷移、團隊懂 Python |
text/html。=\r\n 後再解碼。pd.read_html 或 Jsoup 選第一個 <table> 通常足夠;複雜情況需自行遍歷 DOM。.xlsx (OOXML),避免 .xls 65535 行限制。根據團隊技術棧、部署環境、實時性要求選擇;LibreOffice 批量轉換通常性價比最高。