无需S3/Lambda:C#借助Amazon Textract提取多页PDF表格至Excel的难题
解决方案:C# .Net 借助Amazon Textract提取多页PDF表格到Excel(无S3/Lambda)
核心思路
处理多页PDF表格必须使用异步分析接口(StartDocumentAnalysis,而非文本检测的StartDocumentTextDetection),且完全可以无需依赖S3、SNS/SQS:直接传入PDF字节流发起异步任务,通过轮询获取分析结果即可。
步骤与代码实现
1. 安装依赖NuGet包
AWSSDK.Textract:AWS Textract官方SDKEPPlus:用于生成Excel文件(可替换为其他Excel操作库)
2. 初始化Textract客户端
using Amazon.Textract; using Amazon.Textract.Model; using OfficeOpenXml; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; // 初始化客户端(建议通过环境变量/AWS CLI配置凭证,避免硬编码) var textractClient = new AmazonTextractClient(RegionEndpoint.USWest2); // 替换为你的AWS区域
3. 提交异步表格分析请求
// 读取本地PDF文件为字节流 byte[] pdfBytes = File.ReadAllBytes(@"C:\your-path\multi-page-table.pdf"); var startRequest = new StartDocumentAnalysisRequest { Document = new Document { Bytes = new MemoryStream(pdfBytes) }, FeatureTypes = new List<string> { "TABLES" } // 指定仅提取表格 }; // 发起异步任务 var startResponse = await textractClient.StartDocumentAnalysisAsync(startRequest); string jobId = startResponse.JobId;
4. 轮询任务结果
GetDocumentAnalysisResponse analysisResult = null; bool isJobFinished = false; // 轮询直到任务完成(建议间隔5-10秒,避免API限流) while (!isJobFinished) { var getRequest = new GetDocumentAnalysisRequest { JobId = jobId }; analysisResult = await textractClient.GetDocumentAnalysisAsync(getRequest); switch (analysisResult.JobStatus) { case JobStatus.SUCCEEDED: isJobFinished = true; break; case JobStatus.FAILED: throw new System.Exception($"任务失败:{analysisResult.StatusMessage}"); default: await Task.Delay(5000); // 等待5秒后再次查询 break; } }
5. 解析表格数据
// 建立块ID映射,方便快速查找子元素 var blockMap = analysisResult.Blocks.ToDictionary(b => b.Id, b => b); var extractedTables = new List<List<List<string>>>(); // 遍历所有检测到的表格 foreach (var tableBlock in analysisResult.Blocks.Where(b => b.BlockType == BlockType.TABLE)) { var currentTable = new List<List<string>>(); // 获取当前表格的所有单元格,按行、列排序 var cells = analysisResult.Blocks .Where(b => b.BlockType == BlockType.CELL && b.ParentIds.Contains(tableBlock.Id)) .OrderBy(b => b.RowIndex) .ThenBy(b => b.ColumnIndex); int currentRowNum = -1; List<string> currentRowCells = null; foreach (var cell in cells) { // 拼接单元格内的所有文本 var cellText = string.Join(" ", blockMap.Where(kv => cell.ChildIds.Contains(kv.Key) && kv.Value.BlockType == BlockType.WORD) .Select(kv => kv.Value.Text)); // 切换新行 if (cell.RowIndex != currentRowNum) { if (currentRowNum != -1) currentTable.Add(currentRowCells); currentRowNum = cell.RowIndex; currentRowCells = new List<string>(); // 填充空列(处理单元格不连续的情况) while (currentRowCells.Count < cell.ColumnIndex - 1) { currentRowCells.Add(string.Empty); } } else { // 填充同一行内的空列 while (currentRowCells.Count < cell.ColumnIndex - 1) { currentRowCells.Add(string.Empty); } } currentRowCells.Add(cellText); } if (currentRowCells != null) currentTable.Add(currentRowCells); extractedTables.Add(currentTable); }
6. 导出到Excel
// 配置EPPlus许可证(非商业用途可使用免费许可证) ExcelPackage.LicenseContext = LicenseContext.NonCommercial; using (var excelPackage = new ExcelPackage()) { int sheetCount = 1; foreach (var table in extractedTables) { var worksheet = excelPackage.Workbook.Worksheets.Add($"表格{sheetCount++}"); int row = 1; foreach (var rowCells in table) { int col = 1; foreach (var cellText in rowCells) { worksheet.Cells[row, col].Value = cellText; col++; } row++; } } // 保存Excel文件 excelPackage.SaveAs(new FileInfo(@"C:\your-path\output-tables.xlsx")); }
关键注意事项
- 异步任务限制:单PDF最多支持1000页,文件大小不超过500MB
- 凭证管理:优先使用AWS SDK默认凭证链(环境变量、
~/.aws/credentials文件、IAM角色),禁止硬编码凭证 - 错误处理:需捕获任务失败、API限流等异常,可添加重试逻辑
- 轮询间隔:避免过于频繁查询,推荐5-10秒一次
内容的提问来源于stack exchange,提问作者StackUseR
相关产品推荐
相关产品推荐

