При парсе с html информацию, появляется ошибка
System.ArgumentOutOfRangeException: "Индекс за пределами диапазона. Индекс должен быть положительным числом, а его размер не должен превышать размер коллекции. Имя параметра: index"
HtmlWeb hw = new HtmlWeb();
HtmlAgilityPack.HtmlDocument doc = hw.Load(textBox1.Text);
var c = doc.DocumentNode.SelectSingleNode(@"/html[1]/body[1]/div[5]/section[1]/div[7]/table[1]/tbody");
var tableElements = new List<ReadOnlyCollection<string>>();
if (c != null)
{
var time = c.SelectNodes("//tr[@id]/td[1]/text()");
var info = c.SelectNodes("//tr[@id]/td[2]/text()");
var cob = c.SelectNodes("//tr[@id]/td[4]/a/text()");
var vact = c.SelectNodes("//tr/td[5]/text()");
var Prog = c.SelectNodes("//tr/td[6]/text()");
var Pred = c.SelectNodes("//tr/td[7]/span/text()");
int m = 0;
do
{
var tableRow = new List<string>();
tableRow.Add(time[m++].InnerText.Trim());
tableRow.Add(info[m++].InnerText.Trim());
tableRow.Add(cob[m++].InnerText.Trim());
tableRow.Add(vact[m++].InnerText.Trim());
tableElements.Add(tableRow.AsReadOnly());
} while (m < info.Count);
foreach (var row in tableElements)
{
var FACT = "";
if (row[3] == " ")
FACT = "НЕТУ";
else FACT = row[3];
if (row[0] != "Экономический календарь")
textBox1.Text += "Text" + row[0] + " Страна " + row[1] + "Text" + row[2] + " Факт " + FACT + Environment.NewLine;
else
textBox1.Text += "Нуль";
}
}
Собственно ссылка на сайт https://ru.investing.com/economic-calendar/
По моим наблюдения, думаю, что это из за первого
[tr][/tr]
Потому, что в нем содержится информация только о дате, а вот следующий
[tr][/tr]
Уже имеет нужную инфу Скриншот Вопрос, как исправить ситуацию ?
Я уже пытался удалить, первый [tr], но по методам Remove(); но не получилось (
Честно говоря, не совсем вник в код, но все же сделаю предположение: Нет ли тут ошибки?
do
{
var tableRow = new List<string>();
tableRow.Add(time[m++].InnerText.Trim());
tableRow.Add(info[m++].InnerText.Trim());
tableRow.Add(cob[m++].InnerText.Trim());
tableRow.Add(vact[m++].InnerText.Trim());
tableElements.Add(tableRow.AsReadOnly());
} while (m < info.Count);
Может быть m нужно увеличивать один раз в итерацию цикла? Иначе вы бежите по коллекциям "по диагонали"
do
{
var tableRow = new List<string>();
tableRow.Add(time[m].InnerText.Trim());
tableRow.Add(info[m].InnerText.Trim());
tableRow.Add(cob[m].InnerText.Trim());
tableRow.Add(vact[m].InnerText.Trim());
tableElements.Add(tableRow.AsReadOnly());
m++;
} while (m < info.Count);
Извините за тривиальный ответ, возможно я не разобрался в контексте.
Как по мне вы используете совершенно не правильный подход. Вы все прибиваете гвоздями, делаете статичное. То есть вы говорите "Я хочу 5-ый объект, который находится в первом body", а если объект будет не 5-ый, а скажем 10, или он переместится вовсе в какой нибудь div? Тогда все, вам придется очень многое переделывать и заново искать эти объекты, это не эффективно!
Я вот сделал небольшую "вырезку" с того сайта, давайте по ней попробуем что то получить...
<html>
<body>
<div class="eCalNew eCalMainNew ecoCalCont">
<div id="div-gpt-ad-1370187203350-ec1" style="text-align:center;margin-bottom:20px;"></div>
<div id="ecoCalTabsMenu" class="ecoCalTabs dirLtr">
<ul class="float_lang_base_1 tabsForBox" id="ecoCalTabsTop">
<li class="first selected"><a href="javascript:void(0);">Экономический календарь</a></li>
<li><a href="/holiday-calendar/">Праздники</a></li>
<li><a href="/earnings-calendar/">Отчёты</a></li>
<li><a href="/dividends-calendar/">Дивиденды</a></li>
<li><a href="/stock-split-calendar/">Сплиты</a></li>
<li><a href="/ipo-calendar/">IPO</a></li>
<li class="last"><a href="/futures-expiration-calendar/">Фьючерсы</a></li>
</ul>
<div class="clear"></div>
</div>
<div class="js-notification-bar notification notificationImportant ">
<span class="iconHolder"><i class="importantIcon"></i></span>
<span class="alertText js-open-auth-trigger-inside" data-page-type="sml" data-ga-event-label="Calendars"><a onclick="overlay.overlayLogin();" href="javascript:void(0);" class="bold">Войдите</a> / <a onclick="overlay.overlayRegister();" href="javascript:void(0);" class="bold">зарегистрируйтесь бесплатно</a> для сохранения выбранных фильтров.</span>
<i class="bugCloseIcon js-notification-bar-close"></i>
</div>
<div class="clear"></div>
<table id="economicCalendarData" class="genTbl closedTbl ecoCalTbl persistArea">
<thead>
<tr>
<th class="first time left">Время </th>
<th class="flagCur left">Валюта</th>
<th class="textNum imp left">Важн.</th>
<th class="event left">Событие</th>
<th class="act">Факт.</th>
<th class="time">Прогноз</th>
<th class="prev">Пред.</th>
<th class="last"></th>
</tr>
</thead>
<tbody pagestartat="">
<tr>
<td colspan="9" class="theDay" id="theDay1528329600">Четверг, 7 июня 2018 г.</td>
</tr>
<tr id="eventRowId_367319" class="js-event-item" event_attr_id="349" data-event-datetime="2018/06/07 01:30:00">
<td class="first left time js-time" title="Данные вышли 15ч 49м назад">01:30</td>
<td class="left flagCur noWrap"><span title="Австралия" class="ceFlags Australia" data-img_key="Australia"> </span> AUD</td>
<td class="left textNum sentiment noWrap" title="Низкая волатильность" data-img_key="bull1"><i class="grayFullBullishIcon"></i><i class="grayEmptyBullishIcon"></i><i class="grayEmptyBullishIcon"></i></td>
<td class="left event" title="Для получения дополнительной информации нажмите здесь"><a href="/economic-calendar/aig-construction-index-349" target="_blank">
Индекс активности в сфере строительства от AIG (май)</a>
</td>
<td class="bold act blackFont event-367319-actual" title="" id="eventActual_367319">54,0</td>
<td class="fore event-367319-forecast " id="eventForecast_367319"> </td>
<td class="prev blackFont event-367319-previous" id="eventPrevious_367319"><span title="">55,4</span></td>
<td class="alert js-injected-user-alert-container " data-name="Индекс активности в сфере строительства от AIG" data-event-id="349" data-status-enabled="0">
<span class="alertBellGrayPlus genToolTip oneliner" data-tooltip="Создать уведомление" data-tooltip-alt="Уведомление активно"></span>
</td>
</tr>
<tr id="eventRowId_368093" class="js-event-item revised" event_attr_id="987" data-event-datetime="2018/06/07 02:50:00">
<td class="first left time js-time" title="Данные вышли 14ч 29м назад">02:50</td>
<td class="left flagCur noWrap"><span title="Япония" class="ceFlags Japan" data-img_key="Japan"> </span> JPY</td>
<td class="left textNum sentiment noWrap" title="Низкая волатильность" data-img_key="bull1"><i class="grayFullBullishIcon"></i><i class="grayEmptyBullishIcon"></i><i class="grayEmptyBullishIcon"></i></td>
<td class="left event" title="Для получения дополнительной информации нажмите здесь"><a href="/economic-calendar/foreign-bonds-buying-987" target="_blank">
Объём покупок иностранных облигаций </a>
</td>
<td class="bold act blackFont event-368093-actual" title="" id="eventActual_368093">-1.665,8B</td>
<td class="fore event-368093-forecast " id="eventForecast_368093"> </td>
<td class="prev greenFont event-368093-previous" id="eventPrevious_368093"><span title="Пересмотрено с -717,0B">-700,2B</span></td>
<td class="alert js-injected-user-alert-container " data-name="Объём покупок иностранных облигаций" data-event-id="987" data-status-enabled="0">
<span class="alertBellGrayPlus genToolTip oneliner" data-tooltip="Создать уведомление" data-tooltip-alt="Уведомление активно"></span>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Что мы здесь видим? Хм, ну у нас есть объект table с уникальным ID economicCalendarData, по сути нам этого достаточно для того, что бы вытянуть уже этот объект, попробуем?
var calendarData = htmlDocument.DocumentNode.SelectSingleNode("//table[@id='economicCalendarData']");
Заметьте, я здесь просто указал, что хочу один объект table, id которого = economicCalendarData. Результатом мне выдаст нужный объект для дальнейшей работы.
Отлично, идем дальше! Наша таблица содержит в себе tbody, внутри которого находится куча полезных для нас tr. Что есть примечательного в tr? Правильно, класс, все нужные нам данные помечены классом js-event-item, некоторые содержать дополнительно и другие классы (например revised), по этому нам надо использовать в xpath условие "содержит". Давайте попробуем:
var tableRow = calendarData.SelectNodes(".//tbody//tr[contains(@class,'js-event-item')]");
И тут все довольно просто, я вызываю метод SelectNodes для получения множества результатов. В Xpath задаю, что хочу в указанном объекте (точка в начале) получить tbody, а в нем получить все tr, класс которых содержит js-event-item. Все, результатом в моем примере будет 2 объекта tr.
! Тут хочу сделать предупреждение! Не забывайте делать проверку на NULL, ибо мы можем к примеру не получить table в первом запросе, что выдаст нам NULL, без проверок все упадет!
Ну все, что нам осталось? Получить данные? Ну, а это пусть будет вашим домашним заданием, там все точно также, получаем нужные td, ну и работаем с ними..
В общем вот вам простейший подход к поставленной задаче. Удачи в программирование!
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости