C#实现服务器URL对应PDF文件逐行内容读取的方法
C# 从远程PDF流逐行提取文本实现方案
你现在拿到的是PDF二进制流,没法直接用普通文本流的ReadLine方法读出行内容——PDF本身是结构化二进制格式,没有原生“行”的概念,所有文本都是带坐标的独立块,必须用专门的解析库处理,推荐用开源无依赖的PdfPig,不需要把PDF存本地,直接对接你已经拿到的内存流就能解析。
实现步骤
- 首先给项目安装Nuget包:
PdfPig - 拿到PDF响应流后先做响应校验,避免把鉴权失败返回的HTML内容当PDF解析
- PDF坐标原点在页面左下角,纵向Y坐标差值在阈值内的文本属于同一行,按坐标分组、同组内按横向X坐标从左到右拼接,就能得到符合阅读顺序的逐行内容
- 提取到的逐行文本直接存入集合,后续导出Excel直接遍历集合即可
完整可运行代码
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using UglyToad.PdfPig; using UglyToad.PdfPig.Content; public class Program { // 全局静态HttpClient,避免重复实例化导致端口耗尽 private static readonly HttpClient client = new HttpClient(); public static async Task Main() { var pdfUrl = "你后续替换成最新的有效PDF地址即可"; var response = await client.GetAsync(pdfUrl); // 校验请求是否成功,失败直接抛出异常,避免解析错误内容 response.EnsureSuccessStatusCode(); using (var stream = await response.Content.ReadAsStreamAsync()) using (var pdfDocument = PdfDocument.Open(stream)) { List<string> allPdfLines = new List<string>(); // 遍历PDF所有页面 foreach (var page in pdfDocument.GetPages()) { // 行判定阈值:Y坐标差小于5像素判定为同一行,可根据PDF实际排版调整 const double lineThreshold = 5; var words = page.GetWords().OrderByDescending(w => w.BoundingBox.Bottom).ToList(); if (!words.Any()) { Console.WriteLine($"第{page.Number}页无文本层,可能是扫描件,需要加OCR逻辑才能提取内容"); continue; } // 按行分组拼接 var currentLineBaseY = words[0].BoundingBox.Bottom; List<Word> currentLineWords = new List<Word> { words[0] }; for (int i = 1; i < words.Count; i++) { var word = words[i]; if (Math.Abs(word.BoundingBox.Bottom - currentLineBaseY) <= lineThreshold) { currentLineWords.Add(word); } else { // 同一行内按从左到右顺序拼接文本 var lineText = string.Join(" ", currentLineWords.OrderBy(w => w.BoundingBox.Left).Select(w => w.Text)); allPdfLines.Add(lineText); // 逐行打印 Console.WriteLine(lineText); // 重置行缓存 currentLineBaseY = word.BoundingBox.Bottom; currentLineWords = new List<Word> { word }; } } // 处理页面最后一行 if (currentLineWords.Any()) { var lastLineText = string.Join(" ", currentLineWords.OrderBy(w => w.BoundingBox.Left).Select(w => w.Text)); allPdfLines.Add(lastLineText); Console.WriteLine(lastLineText); } } // 此处allPdfLines就是存储了PDF所有行内容的集合,直接传入Excel导出逻辑即可 } } }
注意事项
- 如果运行时报PDF格式错误,先把流存为本地文件确认内容是否为真的PDF,部分地址会做鉴权拦截返回登录页、错误页的HTML内容,会导致解析失败
- 行判定阈值
lineThreshold可根据你的PDF实际行间距调整,数值越大越容易把上下距离近的文本判定为同一行 - 你提到的URL3小时失效问题,后续只需要替换
pdfUrl变量的值即可,解析逻辑不需要改动
内容的提问来源于stack exchange,提问作者Gouveia
相关产品推荐
相关产品推荐

