Теневой DOM и создание недействительной ссылки:
Автоматическая ссылка на целевую страницу начальная работа не генерирует жизнеспособную ссылку на страницу.Вероятно, это потому, что важные вещи на самом деле происходят на стороне сервера.
Целевая ссылка:

Вы можетенажмите кнопку загрузки на этой странице
Кнопка загрузки:

Откроется новое окно, котороеВот почему Selenium великолепен.У Selenium есть способы переключиться на это новое окно.В противном случае вы можете использовать методы FindWindow, которые я подробно опишу позже в ответе для поиска окна Save As
.
В этом новом окне вы не можете взаимодействовать с кнопками так, как вы это обычно делаете при извлечении в качестве необходимого содержимого.недоступно через DOM.Если вы внимательно посмотрите, то увидите, что кнопка pdf находится в shadow-root
, то есть там, где вы не можете получить к ней доступ.Это выбор дизайна.Мне нужно исследовать эту возможность (выбор с помощью теневого DOM с помощью '/ deep /' комбинатора) в какой-то момент, но я не думаю, что это верно в VBA.
Кнопка загрузки в Shadow root:

Имитация действий клавиатуры:
Я использую оболочку selenium basic VBA и API для имитации действий на экране, чтобы сохранить их в формате PDF с помощью окна Save As
(см. Изображение в самом низу).Особенно используется комбинация клавиш Save
через SendKeys
.Это работает.Я использовал Spy++
, чтобы проверить древовидную структуру окна и проверить имена окон Class
и Titles
.
. Я использую SendKeys
, чтобы автоматизировать открытие диалогового окна Save As
для PDF.Затем я опускаю древовидную структуру Окна, чтобы получить указатели на ComboBox, где вводится имя файла, чтобы я мог отправить ему сообщение , то есть имя файла, и кнопку Save
, чтобы я мог щелкнуть по ней,Возможно, вам потребуется больше времени, чтобы убедиться, что загрузка прошла правильно.На мой взгляд, это немного глючит, и я надеюсь улучшить.
Структура окна через Spy ++

Это довольно надежно.Я использовал Selenium Basic для простоты работы с фреймами и решения проблем с той же политикой происхождения .С IE вы не можете просто взять ссылку src в iframe и с удовольствием перейти на страницу для печати в формате PDF из оригинального дополнения.Я думаю, что вы можете сделать начальный запрос XMLHTTP и получить значение атрибута src
, то есть ссылку.Затем передайте эту ссылку src
на IE, а затем продолжайте, как показано ниже для частей обработки Windows.
Со временем я мог бы добавить версию IE и взглянуть на более надежный метод, чем явное ожидание.добавление времени для мониторинга загрузки файла перед выходом из экземпляра IE.Вероятно, в соответствии с this (Как указано в одном из ответов: используйте SetWindowsHookEx
, чтобы установить WH_SHELL
hook и найдите событие HSHELL_WINDOWCREATED
.)
Примечания:
- Это написано для 64 бит.32 бит удалить
PtrSafe
.Вы могли бы переключить LongPtr
на Long
, но я думаю, что он остается совместимым. - Огромное спасибо @ErikvonAsmuth за его огромное терпение в прохождении API со мной.Посмотрите на его превосходный ответ здесь для работы с Windows .
VBA:
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
Диалоговое окно "Сохранить как":

Ссылки:
- Shadow DOM
- Использование shadow DOM - страницы разработчика Mozilla.
Ссылки на проекты:
Библиотека типов селена
`