为什么我的XPath查询(抓取HTML表)只在Firebug中工作,而在应用程序I';我在发展?
这意味着为每周出现一到两次的所有类似问题(但太过具体的问题,无法成为接近目标的候选人)提供一个规范的问答 我正在开发一个应用程序,需要解析一个包含表的网站。由于导出用于抓取网页的XPath表达式既枯燥又容易出错,因此我想使用Firebug的XPath提取器功能(或其他浏览器中的类似工具)来实现这一点 示例输入如下所示:为什么我的XPath查询(抓取HTML表)只在Firebug中工作,而在应用程序I';我在发展?,html,dom,xpath,firebug,google-chrome-devtools,tag-soup,htmltidy,Html,Dom,Xpath,Firebug,Google Chrome Devtools,Tag Soup,Htmltidy,这意味着为每周出现一到两次的所有类似问题(但太过具体的问题,无法成为接近目标的候选人)提供一个规范的问答 我正在开发一个应用程序,需要解析一个包含表的网站。由于导出用于抓取网页的XPath表达式既枯燥又容易出错,因此我想使用Firebug的XPath提取器功能(或其他浏览器中的类似工具)来实现这一点 示例输入如下所示: 示例单元 另一个 福巴 42 我想提取第一个数据单元(“foobar”)。Firebug提出了XPath表达式 //表[@id=“example”]/tbody/tr[2]/
示例单元
另一个
福巴
42
我想提取第一个数据单元(“foobar”)。Firebug提出了XPath表达式
//表[@id=“example”]/tbody/tr[2]/td[1]
哪个可以在任何XPath测试插件中正常工作,但不是我自己的应用程序(没有找到结果)。如果我将查询缩减到//table[@id]
,它会再次工作
出了什么问题?问题:DOM需要
标记
Firebug、Chrome的开发工具、JavaScript中的XPath函数和其他函数在DOM上工作,而不是基本的HTML源代码
DOM for HTML要求页脚(
,
)的表头中不包含的所有表行都包含在表体标记中。因此,如果在解析(X)HTML时缺少该标记,浏览器会添加该标记。例如,他说
tbody
元素对于所有表都是公开的,即使该表没有明确定义tbody
元素
有一个问题
另一方面:
除非桌子只包含一个桌子主体且没有桌子头或脚部分,否则始终需要t桌子主体
开始标签
大多数XPath处理器处理原始XML
除了JavaScript,大多数XPath处理器都处理原始XML,而不是DOM,因此不添加
标记。HTML解析器库也喜欢并只输出XHTML,而不是“DOM-HTML”
这是在Stackoverflow上发布的PHP、Ruby、Python、Java、C#、GoogleDocs(电子表格)和其他许多应用程序的常见问题Selenium在浏览器内部运行并在DOM上工作——因此它不受影响强>
复制问题
将Firebug(或Chrome的开发工具)显示的源代码与通过右键单击并选择“显示页面源代码”(或浏览器中的任何名称)或使用curl获得的源代码进行比较http://your.example.org
在命令行上。后者可能不包含任何
元素(它们很少使用),Firebug将始终显示它们
解决方案1:拆下
/t车斗轴台阶
检查您所停留的表是否真的不包含
元素(参见最后一段)。如果是的话,你可能会遇到另一种问题
现在删除/tbody
轴步骤,这样您的查询将如下所示
//表[@id=“example”]/tr[2]/td[1]
解决方案2:跳过
标记
这是一个相当脏的解决方案,对于嵌套表来说可能会失败(可以跳转到内部表)。我只建议在极少数情况下这样做
将/tbody
轴步骤替换为后代步骤或自身步骤:
//表[@id=“example”]//tr[2]/td[1]
解决方案3:允许带和不带
标记的输入
如果您事先不确定您的表或查询是否同时在“HTML源代码”和DOM上下文中使用;并且不想/不能使用解决方案2中的hack,提供一个替代查询(针对XPath 1.0)或使用“可选”axis步骤(XPath 2.0及更高版本)
- XPath 1.0:
//表[@id=“example”]/tr[2]/td[1]|//表[@id=“example”]/tbody/tr[2]/td[1]
- XPath2.0:
//表[@id=“example”]/(tbody,)/tr[2]/td[1]
遇到了同样的问题。我几乎编写了一个递归函数来检查每个tbody标记是否存在,并以这种方式遍历dom,然后我记得我知道regex:)
在解析之前,将html作为字符串获取。用regex插入缺少的
和
标记,然后将其加载回DOMDocument对象
Jens Erat给出了一个很好的解释,但这里是
解决方案4:确保HTML源代码始终具有带有regex的
标记
JavaScript
var html='foobar';
替换(/(]+)?>([^]+)(!]+)?>)/g,“$1”)。替换(/(]+)?>)(]+)?>)/g,“$1$4”);
PHP
$html=$dom->saveHTML();
$html=preg_replace(数组('/(]+)?>([^]+)?)(?!]+)?>)/','/(]+)?>)(]+)?>)/'),数组('$1','$1$4'),$html);
$dom->loadHTML($html);
只有正则表达式:
matches `<table>` tag with whatever else junk inside the tag and between this and the next tag if the next tag is NOT `<tbody>` also with stuff inside the tag
/(<table([^>]+)?>([^<>]+)?)(?!<tbody([^>]+)?>)/
replace with
$1<tbody>
the $1 referencing the captured `<table>` tag with contents.
Do the same for the closing tag like this:
/(<(?!(\/tbody))([^>]+)?>)(<\/table([^>]+)?>)/
replace with
$1</tbody>$4
将``标记与标记内的任何其他垃圾匹配,如果下一个标记不是``则将此标记与下一个标记之间的垃圾匹配,并将其与标记内的内容匹配
/(]+)?>([^]+)?)(?!]+)?>)/
取代
$1
$1引用捕获的带有内容的``标记。
对结束标记执行相同的操作,如下所示:
/(]+)?>)(]+)?>)/
取代
$1$4
这样,dom将始终在必要时具有
标记。也许值得一提的是,在
标记中测试这些xpath查询不是一个好主意,这些标记插入
后面,因为它将失败(元素还没有出现)。今天,我还进行了一些讨论,因为这不是表,而是与浏览器Xpath相关的:Firefox似乎接受大写元素和属性名。DOMDocument xpath需要那些小写字母(不是这个参考问题中的问题,但我想把它交叉连接起来,因为我第一次看到它,这是一个伟大的倡议!)。除了上面所说的,对于这些场景,我的刮板,我有一个“skipFirstRow”的标志,它实际上非常有效(对于我正在刮板的页面).我已经搜索了4个小时的解决方案,因为我想从一个站点获取数据
matches `<table>` tag with whatever else junk inside the tag and between this and the next tag if the next tag is NOT `<tbody>` also with stuff inside the tag
/(<table([^>]+)?>([^<>]+)?)(?!<tbody([^>]+)?>)/
replace with
$1<tbody>
the $1 referencing the captured `<table>` tag with contents.
Do the same for the closing tag like this:
/(<(?!(\/tbody))([^>]+)?>)(<\/table([^>]+)?>)/
replace with
$1</tbody>$4