使用vba

时间:2015-10-13 15:52:12

标签: python html vba excel-vba screenshot

我正在处理一组html文件(使用一些python代码保存在Web上的本地驱动器上),我正在查找这些文件中的关键字。然而,它们只有几页,我很难找到一种方法来使用vba自动执行以下序列:打开文件>查找关键字1>截取以keyword1为中心的屏幕截图,x宽度和y高度>在本地驱动器上以最佳格式(jpeg?)保存>转到下一个关键字>转到下一个文件。

最终目标是能够快速浏览上下文中的这些关键字。如果我设法获取这些文件,我将在Excel电子表格中使用超链接链接到这些文件。

这是我现在的代码 - 显然它不起作用:

'Get list of files in folder
Dim xRow As Long
Dim xDirect$, xFname$, InitialFoldr$

InitialFoldr$ = "blablabla"
With Application.FileDialog(msoFileDialogFolderPicker)
    .InitialFileName = Application.DefaultFilePath & "\"
    .Title = "Please select a folder to list Files from"
    .InitialFileName = InitialFoldr$

    If .SelectedItems.Count <> 0 Then
    xDirect$ = .SelectedItems(1) & "\"
    xFname$ = Dir(xDirect$, 7)

    Do While xFname$ <> ""
    Sheets("List of files folder").Cells(3, 2).Offset(xRow) = xFname$
    xRow = xRow + 1
    xFname$ = Dir

    Loop
    End If
End With

'Get # rows in list of files in folder
Dim myrng4 As Range
Dim lastlinelist As Integer
Dim htmlpath As String
Dim objWord
Dim objDoc

Set objWord = CreateObject("Word.Application")

Set myrng4 = Sheets("List of files folder").Range("B3:B50000")
lastlinelist = myrng4.Find(What:="*", LookIn:=xlValues, Lookat:=xlWhole, SearchOrder:=xlRows, _
SearchDirection:=xlPrevious).Row

For Each cn In Range(wb.Sheets("Results conso").Cells(3, 11), wb.Sheets("Results conso").Cells(3, Lastcolumn))
For Each fileref In Range(Sheets("List of files folder").Cells(2, 3), Sheets("List of files folder").Cells(2, lastlinelist))
    With Sheets("results conso")
        htmlpath = InitialFoldr$ & fileref
        If Dir(htmlpath) = "" Then
        Else
            If LCase(Right(pdfpath, 4)) <> "html" Then
            Else
                Set objDoc = objWord.Documents.Open(htmlpath)
                objWord.Visible = True
                objDoc.BringToFront
                If objDoc.findText(cn.Value, True, True, False) = False Then
                    objDoc.Close True
                    Set objDoc = Nothing
                Else
                    Call keybd_event(VK_SNAPSHOT, 0, 0, 0)
                    Set objDoc = wordobj.Documents.Add
                    wordobj.Visible = True
                    Set objselection = wordobj.Selection
                    objselection.Paste
                End If
            End If
        End If
    End With
Next fileref
Next cn

另外,我想知道用Python而不是VBA来做这个是不是更好的主意。

非常感谢, Hadrien

1 个答案:

答案 0 :(得分:1)

找到这个词应该很容易。我写了一个捕获屏幕截图的函数。它可能比您需要的代码更多。它正在寻找程序和窗口等。

Option Explicit
Private mblnFormActivated As Boolean
Private fsFolder        As New FileSystemObject
Private fsFile          As New FileSystemObject
Private bIsRealClick    As Boolean

Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" _
(ByVal hwnd As Long, ByVal lpOperation As String, ByVal lpFile As String, _
ByVal lpParameters As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long

Private Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" (ByVal wCode As Long, ByVal wMapType As Long) As Long
Private Declare Sub keybd_event Lib "user32" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Long, ByVal dwExtraInfo As Long)
Private Const VK_MENU = &H12
Private Const VK_SNAPSHOT = &H2C
Private Const KEYEVENTF_KEYUP = &H2
Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vkey As Long) As Integer

Private Sub cmdScreenshot_Click()
Dim ewohwnd As Long
Dim ewohwnd2 As Long
    'This will capture a screenshot of the EWO window and save it to the job folder.
    ewohwnd = GetHwndFromProcessName("EWO.EXE", "Byers View Station")
    ewohwnd2 = GetHwndFromProcessName("EWO.EXE", "#32770")
    If (ewohwnd2 = 0) Then
        ewohwnd2 = GetHwndFromProcessName("EWO.EXE", "ICL Frame")
    End If

    If ewohwnd = 0 Then
        MsgBox "EWO is not currently running."
        Exit Sub
    End If
    If ewohwnd2 = 0 Then
        MsgBox "validation has not been run"
        Exit Sub
    End If

    DoEvents
    If szJobFolderAlt = "" Then
        Call GetWindowScreenshot(ewohwnd, ewohwnd2, szJobFolder & szJobStatus & " VALIDATION SCREENCOPY.JPG", 1)

        Call ShellExecute(1, "Open", szJobFolder & szJobStatus & " VALIDATION SCREENCOPY.JPG", 0&, 0&, 10)
    Else
        Call GetWindowScreenshot(ewohwnd, ewohwnd2, szJobFolderAlt & szJobStatus & " VALIDATION SCREENCOPY.JPG", 1)

        Call ShellExecute(1, "Open", szJobFolderAlt & szJobStatus & " VALIDATION SCREENCOPY.JPG", 0&, 0&, 10)
    End If
End Sub

这是我模块中名为modWindowScreenshot

的代码
Option Explicit

Private Const PIC_QUALITY_JPG = 75

Private Type GUID
   data1 As Long
   data2 As Integer
   data3 As Integer
   data4(7) As Byte
End Type

Private Type PicBmp
   Size As Long
   Type As Long
   hBmp As Long
   hPal As Long
   Reserved As Long
End Type

Private Type RECT
    Left As Long
    Top As Long
    Right As Long
    Bottom As Long
End Type

Private Declare Function Sleep Lib "Kernel32" (ByVal dwMilliseconds As Long) As Long
Private Declare Function GetWindowRect Lib "user32" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function GetWindowDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hObject As Long) As Long
Private Declare Function BitBlt Lib "gdi32" (ByVal hDCDest As Long, ByVal XDest As Long, ByVal YDest As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hDCSrc As Long, ByVal XSrc As Long, ByVal YSrc As Long, ByVal dwRop As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Declare Function OleCreatePictureIndirect Lib "olepro32" (PicDesc As PicBmp, RefIID As GUID, ByVal fPictureOwnsHandle As Long, IPic As IPicture) As Long
Private Declare Function BringWindowToTop Lib "user32" (ByVal hwnd As Long) As Long


Private Const GW_CHILD = 5
Private Const GW_HWNDNEXT = 2
Private Declare Function GetDesktopWindow Lib "user32" () As Long
Private Declare Function GetWindow Lib "user32" (ByVal hwnd As Long, ByVal wCmd As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function IsWindowVisible Lib "user32" (ByVal hwnd As Long) As Long

Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As Long) As Long

Private Declare Function GetParent Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

'----------------------------------------------------------------------------------------------------------------------
'Section for using gdi to convert to jpeg

Private Declare Function GdiplusStartup Lib "GdiPlus.dll" (ByRef mtoken As Long, ByRef mInput As GdiplusStartupInput, ByRef mOutput As Any) As GpStatus
Private Declare Sub GdiplusShutdown Lib "GdiPlus.dll" (ByVal mtoken As Long)
Private Declare Function GdipSaveImageToFile Lib "GdiPlus.dll" (ByVal mImage As Long, ByVal mFilename As String, ByRef mClsidEncoder As gGUID, ByRef mEncoderParams As EncoderParameters) As GpStatus
Private Declare Function GdipGetEncoderParameterList Lib "GdiPlus.dll" (ByVal mImage As Long, ByRef mClsidEncoder As gGUID, ByVal msize As Long, ByRef mBuffer As EncoderParameters) As GpStatus
Private Declare Function GdipGetEncoderParameterListSize Lib "GdiPlus.dll" (ByVal mImage As Long, ByRef mClsidEncoder As gGUID, ByRef msize As Long) As GpStatus
Private Declare Function GdipCreateBitmapFromHBITMAP Lib "GdiPlus.dll" (ByVal mHbm As Long, ByVal mhPal As Long, ByRef mBitmap As Long) As GpStatus
Private Declare Function GdipDisposeImage Lib "GdiPlus.dll" (ByVal mImage As Long) As GpStatus


Private Enum GpStatus
    Ok = &H0
End Enum

Private Type gGUID
    Data(0 To 3) As Long
End Type

Private Type GdiplusStartupInput
    GdiplusVersion As Long
    DebugEventCallback As Long
    SuppressBackgroundThread As Long
    SuppressExternalCodecs As Long
End Type

Private Type EncoderParameter
    GUID As gGUID
    lNumberOfValues As Long
    lType As Long
    lValue As Long
End Type

Private Type EncoderParameters
    Count As Long
    Parameter(4) As EncoderParameter
End Type

Private Const EncoderParameterValueTypeLong As Long = &H4

Public Function GetWindowScreenshot(WndHandle As Long, WndHandle2 As Long, SavePath As String, Optional BringFront As Integer = 1) As Long
'
' Function to create screeenshot of specified window and store at specified path
'
    On Error GoTo ErrorHandler

    Dim hDCSrc As Long
    Dim hDCSrc2 As Long
    Dim hDCMemory As Long
    Dim hDCMemory2 As Long
    Dim hBmp As Long
    Dim hBmp2 As Long
    Dim hBmpPrev As Long
    Dim hBmpPrev2 As Long
    Dim WidthSrc As Long
    Dim WidthSrc2 As Long
    Dim HeightSrc As Long
    Dim HeightSrc2 As Long
    Dim Pic As PicBmp
    Dim IPic As IPicture
    Dim IID_IDispatch As GUID
    Dim rc As RECT
    Dim rc2 As RECT
    'Dim pictr As PictureBox
    Dim stdPic As StdPicture

    'Bring window on top of all windows if specified
    If BringFront = 1 Then BringWindowToTop WndHandle
    BringWindowToTop WndHandle2
    Sleep 50
    DoEvents

    'Get Window Size
    GetWindowRect WndHandle, rc
    WidthSrc = rc.Right - rc.Left
    HeightSrc = rc.Bottom - rc.Top

    'Get Window  device context
    hDCSrc = GetWindowDC(WndHandle)

    'create a memory device context
    hDCMemory = CreateCompatibleDC(hDCSrc)

    'create a bitmap compatible with window hdc
    hBmp = CreateCompatibleBitmap(hDCSrc, WidthSrc, HeightSrc)

    'copy newly created bitmap into memory device context
    hBmpPrev = SelectObject(hDCMemory, hBmp)


    'GET VALIDATION OVERLAY IN MEMORY
    GetWindowRect WndHandle2, rc2
    WidthSrc2 = rc2.Right - rc2.Left
    HeightSrc2 = rc2.Bottom - rc2.Top

    hDCSrc2 = GetWindowDC(WndHandle2)
    hDCMemory2 = CreateCompatibleDC(hDCSrc2)
    hBmp2 = CreateCompatibleBitmap(hDCSrc2, WidthSrc2, HeightSrc2)
    hBmpPrev2 = SelectObject(hDCMemory2, hBmp2)

    'copy window window hdc to memory hdc
    Call BitBlt(hDCMemory, 0, 0, WidthSrc, HeightSrc, _
                hDCSrc, 0, 0, vbSrcCopy)
    'merg EWO and Validation messagebox

    Call BitBlt(hDCMemory, (rc2.Left - rc.Left), (rc2.Top - rc.Top), WidthSrc2, HeightSrc2, _
                hDCSrc2, 0, 0, vbMergeCopy)

    'Get Bmp from memory Dc
    hBmp = SelectObject(hDCMemory, hBmpPrev)

    'release the created objects and free memory
    Call DeleteDC(hDCMemory)
    Call DeleteDC(hDCMemory2)
    Call ReleaseDC(WndHandle, hDCSrc)
    Call ReleaseDC(WndHandle2, hDCSrc2)

    'fill in OLE IDispatch Interface ID
    With IID_IDispatch
       .data1 = &H20400
       .data4(0) = &HC0
       .data4(7) = &H46
     End With

    'fill Pic with necessary parts
    With Pic
       .Size = Len(Pic)         'Length of structure
       .Type = vbPicTypeBitmap  'Type of Picture (bitmap)
       .hBmp = hBmp             'Handle to bitmap
       .hPal = 0&               'Handle to palette (may be null)
     End With

    'create OLE Picture object
    Call OleCreatePictureIndirect(Pic, IID_IDispatch, 1, IPic)



    'return the new Picture object
    'saves as bmp
    'SavePicture IPic, SavePath
    Set stdPic = IPic
    Call saveBitmapToFileAsJPEG(stdPic, SavePath)

    GetWindowScreenshot = 1
    Exit Function

ErrorHandler:
    GetWindowScreenshot = 0
End Function

Public Function GetHwndFromProcessName(ByVal processName As String, Optional className As String = "") As Long
On Error GoTo ErrHandler

    Dim oWMI
    Dim ret
    Dim oServices
    Dim oService
    Dim servicename

    Set oWMI = GetObject("winmgmts:")
    Set oServices = oWMI.InstancesOf("win32_process")

    'loop through all running processes for exe name
    For Each oService In oServices
        servicename = LCase(Trim(CStr(oService.Name) & ""))
         If InStr(1, servicename, LCase(processName), vbTextCompare) > 0 Then
           GetHwndFromProcessName = GetHwnd(oService.ProcessID, className)
           Exit For
        End If
    Next

    Set oServices = Nothing
    Set oWMI = Nothing

ErrHandler:
    Err.Clear
End Function


Private Function GetHwnd(ByVal ProcessID As Long, Optional className As String = "") As Long

    Dim lHwnd As Long, RetHwnd As Long, RetPID As Long
    Dim sClassName As String
    Dim lMaxCount As Long
    Dim lResult As Long

    lMaxCount = 256
    sClassName = Space(lMaxCount)

    lHwnd = GetDesktopWindow()
    RetHwnd = GetWindow(lHwnd, GW_CHILD)

    'loop through all windows
    Do While RetHwnd
        If IsWindowVisible(RetHwnd) Then
            If GetParent(RetHwnd) = 0 Then
                'Check process id and window class name to get top window handle
                'Using class name as well as process id filters out dialog windows that are not children
                Call GetWindowThreadProcessId(RetHwnd, RetPID)
                lResult = GetClassName(RetHwnd, sClassName, lMaxCount)
                If RetPID = ProcessID Then
                    If className <> "" Then
                        If Left(sClassName, lResult) = className Then
                            Exit Do
                        End If
                        If Left(sClassName, 9) = className Then
                            Exit Do
                        End If
                    Else
                        Exit Do
                    End If
                End If
            End If
        End If
        RetHwnd = GetWindow(RetHwnd, GW_HWNDNEXT)
    Loop
    GetHwnd = RetHwnd

End Function

Private Function saveBitmapToFileAsJPEG(ByRef oPic As StdPicture, szImgPath As String) As Boolean

    Dim hGDIPToken As Long, udtGDIPStartup As GdiplusStartupInput, udtJPEGEnc As gGUID, _
    udtEncParams As EncoderParameters, hImageScrShot As Long, bRet As Boolean


    ' init ret value and GDI+ startup UDT
    bRet = False
    udtGDIPStartup.GdiplusVersion = 1

    If (GdiplusStartup(hGDIPToken, udtGDIPStartup, ByVal 0) = Ok) Then

    With udtJPEGEnc
    ' JPEG Encoder GUID: {557CF401-11D3-1A04-739A-00002EF31EF8}
    .Data(0) = &H557CF401
    .Data(1) = &H11D31A04
    .Data(2) = &H739A
    .Data(3) = &H2EF31EF8
    End With

    With udtEncParams
    .Count = 1
    With .Parameter(0)
    ' EncoderQuality GUID: {1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}
    .GUID.Data(0) = &H1D5BE4B5
    .GUID.Data(1) = &HFA4A452D
    .GUID.Data(2) = &H9CDD5DB3
    .GUID.Data(3) = &H5105E7EB

    ' The Quality Enc Param is a Long from 1(LQ) - 100(HQ)
    .lType = EncoderParameterValueTypeLong
    ' Just this 1 "Quality" Value
    .lNumberOfValues = 1
    ' Set Quality
    '.lValue = CLng(100)
    .lValue = PIC_QUALITY_JPG
    End With
    End With

    ' Create a GDIPlus Bitmap image based off the screen shot Picture
    If (GdipCreateBitmapFromHBITMAP(oPic.Handle, 0, hImageScrShot) = Ok) Then
    ' Save it to a file and dispose of the Picture
    If (GdipSaveImageToFile(hImageScrShot, StrConv(szImgPath, vbUnicode), udtJPEGEnc, udtEncParams) = Ok) Then
    ' File was saved to HDD
    bRet = True
    Set oPic = Nothing
    End If
    ' Cleanup bitmap
    Call GdipDisposeImage(hImageScrShot)
    End If
    ' Shutdown GDI+
    Call GdiplusShutdown(hGDIPToken)
    End If

    saveBitmapToFileAsJPEG = bRet
End Function