遍历 HtmlNodes 并收集数据每次都会给我相同的结果

Looping through HtmlNodes and collecting data gives me the same result every time

我有一个 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 包含相同 object 的副本,但是当我查看 HTML 以及调试和查看 HtmlNode node 时,它们的不同之处在于他们应该。

要么我对一些非常明显的事情视而不见,要么我遇到了一些我不理解的 async 问题。有任何想法吗?我应该从这个调用中得到 50 个唯一的 objects,现在我只得到前 50 次。

提前谢谢你,维克多。

编辑:添加一些截图来展示我的困境。查看本地 InnerHtml (node) 和 foreach 循环的第 1 项和第 2 项的标题。

编辑 2:设法在 .NET 上重现 Fiddle:https://dotnetfiddle.net/A2I4CQ

我不太确定如何描述这个,但你的问题就在这里(我认为)

//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;
            }

您需要使用 .// 而不是 //

这里是固定的Fiddle:https://dotnetfiddle.net/dZkSRN


// 将搜索文档中的任意位置

.// 会搜索当前节点的任意位置