由于VBA中的IE自动化,我试图从网站上自动下载PDF(职位发布),由于某种原因,我无法生成单个PDF。
通过在网页上进行手动操作,然后在pdf图标上执行“另存为”操作,效果很好,可以给我有效的PDF,但是自动化失败。
我不明白为什么,希望有人能够给我提示。
谢谢
VeeBee
请在此后找到我到目前为止的代码(URL是公开的,我已经随机选择了报价)
Private Declare Function DownloadFilefromURL Lib "urlmon" _
Alias "URLDownloadToFileA" _
(ByVal pCaller As Long, _
ByVal szURL As String, _
ByVal szFileName As String, _
ByVal dwReserved As Long, _
ByVal lpfnCB As Long) As Long
Private Const ERROR_SUCCESS As Long = 0
Private Const BINDF_GETNEWESTVERSION As Long = &H10
Public Function DownloadFile(SourceUrl As String, LocalFile As String) As Boolean
DownloadFile = DownloadFilefromURL(0&, SourceUrl, LocalFile, BINDF_GETNEWESTVERSION, 0&) = ERROR_SUCCESS
End Function
Sub TestSavePDF()
Dim oNav As SHDocVw.InternetExplorer
Dim oDoc As MSHTML.HTMLDocument
Dim MyURL As String
Set oNav = New SHDocVw.InternetExplorer
oNav.Visible = True
'Test Altays Client A (Banque de France)
MyURL = "https://www.recrutement.banque-france.fr/detail-offre/?NoSource=16001&NoSociete=167&NoOffre=2036788&NoLangue=1"
'Test Altays Client B (Egis)
' MyURL = "https://www.altays-progiciels.com/clicnjob/FicheOffreCand.php?PageCour=1&Liste=Oui&Autonome=0&NoOffre=2037501&RefOffrel=&NoFaml=0&NoParam1l=0&NoParam2l=0&NoParam3l=0&NoParam133l=0&NoParam134l=0&NoParam136l=0&NoEntite1=0&NoEntite=&NoPaysl=0&NoRegionl=0&NoDepartementl=0&NoTableOffreLieePl=0&NoTableOffreLieeFl=0&NoNivEtl=0&NoTableCCl=0&NoTableCC2l=0&NoTableCC3l=0&NoTableOffreUnl=0&NoTypContratl=0&NoTypContratProl=0&NoStatutOffrel=&NoUtilisateurl=&RechPleinTextel=#ancre3"
oNav.navigate MyURL
'link provided to download the job offer in PDF. when clicked the PDF opens in a new tab
MyURL = "https://www.altays-progiciels.com/clicnjob/ExportPDFFront.php"
DownloadFile MyURL, "C:\[...Path...]\test.pdf"
End Sub
答案 0 :(得分:1)
initial job page自动点击目标href不会产生可行的页面链接。大概是因为重要的事情实际上发生在服务器端。
目标href:
您可以单击此页面上的实际下载按钮
下载按钮:
这将打开一个新窗口,这就是Selenium很棒的原因。 Selenium具有切换到此新窗口的方法。否则,您可以使用答案中稍后详细介绍的FindWindow方法来查找Save As
窗口。
在这个新窗口中,由于不能通过DOM获得所需的内容,因此无法像平常一样按常规方式与按钮进行交互。如果仔细检查,您会看到pdf按钮位于shadow-root
中,即您无法访问的位置。这是一种设计选择。我确实需要在某个时候研究this的可能性(使用'/ deep /'组合器通过阴影DOM进行选择),但我认为在VBA中它不成立。
下载按钮:
我正在使用selenium basic VBA包装器和API来模拟屏幕上的操作,并使用Save As
窗口将其另存为pdf(请参见底部的图像)。特别是通过Save
使用SendKeys
键盘快捷键。这可行。
我用Spy++
来检查Window树形结构,并检查Window Class
的名称和Titles
。
我使用SendKeys
自动打开pdf的Save As
对话框。然后,我下降Window树结构以在输入文件名的ComboBox上获取句柄,因此可以向其中发送 message 即文件名,并在Save
按钮上发送,可以单击它。您可能需要更长的等待时间,以确保下载正确进行。我认为这有点不足,我希望有所改进。
通过Spy++
的窗口结构
它相当健壮。我使用Selenium Basic是为了轻松使用iframe并解决same origin policy问题。使用IE,您不能简单地获取iframe的src链接并愉快地导航至原始添加的pdf打印页面。我相信您可以做的是发出一个初始XMLHTTP request并获取src
属性值,即链接。然后将src
链接传递到IE,然后对Windows处理部分进行如下所示的操作。
与更多的时间相比,我可以添加IE版本,并且比使用显式的等待时间来查看更可靠的方法,该方法用于在退出IE实例之前监视文件下载。可能与this相似(如答案之一所述:使用SetWindowsHookEx
设置WH_SHELL
挂钩并查找HSHELL_WINDOWCREATED
事件。)
注释:
PtrSafe
。您可以将LongPtr
切换为Long
,但我认为它仍然兼容。Option Explicit
Declare PtrSafe Function SendMessageW Lib "User32" (ByVal hWnd As LongPtr, ByVal wMsg As LongPtr, ByVal wParam As LongPtr, ByVal lParam As LongPtr) As LongPtr
Declare PtrSafe Function FindWindowExW Lib "User32" (ByVal hWndParent As LongPtr, _
Optional ByVal hwndChildAfter As LongPtr, Optional ByVal lpszClass As LongPtr, _
Optional ByVal lpszWindow As LongPtr) As LongPtr
Public Declare PtrSafe Function FindWindowW Lib "User32" (ByVal lpClassName As LongPtr, Optional ByVal lpWindowName As LongPtr) As LongPtr
Public Const WM_SETTEXT = &HC
Public Const BM_CLICK = &HF5
Public Sub GetInfo()
Dim d As WebDriver, keys As New Selenium.keys
Const MAX_WAIT_SEC As Long = 5
Dim t As Date
Set d = New ChromeDriver
Const URL = "https://www.recrutement.banque-france.fr/detail-offre/charge-de-recrutement-confirme-h-f-2037343/"
With d
.start "Chrome"
.get URL
.SwitchToFrame .FindElementById("altiframe")
.FindElementById("btn-pdf").Click
.SwitchToNextWindow
.SendKeys keys.Control, "s"
Dim str1 As String, cls As String, name As String
Dim ptrSaveWindow As LongPtr
str1 = "#32770" & vbNullChar
t = Timer
Do
DoEvents
ptrSaveWindow = FindWindowW(StrPtr(str1))
If Timer - t > MAX_WAIT_SEC Then Exit Do
Loop While ptrSaveWindow = 0
Dim duiViewWND As LongPtr, directUIHWND As LongPtr
Dim floatNotifySinkHWND As LongPtr, comboBoxHWND As LongPtr, editHWND As LongPtr
If Not ptrSaveWindow > 0 Then Exit Sub
duiViewWND = FindWindowExW(ptrSaveWindow, 0&)
If Not duiViewWND > 0 Then Exit Sub
directUIHWND = FindWindowExW(duiViewWND, 0&)
If Not directUIHWND > 0 Then Exit Sub
floatNotifySinkHWND = FindWindowExW(directUIHWND, 0&)
If Not floatNotifySinkHWND > 0 Then Exit Sub
comboBoxHWND = FindWindowExW(floatNotifySinkHWND, 0&)
If Not comboBoxHWND > 0 Then Exit Sub
editHWND = FindWindowExW(comboBoxHWND, 0&)
If Not editHWND > 0 Then Exit Sub
Dim msg As String
msg = "myTest.pdf" & vbNullChar
SendMessageW editHWND, WM_SETTEXT, 0, StrPtr(msg)
.SendKeys keys.Control, "s"
Dim ptrSaveButton As LongPtr
cls = "Button" & vbNullChar
name = "&Save" & vbNullChar
ptrSaveButton = FindWindowExW(ptrSaveWindow, 0, StrPtr(cls), StrPtr(name))
SendMessageW ptrSaveButton, BM_CLICK, 0, 0
Application.Wait Now + TimeSerial(0, 0, 4)
.Quit
End With
End Sub
另存为对话框窗口:
参考:
项目参考:
硒类型库
`