При очистке с помощью htmlunit почему изменение выпадающего значения не обновляет таблицу?

#web-scraping #drop-down-menu #dom-events #htmlunit #yahoo-finance

#веб-очистка #выпадающее меню #dom-события #htmlunit #yahoo-финансы

Вопрос:

Я очищаю (используя htmlunit на Java с использованием Maven в Eclipse IDE) сайт Yahoo Finance, на котором отображаются опционные контракты (например, для акций Apple URL-адрес https://finance .yahoo.com/quote/AAPL/options ?) в таблицах «вызовы» и «puts». Затем я сохраняю интересные параметры «put» в файле Excel. Все это отлично работает для таблицы дат по умолчанию для опционов put. Когда вы вручную меняете раскрывающийся выбор на одну из других доступных дат, таблицы обновляются до контрактов для этих дат. Используя Chrome inspect, вы можете увидеть Javascript, который запускается для выполнения этого обновления. Используя htmlunit, я могу: определить узел домена «выбрать», доступные значения даты выбора, изменить выбранную дату на каждое из доступных значений и доказать, что я фактически обновляю выбранное значение, распечатав его в консоли Eclipse IDE. Я считаю, что при изменении javascript это должно запускаться автоматически. Однако таблица опционных контрактов, которую я извлекаю, всегда (для каждого доступного значения даты опции) является начальной таблицей для даты по умолчанию. Как показано, я также попытался намеренно выполнить Javascript, как показано. Я попытался подождать 5 секунд (также попробовал 20 секунд), как показано, прежде чем обновлять страницу и извлекать таблицу (обновление вручную занимает около 3 секунд). Я также пытался не обновлять страницу.

Примечание: способ получения узлов для значений даты контракта и для выбора кажется уродливым. Если вы используете Chrome inspect, вы увидите, что ни у одного из этих узлов нет идентификатора или имени. У каждого из них есть уникальный класс, но до сих пор я мог использовать класс только для получения самой таблицы. похоже, что в htmlunit нет метода для извлечения выбранного узла по классу, только методы по идентификатору или по имени. Итак, мне пришлось выбрать узел-предок, у которого есть идентификатор, и продвигаться вниз, пока я не нашел список дат, а затем поднялся на один уровень, чтобы найти узел, который можно было бы использовать как htmlselect . Только один узел может быть приведен как таковой, поэтому я уверен, что это узел выбора. Кроме того, я подтвердил, что могу изменить выбранное значение даты, изменив его, а затем напечатав текущее выбранное значение на консоли. Итак, я знаю, что меняю раскрывающееся значение. Я пробовал различные эмуляции браузера, доступные в htmlunit, включая Chrome, Firefox, Internet Explorer и «наиболее поддерживаемые».

После нескольких недель поиска в Google и пробования комбинаций трюков я действительно застрял. Вот мой код:

 WebClient webClient = new WebClient( BrowserVersion.CHROME );
webClient.getOptions().setJavaScriptEnabled(true);
webClient.getOptions().setThrowExceptionOnScriptError(false);
webClient.waitForBackgroundJavaScript(5 * 1000);
String url = "https://finance.yahoo.com/quote/APPL/options?";
HtmlPage page = (HtmlPage) webClient.getPage(url);
Iterable<DomElement> contractDates =  page.getElementById("Col1-1-OptionContracts-Proxy").getFirstChild().getFirstChild().getFirstChild().getFirstChild().getDomElementDescendants(); //this is the list of option dates in the drop down!!
DomNode theSelector = page.getElementById("Col1-1-OptionContracts-Proxy").getFirstChild().getFirstChild().getFirstChild().getFirstChild();//this gets the drop down node
HtmlSelect select = (HtmlSelect) theSelector;// "theSelector" is the only node  can be cast as htmlselect; the parent cannot, the child cannot.
                
if (contractDates == null) { System.out.println("***********  Contract Dates not found"); }else 
{   
for (DomElement aContractDate : contractDates) 
{
HtmlOption option = select.getOptionByText(aContractDate.asText());
select.setSelectedAttribute(option, true);// confirmed that this selects the option 
page.executeJavaScript("https://s.yimg.com/uc/finance/ddsite/js/vendor.fd8794bfdc89142e2d1.modern.js");//this is from chrome inspect of the event listeners
webClient.waitForBackgroundJavaScript(5 * 1000);// manually takes about 3 seconds
page = (HtmlPage) page.getEnclosingWindow().getEnclosedPage();// to refresh the page
List<HtmlTable> listElement = page.getByXPath("//table[@class='puts W(100%) Pos(r) list-options']");//note that the list retrieved has one element
HtmlTable table = listElement.get(0);// this makes the one element retrieved into a table
List<HtmlTableRow> rows = table.getRows();
                            
//the rest of the code is to retain the rows of the table to the spreadsheet ...
 

Комментарии:

1. Я нашел обходной путь, возможно, единственный способ сделать это. Вручную, при изменении даты URL обновляется, чтобы иметь дату в виде минут с 1/1/1970. Открытие нового URL-адреса, построенного с датой в этом формате, работает по желанию.

2. исправление: … дата в виде секунд с 1/1/1970…