Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/vba/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Excel 从PDF中提取数据并添加到工作表_Excel_Vba_Pdf - Fatal编程技术网

Excel 从PDF中提取数据并添加到工作表

Excel 从PDF中提取数据并添加到工作表,excel,vba,pdf,Excel,Vba,Pdf,我试图将PDF文档中的数据提取到工作表中。PDF显示和文本可以手动复制并粘贴到Excel文档中 我目前正在通过SendKeys执行此操作,但它不起作用。尝试粘贴PDF文档中的数据时出错。为什么我的粘贴不起作用?如果在宏停止运行后粘贴,它将按正常方式粘贴 Dim myPath As String, myExt As String Dim ws As Worksheet Dim openPDF As Object 'Dim pasteData As MSForms.DataObject Dim fC

我试图将PDF文档中的数据提取到工作表中。PDF显示和文本可以手动复制并粘贴到Excel文档中

我目前正在通过SendKeys执行此操作,但它不起作用。尝试粘贴PDF文档中的数据时出错。为什么我的粘贴不起作用?如果在宏停止运行后粘贴,它将按正常方式粘贴

Dim myPath As String, myExt As String
Dim ws As Worksheet
Dim openPDF As Object
'Dim pasteData As MSForms.DataObject
Dim fCell As Range

'Set pasteData = New MSForms.DataObject
Set ws = Sheets("DATA")
If ws.Cells(ws.Rows.Count, "A").End(xlUp).Row > 1 Then Range("A3:A" & ws.Cells(ws.Rows.Count, "A").End(xlUp).Row).ClearContents

myExt = "\*.pdf"
'When Scan Receipts Button Pressed Scan the selected folder/s for receipts
For Each fCell In Range(ws.Cells(1, 1), ws.Cells(1, ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column))
    myPath = Dir(fCell.Value & myExt)
    Do While myPath <> ""
        myPath = fCell.Value & "\" & myPath
        Set openPDF = CreateObject("Shell.Application")
        openPDF.Open (myPath)
        Application.Wait Now + TimeValue("00:00:2")
        SendKeys "^a"
        Application.Wait Now + TimeValue("00:00:2")
        SendKeys "^c"
        'Application.Wait Now + TimeValue("00:00:2")
        ws.Select
        ActiveSheet.Paste
        'pasteData.GetFromClipboard

        'ws.Cells(3, 1) = pasteData.GetText
        Exit Sub

        myPath = Dir
    Loop

Next fCell
Dim myPath作为字符串,myExt作为字符串
将ws设置为工作表
Dim openPDF作为对象
'将数据作为MSForms.DataObject粘贴
变暗fCell As范围
'设置粘贴数据=新的MSForms.DataObject
设置ws=图纸(“数据”)
如果ws.Cells(ws.Rows.Count,“A”).End(xlUp).Row>1,则范围(“A3:A”和ws.Cells(ws.Rows.Count,“A”).End(xlUp).Row.ClearContent
myExt=“\*.pdf”
'当按下扫描收据按钮时,扫描所选文件夹中的收据
对于范围内的每个fCell(ws.Cells(1,1),ws.Cells(1,ws.Cells(1,ws.Columns.Count).End(xlToLeft.Column))
myPath=Dir(fCell.Value&myExt)
在myPath“”时执行此操作
myPath=fCell.Value&“\”&myPath
设置openPDF=CreateObject(“Shell.Application”)
openPDF.Open(myPath)
应用程序。立即等待+时间值(“00:00:2”)
发送密钥“^a”
应用程序。立即等待+时间值(“00:00:2”)
发送密钥“^c”
'Application.Wait Now+时间值(“00:00:2”)
ws.Select
活动表。粘贴
'pasteData.GetFromClipboard
'ws.Cells(3,1)=pasteData.GetText
出口接头
myPath=Dir
环
下一个fCell

您可以使用Adobe library打开PDF文件并提取其内容(我相信您可以将其作为SDK的一部分从Adobe下载,但它还附带某些版本的Acrobat)

确保也将库添加到引用中(在我的机器上,它是Adobe Acrobat 10.0类型库,但不确定它是否是最新版本)

即使使用Adobe library,它也不是微不足道的(您需要添加自己的错误捕获等):

这与您尝试做的基本相同——只使用Adobe自己的库。它一次浏览一个PDF页面,突出显示页面上的所有文本,然后将其(一次一个文本元素)放入字符串中

记住,从中获取的所有类型的非打印字符(行提要、换行符等)甚至可能在类似连续文本块的中间结束,因此您可能需要额外的代码在使用之前清理它。


希望有帮助

随着时间的推移,我发现以结构化格式从PDF中提取文本是一件困难的事情。但是,如果您正在寻找一个简单的解决方案,您可能需要考虑工具<代码> PDFTOTEX< /COD> 提取文本的伪代码包括:

  • 使用
    SHELL
    VBA语句使用
  • 使用顺序文件读取语句将临时文件内容读入字符串
  • 将字符串粘贴到Excel中
  • 简化示例如下:

        Sub ReadIntoExcel(PDFName As String)
            'Convert PDF to text
            Shell "C:\Utils\pdftotext.exe -layout " & PDFName & " tempfile.txt"
    
            'Read in the text file and write to Excel
            Dim TextLine as String
            Dim RowNumber as Integer
            Dim F1 as Integer
            RowNumber = 1
            F1 = Freefile()
            Open "tempfile.txt" for Input as #F1
                While Not EOF(#F1)
                    Line Input #F1, TextLine
                    ThisWorkbook.WorkSheets(1).Cells(RowNumber, 1).Value = TextLine
                    RowNumber = RowNumber + 1
                Wend
            Close #F1
        End Sub
    

    通过用户交互模拟进行复制和粘贴可能不可靠(例如,出现弹出窗口并切换焦点)。您可能有兴趣尝试专门设计用于从PDF中提取数据的广告,它可以从VBA中工作。它还能够使用CSV从发票和表格中提取数据

    下面是用于Excel的VBA代码,用于从给定位置提取文本并将其保存到
    工作表1的单元格中:

    Private Sub CommandButton1_Click()
    
    ' Create TextExtractor object
    ' Set extractor = CreateObject("Bytescout.PDFExtractor.TextExtractor")
    Dim extractor As New Bytescout_PDFExtractor.TextExtractor
    
    extractor.RegistrationName = "demo"
    extractor.RegistrationKey = "demo"
    
    ' Load sample PDF document
    extractor.LoadDocumentFromFile ("c:\sample1.pdf")
    
    ' Get page count
    pageCount = extractor.GetPageCount()
    
    Dim wb As Workbook
    Dim ws As Worksheet
    Dim TxtRng  As Range
    
    Set wb = ActiveWorkbook
    Set ws = wb.Sheets("Sheet1")
    
    For i = 0 To pageCount - 1
                RectLeft = 10
                RectTop = 10
                RectWidth = 100
                RectHeight = 100
    
                ' check the same text is extracted from returned coordinates
                extractor.SetExtractionArea RectLeft, RectTop, RectWidth, RectHeight
                ' extract text from given area
                extractedText = extractor.GetTextFromPage(i)
    
                ' insert rows
                ' Rows(1).Insert shift:=xlShiftDown
                ' write cell value
                 Set TxtRng = ws.Range("A" & CStr(i + 2))
                 TxtRng.Value = extractedText
    
    Next
    
    Set extractor = Nothing
    
    
    End Sub
    
    披露:我与ByteScout有关,使用是一个很好的选择。它价格便宜,提供了大量与PDF相关的功能。上面的一个答案指向GitHub上的死页Bytescout。我提供了一个相关的工作样本,从PDF中提取表格。您可以使用它以任何格式导出

    Set extractor = CreateObject("Bytescout.PDFExtractor.StructuredExtractor")
    
    extractor.RegistrationName = "demo"
    extractor.RegistrationKey = "demo"
    
    ' Load sample PDF document
    extractor.LoadDocumentFromFile "../../sample3.pdf"
    
    For ipage = 0 To extractor.GetPageCount() - 1 
    
        ' starting extraction from page #"
        extractor.PrepareStructure ipage
    
        rowCount = extractor.GetRowCount(ipage)
    
        For row = 0 To rowCount - 1 
            columnCount = extractor.GetColumnCount(ipage, row)
    
            For col = 0 To columnCount-1
                WScript.Echo "Cell at page #" +CStr(ipage) + ", row=" & CStr(row) & ", column=" & _
                    CStr(col) & vbCRLF & extractor.GetCellValue(ipage, row, col)
            Next
        Next
    Next
    

    这里提供了更多示例:

    由于我不喜欢依赖外部库和/或其他程序,因此我扩展了您的解决方案,使其能够正常工作。 这里的实际更改是使用GetFromClipboard函数,而不是主要用于粘贴一系列单元格的Paste函数。 当然,缺点是用户不能在整个过程中改变焦点或干预

    Dim pathPDF As String, textPDF As String
    Dim openPDF As Object
    Dim objPDF As MsForms.DataObject
    
    pathPDF = "C:\some\path\data.pdf"
    Set openPDF = CreateObject("Shell.Application")
    openPDF.Open (pathPDF)
    'TIME TO WAIT BEFORE/AFTER COPY AND PASTE SENDKEYS
    Application.Wait Now + TimeValue("00:00:2")
    SendKeys "^a"
    Application.Wait Now + TimeValue("00:00:2")
    SendKeys "^c"
    Application.Wait Now + TimeValue("00:00:1")
    
    AppActivate ActiveWorkbook.Windows(1).Caption
    objPDF.GetFromClipboard
    textPDF = objPDF.GetText(1)
    MsgBox textPDF
    

    如果您有兴趣在中查看我的项目。

    为了改进Slinky Sloth的解决方案,我必须在从剪贴板获取之前添加以下内容:

    Set objPDF = New MSForms.DataObject
    

    遗憾的是,它不适用于10页的pdf。

    这似乎不适用于Adobe类型库。它一打开,我就得到一个429错误。Acrobat工作得很好,但…

    我知道这是一个老问题,但我只是为了工作中的一个项目才这样做,我很惊讶还没有人想到这个解决方案: 只要用Microsoft word打开.pdf即可。

    当您试图从.docx中提取数据时,使用该代码要容易得多,因为它是在Microsoft Word中打开的。Excel和Word都是Microsoft程序,因此两者配合得很好。在我的例子中,问题文件必须是.pdf文件。以下是我提出的解决方案:

  • 选择默认程序以打开Microsoft Word中的.pdf文件
  • 第一次使用word打开.pdf文件时,会弹出一个对话框,声称word需要将.pdf文件转换为.docx文件。单击左下角的“不再显示此邮件”复选框,然后单击“确定”
  • 创建从.docx文件中提取数据的宏。我用它作为一个资源
  • 修改MoveDown、MoveRight和Find.Execute方法以满足任务的需要

  • 是的,您可以将.pdf文件转换为.docx文件,但在我看来,这是一个简单得多的解决方案。

    Adobe Library绝对是一个不错的选择。需要注意的是,它可以比您显示的功能更强大,因为它可以从单个文本框块或其他对象中获取文本,这可能更简洁
    Set objPDF = New MSForms.DataObject