Есть ли способ очистки списка элементов HTML на основе ключевых слов, где структура документа не определена?

#c# #asp.net #xpath #web-scraping #html-agility-pack

#c# #asp.net #xpath #веб-очистка #html-agility-pack

Вопрос:

Я создаю скребок для использования на многих сайтах (слишком много, чтобы очистить вручную с помощью инструмента веб-очистки, такого как Octoparse).

Каждый сайт, вероятно, будет отличаться по структуре. На некоторых сайтах могут быть данные, которые я хочу очистить; некоторые могут и не быть. Это должно быть определено с помощью списка ключевых слов / ключевых фраз. Сайты, которые я хочу, чтобы данные были проанализированы, они, вероятно, будут представлены в виде списка каким-либо образом. Однако элементы HTML, используемые для представления списка, не определены (т. Е. Могут быть списком ul, списком li, списком div, таблицей и т. Д.).

Если найдено ключевое слово / ключевая фраза, я хочу, чтобы был проанализирован не только этот элемент, но и все остальные, которые могут быть частью того же списка / группы.

Пример 1

 <div>
  <h1>Random content I am not interested in</h1>
</div>
<div>
  <h1>Some more random content I am not interested in</h1>
</div>
<div>
  <ul>
    <li>Dogs</li>
    <li>Cats</li>
    <li>Birds</li>
  </ul>
</div>
  

Пример 2

 <div>
  <h1>Random content I am not interested in</h1>
</div>
<div>
  <h1>Some more random content I am not interested in</h1>
</div>
<div>
  <div>
    <div>
      <div>
        <h1>Bob</h1>
        <p>A description of Bob</p>
      </div>
      <div>
        <h1>Ben</h1>
        <p>A description of Ben</p>
      </div>
      <div>
        <h1>Bill</h1>
        <p>A description of Bill</p>
      </div>
    </div>
  </div>
</div>
  

Из первого примера, если бы я определил элемент Dogs , я бы хотел, чтобы результат был Dogs, Cats, Birds .

Из второго примера, если бы я определил Ben, я бы хотел, чтобы результатом было 3 элемента div, каждый из которых содержит заголовок и абзац; ключ в том, что все результаты должны включать HTML, а не только текст.

Любая помощь / рекомендации будут высоко оценены.

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

1. Ваше описание желаемого результата несколько сбивает с толку; можете ли вы предоставить фактические результаты для этих двух примеров?

2. Похоже, вы ищете какое-то пользовательское решение NLP

Ответ №1:

Мне удалось что-то вроде этого:

 static IEnumerable<string> FindSimilarItems(string html, string[] values, int maxDepth)
{
    var doc = new HtmlDocument();
    doc.LoadHtml(html);
    var output = new List<string>();

    foreach (var value in values)
    {
        var rootElement = doc.DocumentNode.SelectSingleNode($"//*[text()='{value}']");
        if (rootElement == null) continue;
        for (int i = 0; i < maxDepth; i  )
        {
            var newXpath = RemoveXpathGroupIndex(rootElement.XPath, i);
            var newElements = doc.DocumentNode.SelectNodes(newXpath);
            if (newElements.Count <= 1) continue;

            output.AddRange(newElements.Select(x => x.InnerText));
        }
    }

    return output.GroupBy(x => x).Select(x => x.First()).ToList();
}

static string RemoveXpathGroupIndex(string xpath, int groupElement)
{
    var splited = xpath.Split('/');
    var pickedElement = splited.Length - 1 - groupElement;
    splited[pickedElement] = splited[pickedElement].Substring(0, splited[pickedElement].IndexOf('['));
    return string.Join("/", splited);
}
  

Этот код:

 var similarItems = FindSimilarItems(input1, new string[] { "Dogs" }, 3);
  

Вернет

 ["Dogs", "Cats", "Birds"]