XL 2016 VBA - Récupérer le texte d'un fichier PDF

Dudu2

XLDnaute Barbatruc
Bonjour,

Y a-t-il un moyen de chercher et récupérer du texte directement dans un PDF sans avoir à l'ouvrir / tout sélectionner / copier dans le clipboard texte ?

Merci pour toute information.

Edit: Titre modifié pour mieux refléter la solution de cette longue discussion.
 
Dernière édition:

patricktoulon

XLDnaute Barbatruc
en dessous 2019
contexte gratuit
  • soit la méthode cromagnon avec la fenêtre et les api ou le webbrowser dans userform
  • soit pdfcreator v 1.7 (gratuit)( se rapprocher de kiki69 pour plus de details sur ce point)
  • soit le kit xpdf (en ligne de commande peut etre piloté par vba) et la fonction pdftotext
pour le contexte payant il y a moulte solution et app ,plus ou moins pilotables par vba

il y a aussi les convertisseur en lignes certains gratuit mais perso je ne mettrais pas des document plus ou moins important en ligne ,mais ca n'est que mon opinion
 

Dudu2

XLDnaute Barbatruc
Pour le moment j'arrive à récupérer le texte d'un PDF de manière rudimentaire en lançant Chrome avec le fichier PDF en URL, en envoyant Ctrl A puis Ctrl C puis Alt {F4} puis Ctrl V en A1.

Me problème est que ce code ne fonctionne pas chez la personne à qui il est destiné sans que j'aie pu débuguer chez elle. Cette personne n'est pas sous Office 2021.
 

patricktoulon

XLDnaute Barbatruc
re
ryu
non un pdf est un encodage special tu recevrais du charabia
@Dudu2
dans le pire des cas fait un multi app
chrome, firefox,etc..(les plus utilisés ) le reste (les sendkeys et tout y cointi c'est pareil
au debut faire un dir sur le chemin chrome 32 et 64
pareil pour firefox
selon l'app trouvé tu la shell en maximisedfocus c'est tout
 

Dudu2

XLDnaute Barbatruc
Oui, j'ai testé les 2 chemins:
- C:\Program Files\Google\Chrome\Application\chrome.exe
- C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
La personne en question a Chrome 32bits.
selon l'app trouvé tu la shell en maximisedfocus c'est tout
En effet, c'est ce que je fais, en NormalFocus.

VB:
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

'-----------------------------------------
'Open a PDF and copy the text in the sheet
'-----------------------------------------
Function GetPDFTextViaExcel(FichierPDF As String) As String
    Dim ChromeExe As String
    '
    Const Chrome64 = "C:\Program Files\Google\Chrome\Application\chrome.exe"
    Const Chrome32 = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
    
    If Len(Dir(Chrome64)) > 0 Then
        ChromeExe = Chrome64
    ElseIf Len(Dir(Chrome32)) > 0 Then
        ChromeExe = Chrome32
    Else
        MsgBox "Chrome.exe non trouvé !"
        Exit Function
    End If

    'Run Chrome
    Call Shell(ChromeExe & " --new-window -url " & """" & FichierPDF & """", vbNormalFocus)
    Sleep 2000
    
    'Send keys to Select All / Copy / Kill the application
    CreateObject("wscript.shell").SendKeys "^a"
    Temporisation 100
    CreateObject("wscript.shell").SendKeys "^c"
    Temporisation 100
    CreateObject("wscript.shell").SendKeys "%{F4}"
    Temporisation 10000
    
    With ThisWorkbook.Worksheets(1)
        .[A1].Select
        .[A1].ClearContents
        CreateObject("wscript.shell").SendKeys "^v"
        Temporisation 100
        Application.ScreenUpdating = True
        GetPDFTextViaExcel = .[A1].Value
    End With
End Function

'-------------
'Temporisation
'-------------
Private Sub Temporisation(NbDoEvents As Integer)
    Dim k As Integer
    
    For k = 1 To NbDoEvents
        DoEvents
    Next k
End Sub
 

Dudu2

XLDnaute Barbatruc
Chez la personne concernée je soupçonne le Sleep 2000 de ne pas être suffisant.
Ajouter du temps reste arbitraire.
Il faudrait que je trouve un moyen de tester via l'API quand Chrome est prêt, celui lancé par le Shell ou dans le pire des cas, le seul processus Chrome actif si on exige qu'il n'y en ait pas qui tourne indépendamment de ce code.

Peut-être un FindWindow sur le nom du PDF qui semble être le nom de la fenêtre Chrome ?
 

patricktoulon

XLDnaute Barbatruc
re
chez moi le ctrl+V à la fin ne fonctionne pas
en effet le ctrl+V fonctionne quand le clipborad n'est pas en train de bouffer de la donné
le paste colle progressivement
donc j'ai remplacé par .paste dans le bloc with
j'ai ajouté firefox
perso j'ai reduit les temps partout
VB:
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

'-----------------------------------------
'Open a PDF and copy the text in the sheet
'-----------------------------------------
Function GetPDFTextViaExcel(FichierPDF As String) As String
    Dim nav$
    '
    Const nav1 = "C:\Program Files\Google\Chrome\Application\chrome.exe"
    Const nav2 = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
    Const nav3 = "C:\Program Files\Mozilla Firefox\firefox.exe"
    Const nav4 = "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"
 
   
    Select Case True
    Case Dir(nav3) <> "": nav = nav3 'je met le nav3 en premier je préfère firefox64 comme j' ai les deux
    Case Dir(nav1) <> "": nav = nav1
    Case Dir(nav2) <> "": nav = nav2
    Case Dir(nav4) <> "": nav = nav4
    Case Else
    End Select
   
   

    'Run Chrome
    Call Shell(nav & " --new-window -url " & """" & FichierPDF & """", vbNormalFocus)
    Sleep 3000
   
    'Send keys to Select All / Copy / Kill the application
    CreateObject("wscript.shell").SendKeys "^a"
    Temporisation 50
    CreateObject("wscript.shell").SendKeys "^c"
    Temporisation 50
    CreateObject("wscript.shell").SendKeys "%{F4}"
    Temporisation 100
    ThisWorkbook.Activate ' sait on jamais
    With ThisWorkbook.Worksheets(1)
        .[A1].Select
        .[A1].ClearContents
        'CreateObject("wscript.shell").SendKeys "^v"'ne fonctionne pas chez moi
        .Paste
        Temporisation 50
        'Application.ScreenUpdating = True
        GetPDFTextViaExcel = .[A1].Value
    End With
End Function

'-------------
'Temporisation
'-------------
Private Sub Temporisation(NbDoEvents As Integer)
    Dim k As Integer
     For k = 1 To NbDoEvents
        DoEvents
    Next k
End Sub

Sub test()
GetPDFTextViaExcel "C:\Users\patricktoulon\Desktop\trier un tableau avec la fonction sort d'excel 2023.pdf"
End Sub
j'ai ma petite idée pour une gestion d'attente ;)
 

patricktoulon

XLDnaute Barbatruc
alors si on prenait le problème à l'envers
ça te dit
ramenons la chose a sa plus simple définition
le problème c'est quoi
c'est la gestion du temps entre l'appel de la fonction et le return
qui est gérée dans ta version par des sleep et pseudo wait harbitraire
et si on attendait tout simplement que le clipboard soit plein ? ;)
on va donc laisser un sleep minimum (1 seconde)pour le reday de la fenêtre(indispensable!!)
et pour les autres wait on les réduit a peau de chagrin dans un do loop tant que le clipborad est vide
et donc le sendkeys"%F4" ne se fera que quand c'est bon
VB:
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

'-----------------------------------------
'Open a PDF and copy the text in the sheet
'Autor;[@Dudu2] on exceldownloads
'code redesigned by [@patricktoulon] on exceldownloads
'adding Chrome firefox control in an select case
'reduction of (window ready wait times) for  (chrome or firefox)
'added clipboard management
'non-empty clipboard wait loop
'loading time lasts the time the clipboard takes to load the data
'-----------------------------------------
Function GetPDFTextViaExcel(FichierPDF As String) As String
    Dim nav$, T$, clip As Object, wshsell As Object
    '
    Const nav1 = "C:\Program Files\Google\Chrome\Application\chrome.exe"
    Const nav2 = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
    Const nav3 = "C:\Program Files\Mozilla Firefox\firefox.exe"
    Const nav4 = "C:\Program Files (x86)\Mozilla Firefox\firefox.exe"


    Select Case True
    Case Dir(nav3) <> "": nav = nav3    'je met le nav3 en premier je préfère firefox64
    Case Dir(nav1) <> "": nav = nav1
    Case Dir(nav2) <> "": nav = nav2
    Case Dir(nav4) <> "": nav = nav4
    Case Else
    End Select

    'on vide le clipboard
    'on crée l'object(late binding)
    Set clip = CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}")
    clip.SetText "": clip.PutInClipboard

    'Run Chrome
    Call Shell(nav & " --new-window -url " & """" & FichierPDF & """", vbNormalFocus)
    Sleep 1000    'on laisse quand même un minimum de 1 seconde
  
    Set wshshell = CreateObject("wscript.shell")
  
    Do While Len(T) = 0
        'Send keys to Select All / Copy / Kill the application
        wshshell.SendKeys "^a"
        Temporisation 30
        wshshell.SendKeys "^c"
        Temporisation 30
        clip.GetFromClipboard
        T = clip.GetText(1)
        DoEvents
    Loop

    wshshell.SendKeys "%{F4}"
    Temporisation 100
    ThisWorkbook.Activate    ' sait on jamais
    With ThisWorkbook.Worksheets(1)
        .[A1].Select
        .[A1].ClearContents
        'CreateObject("wscript.shell").SendKeys "^v"'ne fonctionne pas chez moi
        .Paste
        Temporisation 50
        'Application.ScreenUpdating = True
        GetPDFTextViaExcel = .[A1].Value
    End With
    Set clip = Nothing
End Function

Sub test2()
    GetPDFTextViaExcel "C:\Users\patricktoulon\Desktop\trier un tableau avec la fonction sort d'excel 2023.pdf"
End Sub

think differently;)
j'ajoute que des object anonyme à répétition c'est pas top
prso j'en crée un et c'est tout


ps :le temporisation 100 et le 50 tu peux les virer carrément
je les avaient perdu de vue ceux là 🤣 🤣 🤣
 
Dernière édition:

Dudu2

XLDnaute Barbatruc
Ton idée est judicieuse. Et peut-être, par sécurité devrais-je l'ajouter à ma solution qui se contente d'un FindWindow à essayer chez toi.

Avant le traitement, j'ai aussi nettoyé d'éventuelle fenêtres Chrome ouvertes sur le fichier PDF au cas où.

Au passage une petite remarque avec Chrome: j'avais remarqué que Ctrl A suivi de Ctrl C ne passait pas et que par hasard, en essayant des touches, j'avais réussi à faire marcher le Ctrl C en envoyant avant une Tabulation. D'où le Sendkeys {TAB} dans le code.

VB:
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassname As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long
'
Private Const WM_CLOSE As Integer = &H10

'-----------------------------------------
'Open a PDF and copy the text in the sheet
'-----------------------------------------
Function GetPDFTextViaExcel(FichierPDF As String) As String
    Dim ChromeExe As String
    Dim NomPDF As String
    Dim hWnd As LongPtr
    '
    Const Chrome64 = "C:\Program Files\Google\Chrome\Application\chrome.exe"
    Const Chrome32 = "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"
  
    If Len(Dir(Chrome64)) > 0 Then
        ChromeExe = Chrome64
    ElseIf Len(Dir(Chrome32)) > 0 Then
        ChromeExe = Chrome32
    Else
        MsgBox "Chrome.exe non trouvé !"
        Exit Function
    End If
  
    'PDF file name
    NomPDF = Mid(FichierPDF, InStrRev(FichierPDF, "\") + 1)
  
    'Kill possible existing window
    Do While 1
        hWnd = FindWindow(vbNullString, NomPDF & " - Google Chrome")
        If Not hWnd = 0 Then
            Call SendMessage(hWnd, WM_CLOSE, 0, 0)
        Else
            Exit Do
        End If
    Loop

    'Run Chrome and wait for the Window to be ready
    Call Shell(ChromeExe & " --new-window -url " & """" & FichierPDF & """", vbNormalFocus)
    Do While FindWindow(vbNullString, NomPDF & " - Google Chrome") = 0
        Temporisation 100
    Loop
  
    'Send keys to Select All / Copy / Kill the application
    CreateObject("wscript.shell").SendKeys "^a"
    Temporisation 100
    CreateObject("wscript.shell").SendKeys "{TAB}"
    Temporisation 100
    CreateObject("wscript.shell").SendKeys "^c"
    Temporisation 100
    CreateObject("wscript.shell").SendKeys "%{F4}"
    Temporisation 10000
  
    With ThisWorkbook.Worksheets(1)
        .[A1].Select
        .[A1].ClearContents
        On Error Resume Next
        .Paste
        On Error GoTo 0
        Temporisation 100
        Application.ScreenUpdating = True
        GetPDFTextViaExcel = .[A1].Value
    End With
End Function

'-------------
'Temporisation
'-------------
Private Sub Temporisation(NbDoEvents As Integer)
    Dim k As Integer
  
    For k = 1 To NbDoEvents
        DoEvents
    Next k
End Sub
 

Discussions similaires

Statistiques des forums

Discussions
315 111
Messages
2 116 340
Membres
112 720
dernier inscrit
henri marc michel