Цикл через HtmlNodes и сбор данных дает мне один и тот же результат каждый раз - PullRequest
1 голос
/ 21 октября 2019

У меня есть метод async, который вызывает преобразователь для преобразования строки HTML в IEnumerable:

public async Task<IEnumerable<MovieRatingScrape>> GetMovieRatingsAsync(string username, int page)
{
    var response = await _httpClient.GetAsync($"/betyg/{username}?p={page}");
    response.EnsureSuccessStatusCode();
    var html = await response.Content.ReadAsStringAsync();
    return new MovieRatingsHtmlMapper().Map(html);
}

...

public class MovieRatingsHtmlMapper : HtmlMapperBase<IEnumerable<MovieRatingScrape>>
{
    // In reality, this method belongs to base class with signature T Map(string html)
    public IEnumerable<MovieRatingScrape> Map(string html)
    {
        var htmlDocument = new HtmlDocument();
        htmlDocument.LoadHtml(html);
        return Map(htmlDocument);
    }

    public override IEnumerable<MovieRatingScrape> Map(HtmlDocument item)
    {
        var movieRatings = new List<MovieRatingScrape>();
        var nodes = item.DocumentNode.SelectNodes("//table[@class='list']/tr");

        foreach (var node in nodes)
        {
            var title = node.SelectSingleNode("//td[1]/a")?.InnerText;

            movieRatings.Add(new MovieRatingScrape
            {
                Date = DateTime.Parse(node.SelectSingleNode("//td[2]")?.InnerText),
                Slug = node.SelectSingleNode("//td[1]/a[starts-with(@href, '/film/')]")?
                    .GetAttributeValue("href", null)?
                    .Replace("/film/", string.Empty),
                SwedishTitle = title,
                Rating = node.SelectNodes($"//td[3]/i[{XPathHasClass("fa-star")}]").Count
            });
        }

        return movieRatings;
    }
}

Полученный список movieRatings содержит копии того же объекта, но когда я смотрюв HTML, и когда я отлаживаю и просматриваю HtmlNode node, они отличаются, как и должно быть.

Либо я слеп к чему-то действительно очевидному, либо я сталкиваюсь с какой-то проблемой async, которой у меня нетухватить. Есть идеи? Я должен получить 50 уникальных объектов из этого вызова, теперь я получаю только первые 50 раз.

Заранее спасибо, Виктор.

Редактировать: добавив несколько скриншотов, чтобы показать мое затруднительное положение,Посмотрите на местных жителей InnerHtml (node) и название для элементов 1 и 2 цикла foreach.

Редактировать 2: удалось воспроизвести на .NET Fiddle: https://dotnetfiddle.net/A2I4CQ

enter image description here enter image description here

Ответы [ 2 ]

1 голос
/ 23 октября 2019

Вам нужно использовать .//, а не //

Вот фиксированная скрипка: https://dotnetfiddle.net/dZkSRN


// будет искать в любом месте документа

.// будет искать в любом месте текущего узла

0 голосов
/ 23 октября 2019

Я не очень уверен, как описать это, но ваша проблема здесь (я думаю)

//table[@class='list']/tr"

, в частности, //

Я испытал то же самое, когда искал промежуток,мне пришлось использовать что-то похожее

    var nodes = htmlDoc.DocumentNode.SelectNodes("//li[@class='itemRow productItemWrapper']");
            foreach(HtmlNode node in nodes)
            {
                var nodeDoc = new HtmlDocument();
                nodeDoc.LoadHtml(node.InnerHtml);

string name = nodeDoc.DocumentNode.SelectSingleNode("//span[@class='productDetailTitle']").InnerText;
            }
...