Я немного изучил ваш веб-сайт, и, поскольку я не мог сказать все это в одном комментарии, я решил опубликовать ответ (хотя он и не дает конкретного решения, а просто "ответ" "и, возможно, несколько советов).
Ответ на ваш вопрос
Как я могу исправить свой скрипт, чтобы он продолжал нажимать на кнопку «Загрузить больше хитов», пока такой кнопки не осталось?
К сожалению, это не твоя вина. Веб-сайт, на который вы ориентируетесь, работает через WebSocket-связь между веб-клиентом (вашим браузером) и веб-сервером, предоставляя цены, которые вы пытаетесь очистить. Вы можете увидеть это следующим образом:
Вообразите это так:
- Когда вы впервые загружаете свою веб-страницу, веб-сокет инициализируется и отправляется первый запрос (веб-клиент: "Эй, сервер, дай мне первые X результатов" , веб-сервер: " Конечно, вы идете ").
- Каждый раз, когда вы нажимаете кнопку «Загрузить дополнительные результаты», веб-клиент ( важно: повторное использование того же WS-соединения ) продолжает запрашивать X новых результатов для веб-сервера.
Итак, связь продолжается некоторое время. В какой-то момент, вне вашего контроля , случается, что веб-сокет просто умирает. Достаточно взглянуть на консоль JavaScript, нажимая кнопку «Загрузить дополнительные результаты»: вы увидите, что запрос выполняется до тех пор, пока в какой-то момент вы не увидите просто поднятый NullPointerException
:
Если вы нажмете на последнюю строку стека перед исключением, вы увидите, что это из-за веб-сокета:
Ошибка ясно говорит: cannot read .send() on null
, что означает, что _ws
(веб-сокет) пропал.
С этого момента вы можете забыть о своем сайте. Когда вы нажимаете кнопку «Загрузить дополнительные результаты», веб-клиент попросит веб-сокет доставить новый запрос на веб-сервер, но веб-сокет пропал, так что прощайте связь между ними, и, к сожалению, до свидания остальные ваши данные.
Вы можете проверить это, просто поднявшись немного выше в стеке:
Как вы можете видеть выше, у нас есть:
- Сообщение, зарегистрированное в консоли с надписью "executeSearch params ...") непосредственно перед отправкой нового запроса данных
-
post
нового запроса данных
- Сообщение, зарегистрированное в консоли с надписью "выполнил поиск с результатом ...") сразу после публикации нового запроса данных
Пока веб-сокет еще активен, каждый раз, когда вы нажимаете «Загрузить больше результатов», вы видите эти два сообщения в консоли (с другими сообщениями между ними, напечатанными поверх остальной части их кода):
Однако после первого сбоя веб-сокета, независимо от того, сколько раз вы пытаетесь нажать на кнопку, вы получите только первое сообщение (веб-клиент отправляет запрос), но никогда не получит второе сообщение (запрос получает потерял в пустоте):
Обратите внимание, это соответствует вашему поведению, наблюдаемому в VBA:
скрипт застревает после нажатия на эту кнопку 3/4 раза.
Он не застревает, на самом деле ваш скрипт продолжает работать правильно. Время ожидания истекло.
Я пытался выяснить, почему веб-сокет падает, но безуспешно. Это просто кажется тайм-аутом (у меня было намного больше при отладке их JavaScript, поэтому мои точки останова вызывали тайм-аут), но я не могу убедиться, что это единственная причина. Поскольку вы не контролируете процесс между веб-клиентом и веб-сервером, все, что вы можете сделать, - это надеяться, что он не истечет.
Кроме того, я считаю, что использование Selenium автоматически устанавливает несколько более длительных тайм-аутов (из-за длительного времени выполнения), и это как-то позволяет сохранять веб-сокет более терпимым по отношению к тайм-аутам.
Единственный способ восстановить соединение после сбоя веб-сокета - это полная перезагрузка веб-страницы и перезапуск процесса с нуля .
Мои предложения
Я думаю, что вы могли бы пойти с созданием XHR-запроса и отправкой через JavaScript, потому что их API (через который веб-клиент / веб-сокет доставляет запрос на веб-сервер) довольно сильно представлены в их коде переднего плана.
Если вы откроете их файл FinderAPI.js
, вы увидите, что они оставили конечные точки и конфигурации API зашифрованными:
var FinderAPI = {
store: null,
state: null,
finderEndpoint: '/api/v1/bsg/etp/finder/list',
bidAskEndpoint: '/api/v1/prices/bidAsk/get',
instrumentNameEndpoint: '/api/products/ProductTypeMapping/InstrumentNames',
nameMappingEndpoint: '/api/v1/bsg/general/namemapping/list',
apiConfig: false,
initialize: function initialize(store, finderEndpoint) {
var apiConfig = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
this.store = store;
this.state = store.getState();
this.apiConfig = apiConfig;
this.finderEndpoint = finderEndpoint;
},
Это означает, что вы знаете URL-адрес, на который следует отправить запрос POST
.
Для запроса также требуется, чтобы токен на предъявителя был проверен сервером. К счастью, они также забыли защитить свои токены, предоставив (GORSH) конечную точку GET
для получения токена:
Конечная точка: https://www.boerse -stuttgart.de / api / products
Ответ:
{"AuthenticationToken": "JgACxn2DfHceHL33uJhNj34qSnlTZu4 + hAUACGc49UcjUhmLutN6sqcktr / T634vaPVcNzJ8sHBvKvWz", "Хост": "frontgate.m} 11" "
Вам просто нужно немного поиграть с веб-сайтом, чтобы выяснить, каково тело вашего POST-запроса, затем создать новый XmlHttpRequest
и отправить эти значения внутри него, чтобы получить цены непосредственно в вашем VBA. без открытия веб-страницы и роботизированной очистки.
Я предлагаю вам начать с точки останова в файле FinderAPI.js
, строка 66 (строка кода this.post(this.finderEndpoint, params)
, params
должна привести вас к телу запроса - я помню, вы можете напечатать объект как строка с JSON.stringify(params)
).
Также обратите внимание, что они используют нумерацию результатов 50
каждый раз, хотя их API поддерживает до 500
из них. Другими словами, если вам нужно ввести значение 500 (вместо 50) в их свойство разбиения на страницы, отправленное в API для запроса:
... тогда вы получите 500 результатов за раз вместо 50, поэтому на 10 раз сократится время, которое ваш код потратит на очистку веб-страницы, если вы решите не углубляться в решение XHR.