5

我正在使用 HtmlAgilityPack 来解析大约 200,000 个 HTML 文档。

我无法预测这些文档的内容,但是一个这样的文档会导致我的应用程序失败并显示StackOverflowException. 该文档包含以下 HTML:

<ol>
    <li><li><li><li><li><li>...
</ol>

大约有 10,000 个<li>这样嵌套的元素。由于 HtmlAgilityPack 解析 HTML 的方式,它会导致StackOverflowException.

不幸的是,在 .NET 2.0 及更高版本中无法捕获 StackOverflowException。

我确实想知道为线程的堆栈设置更大的大小,但是设置更大的堆栈大小是一种技巧:它会导致我的程序使用更多的内存(我的程序启动了大约 50 个线程来处理 HTML,所以所有这些线程会增加堆栈大小)并且如果再次遇到类似情况则需要手动调整。

我可以采用其他任何解决方法吗?

4

3 回答 3

5

我刚刚修补了一个我认为与您描述的相同的错误。已将补丁上传到 hap 项目站点...

http://www.codeplex.com/site/users/view/sjdirect(参见 2012 年 3 月 8 日的补丁)

或在此处查看有关问题和结果的更多文档......

https://code.google.com/p/abot/issues/detail?id=77

实际的修复是... 添加了 HtmlDocument.OptionMaxNestedChildNodes 可以设置以防止由大量嵌套标签引起的 StackOverflowExceptions。它将抛出一个 ApplicationException 消息“文档有多个嵌套标签。这可能是由于页面没有正确关闭标签。”

补丁后我如何使用 Hap...

HtmlDocument hapDoc = new HtmlDocument();
hapDoc.OptionMaxNestedChildNodes = 5000;//This is what was added
string rawContent = GETTHECONTENTHERE
try
{
    hapDoc.LoadHtml(RawContent);    
}
catch (Exception e)
{
    //Instead of a stackoverflow exception you should end up here now
    hapDoc.LoadHtml("");
    _logger.Error(e);
}
于 2013-03-08T20:55:18.807 回答
2

理想情况下,长期解决方案是修补 HtmlAgilityPack 以使用堆堆栈而不是调用堆栈,但这对我来说是一项太大的任务。我暂时丢失了我的 CodePlex 帐户详细信息,但是当我找回它们时,我将提交有关该问题的问题报告。我还注意到,这个问题可能会给任何使用 HtmlAgilityPack 清理用户提交的 HTML 的站点带来拒绝服务攻击漏洞——精心制作的过度嵌套的 HTML 文档会导致 w3wp.exe 进程终止。

同时,我认为最好的方法是手动覆盖最大线程堆栈大小。我之前的说法是错误的,即更大的堆栈大小意味着所有线程都会自动消耗该内存(似乎内存页面是在线程堆栈增长时分配给它的,而不是一次全部分配)。

我复制了该<ol><li>页面并进行了一些实验。我发现当堆栈大小小于2^21字节(2MB)时,我的程序失败了,但最大2^22字节大小(4MB)成功了——我书中的 4MB 作为“可接受的”黑客通过了......暂时。

于 2012-10-01T01:00:28.917 回答
-1

这应该有效:


HtmlDocument.MaxDepthLevel = 10000;
var doc = new HtmlDocument();
try
{
    doc.LoadHtml(document);
}
catch(Exception ex)
{
    Console.WriteLine("Exception while loading html: " + ex);
    yield break;
}

于 2022-01-11T10:31:59.117 回答