我正在用 C# 编写简单的屏幕抓取程序,为此我需要选择放置在一个名为“aspnetForm”的单个表单内的所有输入(页面上有 2 个表单,我不希望来自另一个表单的输入),并且此表单中的所有输入都放置在不同的表、div 中,或者仅放置在该表单的第一个子级中。
所以我写了非常简单的 XPath 查询:
//form[@id='aspnetForm']//input
它在我测试的所有浏览器(Chrome、IE、Firefox)中按预期工作 - 它返回我想要的内容。
但在 HTMLAgilityPack 中它根本不起作用 - SelectNodes 总是返回 NULL。
我为测试编写的这个查询工作正常,但返回的不是我想要的。首先选择作为我的表单的第一个子项的所有输入,然后选择返回的表单:
//form[@id='aspnetForm']/input
//form[@id='aspnetForm']
是的,我知道我可以枚举上次查询中的节点,或者在其结果上创建另一个 SelectNode,但我真的不想这样做。我想使用与浏览器中相同的查询。
HTMLAgilityPack 中的 XPath 目前是否已损坏? C# 有任何替代的 XPath 实现吗?
UPDATE:测试代码:
using HtmlAgilityPack;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace HtmlAGPTests
{
[TestClass]
public class XPathTests
{
private const string html =
"<form id=\"aspnetForm\">" +
"<input name=\"first\" value=\"first\" />" +
"<div>" +
"<input name=\"second\" value=\"second\" />" +
"</div>" +
"</form>";
private static HtmlNode GetHtmlDocumentNode()
{
var document = new HtmlDocument();
document.LoadHtml(html);
return document.DocumentNode;
}
[TestMethod]
public void TwoLevelXpathTest() // fail - nodes is NULL actually.
{
var query = "//form[@id='aspnetForm']//input"; // what i want
var documentNode = GetHtmlDocumentNode();
var inputNodes = documentNode.SelectNodes(query);
Assert.IsTrue(inputNodes.Count == 2);
}
[TestMethod]
public void TwoSingleLevelXpathsTest() // works
{
var formQuery = "//form[@id='aspnetForm']";
var inputQuery = "//input";
var documentNode = GetHtmlDocumentNode();
var formNode = documentNode.SelectSingleNode(formQuery);
var inputNodes = formNode.SelectNodes(inputQuery);
Assert.IsTrue(inputNodes.Count == 2);
}
[TestMethod]
public void SingleLevelXpathTest() // works
{
var query = "//form[@id='aspnetForm']";
var documentNode = GetHtmlDocumentNode();
var formNode = documentNode.SelectSingleNode(query);
Assert.IsNotNull(formNode);
}
}
}
测试中出现意外行为是因为 html 包含<form>
元素。以下是相关讨论:
Ariman :“我发现解析后任何节点都没有任何子节点。所有应该位于表单(、等)内的节点都被创建为兄弟节点而不是子节点。
维克西亚:“在 Html 规范中,表单标签可以重叠,因此 Htmlagilitypack 处理此节点的方式略有不同......”
[CodePlex 讨论:FORM 对象没有子节点 https://htmlagilitypack.codeplex.com/discussions/247206]
正如建议的VikciaR在那里,尝试修改您的测试代码初始化,如下所示:
private static HtmlNode GetHtmlDocumentNode()
{
var document = new HtmlDocument();
document.LoadHtml(html);
//execute this line once
HtmlNode.ElementsFlags.Remove("form");
return document.DocumentNode;
}
边注: inputQuery
测试方法中的值TwoSingleLevelXpathsTest()
应该.//input
。注意点(.
) 开头表示该查询是相对于当前节点的。否则它会从根开始搜索,忽略前者formQuery
(没有点,你可以改变formQuery
任何东西,只要它不返回 null,inputQuery
将始终返回相同的结果)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)