【问题标题】:MVC StackOverflowException with larger html data具有较大 html 数据的 MVC StackOverflowException
【发布时间】:2015-04-15 20:29:00
【问题描述】:

我有以下方法(我正在使用 htmlagilitypack):

public DataTable tableIntoTable(HtmlDocument doc)
    {
        var nodes = doc.DocumentNode.SelectNodes("//table");
        var table = new DataTable("MyTable");
        table.Columns.Add("raw", typeof(string));                       

        foreach (var node in nodes)
        {
            if (
                (!node.InnerHtml.Contains("pldefault"))
                && (!node.InnerHtml.Contains("ntdefault"))
                && (!node.InnerHtml.Contains("bgtabon"))                
                )
            {
                table.Rows.Add(node.InnerHtml);
            }
        }
        return table;
    }

它接受使用这个抓取的 html:

 public HtmlDocument getDataWithGet(string url)
    {
        using (var wb = new WebClient())
        {
            string response = wb.DownloadString(url);
            var doc = new HtmlDocument();
            doc.LoadHtml(response);
            return doc;
        }
    }

对于 3294 行长的 html 文档,一切正常。
当我提供一些 33960 行长的 html 时,我得到: StackOverflowException 在 tableIntoTable 方法中的 IF 语句中未处理,如下图所示: http://imgur.com/Q2FnIgb

我认为这可能与 1000 的 MaxHttpCollectionKeys 限制有关,因此我尝试将其放入我的 Web.config 中,但仍然无法正常工作: 添加 key="aspnet:MaxHttpCollectionKeys" value="9999"

我不确定从这里往哪里走,它只会在较大的 html 文档中中断。

【问题讨论】:

  • 为什么不用xpath查询节点内容?
  • 这不是var nodes = doc.DocumentNode.SelectNodes("//table");在做什么吗?
  • 您的查询很糟糕,您可以使用更合适的查询,但是关于异常尝试使用 editbin.exe 增加您的堆栈大小,它可能会起作用,至少到 1MB
  • @jrow 然后您将查看每个节点以获取所有内容并执行 String.Contains 操作。我不知道这怎么会导致堆栈溢出(您可以发布堆栈跟踪以进行进一步调查),但使用 xpath ALSO 更快且资源消耗更少。
  • 不幸的是,我必须选择所有表,我从中提取的 html 源没有表 id,或者无论如何都无法区分它们(我无法控制源 html)。

标签: c# html html-agility-pack dom


【解决方案1】:

假设您的 if 语句中的值包含在某个表的某个后代的某个属性值中。

var xpath = @"//table[not(.//*[contains(@*,'pldefault') or
                               contains(@*,'ntdefault') or 
                               contains(@*,'bgtabon')])]";

var tables = doc.DocumentNode.SelectNodes(xpath);

更新:根据您的 cmets 更准确:

        @"//table[not(.//td[contains(@class,'pldefault') or
                            contains(@class,'ntdefault') or 
                            contains(@class,'bgtabon')])]";

【讨论】:

  • 这行得通。是因为它只选择我想要的东西,而且数量可能更少吗? (pldefault、nedefault 和 bgtabon 是我不想要的表)
  • @Jrow 但它们究竟是表标签中的属性或表标签后代的属性,分享有关您的 html 的更多信息将有助于我在不知道您到底想要什么的情况下编写此答案。
  • 这是我不需要的表中的 TD 类:<TD CLASS="pldefault"> 有很多表,其中一些包含我不需要的数据的表包含带有类的 TD pldefault、ntdefault 和 bgtabon。其他表没有类或ID或任何东西,只是<TABLE>我试图将html放入pastebin但它太大了。
  • @Jrow 啊太好了,那么这个查询适合你。
猜你喜欢
  • 1970-01-01
  • 2011-11-23
  • 2021-09-27
  • 1970-01-01
  • 1970-01-01
  • 2020-05-09
  • 1970-01-01
  • 1970-01-01
  • 2021-05-20
相关资源
最近更新 更多