Не могу решить одну задачу
Есть текст: ...
Время 01:45 Страна JPY Факт.Базовые заказы в машиностроении (г/г) (апр) Прогноз 9,6% Пред. 3,9% Факт -2,4% Время 02:50 Страна JPY Факт.Базовые заказы в машиностроении (м/м) (апр) Прогноз 10,1% Пред. 2,8% Факт -3,9% Время 02:50 Страна JPY Факт.Денежный агрегат М2 (г/г) Прогноз 3,2% Пред. 3,3% Факт 3,2% Время 02:50 Страна GBP Факт.Индекс GBP/USD Прогноз 57,3% Пред. Факт 57,1% Время 08:30 Страна USD Факт.Индекс золота Прогноз 64,2% Пред. Факт 68,5% Время 08:30 Страна USD Факт.Индекс S&P 500 Прогноз 68,1% Пред. Факт 55,5%
...
Перебираю текст построчно:
String[] s = textBox1.Text.Split(new String[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
int w = Convert.ToInt32(col_vo);
for (int i = 0; i < w; i++)
{
label3.Text += s[i] + "\r\n";
}
И вот в чем я не могу разобраться. Как в цикле выбирать например: В строчке Время 01:45 Страна JPY Факт.Базовые заказы в машиностроении (г/г) (апр) Прогноз 9,6% Пред. 3,9% Факт -2,4%
Только: 1:45 JPY Базовые заказы в машиностроении (г/г) (апр)
Если бы текст был статичным было бы проще, но он всегда меняется.
Мысли есть, что можно по слову Время, найти время. Но не хватает знаний.
Подскажите какой метод использовать ?
Добавляю исходный файл: Яндекс Диск
Все началось, как я понял, с этого вопроса: Индекс за пределами диапазона C# XPath. Потом продолжилось здесь, а результатом должен был быть банальный парсинг сайта. Проблема эта не нова. Если поискать по SO, то можно найти кучу вопросов и ответов.
Только ради того, чтоб закончить эпопею с этим сайтом, решил помочь.
Таблица на этом сайте строится динамически с помощью javascript. Потому либо нужено использовать что-то типа Selenium, либо, если не охота париться, просто открываем сайт в браузере, а потом сохраняем страницу в файл html.
А дальше работаем с файлом
Создадим пару классов для хранения этой информации
public class EconomicCalendar
{
public string Title { get; set; }
public List<CalendarRow> Rows { get; } = new List<CalendarRow>();
}
public class CalendarRow
{
public string ID { get; set; }
public string EventAttrId { get; set; }
public string DataEventDatetime { get; set; }
public string FirstLeftTile { get; set; }
public string CountryAbbr { get; set; }
public string CountryRus { get; set; }
public string CountryEng { get; set; }
public string Forecast { get; set; }
public string Previous { get; set; }
public string Alert { get; set; }
public string Volatility { get; set; }
}
Чтобы преобразовать HTML в XML установим такую библ.
Напишем такой подсобный класс
public class HtmlToXmlService
{
/// <summary>
/// Получение экземпляра XDocument на основе html файла
/// </summary>
/// <param name="pathToFile">путь к файлу html</param>
/// <returns>экземпляр XDocument</returns>
public static XDocument GetXDocument(string pathToFile)
{
if (String.IsNullOrEmpty(pathToFile)) throw new ArgumentNullException(nameof(pathToFile));
if (!File.Exists(pathToFile)) throw new ArgumentException("Файл не найден!");
//читаем файл и получаем документ
XDocument result = null;
using (StreamReader sr = File.OpenText(pathToFile))
{
result = FromHtml(sr);
}
//удаление пространства имен
RemoveNamespaces(result);
return result;
}
private static void RemoveNamespaces(XDocument result)
{
//удаление namespaces у элементов
result.Descendants()
.Attributes()
.Where(x => x.IsNamespaceDeclaration)
.Remove();
foreach (var elem in result.Descendants())
elem.Name = elem.Name.LocalName;
//удаление namespaces у атрибутов элементов
foreach (var attr in result.Descendants().Attributes())
{
var elem = attr.Parent;
attr.Remove();
elem.Add(new XAttribute(attr.Name.LocalName, attr.Value));
}
}
private static XDocument FromHtml(TextReader reader)
{
// setup SgmlReader
SgmlReader sgmlReader = new SgmlReader();
sgmlReader.DocType = "HTML";
sgmlReader.WhitespaceHandling = WhitespaceHandling.All;
sgmlReader.CaseFolding = CaseFolding.ToLower;
sgmlReader.InputStream = reader;
return XDocument.Load(sgmlReader);
}
}
В этом классе будем парсить xml с помощью LINQ (может не самым удобным образом..., критика приветствуется)
/// <summary>
/// Обработка страницы сайта полученной с адреса https://ru.investing.com/economic-calendar/
/// </summary>
public class EconomicCalendarService
{
/// <summary>
/// Парсинг файла HTML сохраненной страницы
/// </summary>
/// <param name="pathToHtmlFile">путь к файлу html</param>
/// <returns>экземпляр EconomicCalendar </returns>
public static Task<EconomicCalendar> GetEconomicCalendar(string pathToHtmlFile)
{
if (String.IsNullOrEmpty(pathToHtmlFile)) throw new ArgumentNullException(nameof(pathToHtmlFile));
EconomicCalendar result = new EconomicCalendar();
//получаем из Html файла -> XDocument
XDocument document = HtmlToXmlService.GetXDocument(pathToHtmlFile);
//название таблицы
result.Title = document.Descendants("table")
.Where(table => table.Attributes("id").Any())
.Where(t => t.Attribute("id").Value.StartsWith("economicCalendarData"))
.Descendants("td")
.Where(td => td.Attributes("class").Any())
.Where(td => td.Attribute("class").Value.StartsWith("theDay"))
.First().Value;
//извлекаем строки таблицы
var crs = document.Root.Element("body")
.Descendants("tr")
.Where(tr => tr.Attributes("class").Any())
.Where(tr => tr.Attribute("class").Value.StartsWith("js-event-item"))
.Select(tr => new CalendarRow
{
ID = tr.Attribute("id")?.Value,
EventAttrId = tr.Attribute("event_attr_id")?.Value,
DataEventDatetime = tr.Attribute("data-event-datetime")?.Value,
FirstLeftTile = tr.Descendants("td")
.FirstOrDefault(td => td.Attribute("class").Value.StartsWith("first left"))
?.Value,
CountryAbbr = tr.Descendants("td")
.FirstOrDefault(td => td.Attribute("class").Value.StartsWith("left flagCur"))
?.Value,
CountryRus = tr.Descendants("td")
.Where(td => td.Attribute("class").Value.StartsWith("left flagCur"))
.Select(td => td?.Descendants().First()?.Attribute("title")?.Value)
.FirstOrDefault(),
CountryEng = tr.Descendants("td")
.Where(td => td.Attribute("class").Value.StartsWith("left flagCur"))
.Select(td => td?.Descendants().First()?.Attribute("data-img_key")?.Value)
.FirstOrDefault(),
Forecast = tr.Descendants("td")
.FirstOrDefault(td => td.Attribute("class").Value.StartsWith("fore"))
?.Value,
Previous = tr.Descendants("td")
.Where(td => td.Attribute("class").Value.StartsWith("prev"))
.Select(td => td?.Descendants().First()?.Value)
.FirstOrDefault(),
Alert = tr.Descendants("td")
.Where(td => td.Attribute("class").Value.StartsWith("alert"))
.Select(td => td.Attribute("data-name")?.Value)
.FirstOrDefault(),
Volatility = tr.Descendants("td")
.Where(td => td.Attribute("class").Value.StartsWith("left textNum"))
.Select(td => td.Attribute("title")?.Value)
.FirstOrDefault(),
});
//вносим строки
result.Rows.AddRange(crs);
return Task.FromResult(result);
}
}
Как-то так. Построение граф интерфейса банально, код приводить не буду. Только как пользоваться написанным выше классом
try
{
EconomicCalendar calendar = await EconomicCalendarService.GetEconomicCalendar(File);
Title = calendar.Title;
Rows = calendar.Rows;
}
catch (Exception ex)
{
_mainWindow.ShowMessage($"Возникла ошибка: {ex.Message}");
}
Пример можно скачать здесь
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости