我在面试时回答了一些测验问题,问题是关于如何进行屏幕抓取。也就是说,假设您没有更好的结构化方法直接查询信息(例如,Web服务),则从网页中挑选内容。
我的解决方案是使用 XQuery 表达式。该表达式相当长,因为我需要的内容在HTML层次结构中非常深。在找到具有id
属性的元素之前,我必须以一种公平的方式对祖先进行搜索。例如,刮取有关Product Dimensions的Amazon.com页面,如下所示:
//a[@id="productDetails"]
/following-sibling::table
//h2[contains(child::text(), "Product Details")]
/following-sibling::div
//li
/b[contains(child::text(), "Product Dimensions:")]
/following-sibling::text()
那是一个很讨厌的表达,但这就是为什么亚马逊提供了一个Web服务API。无论如何,这只是一个例子。问题不是关于亚马逊,而是关于屏幕抓取。
面试官不喜欢我的解决方案。他认为这很脆弱,因为亚马逊对页面设计的更改可能需要重写XQuery表达式。调试与它所针对的页面中的任何内容都不匹配的XQuery表达式很困难。
我不同意他的说法,但我并不认为他的解决方案有任何改善:他认为最好使用正则表达式,并在运输重量附近搜索内容和标记。例如,使用Perl:
$html =~ m{<li>\s*<b>\s*Product Dimensions:\s*</b>\s*(.*?)</li>}s;
我的反对意见是,这也容易使亚马逊更改其HTML代码。他们可以用大写字母(
<LI>
)拼写HTML标签,或添加CSS属性,或将<b>
更改为<span>
或将标签“Product Dimensions:”更改为“Dimensions:”,或进行许多其他类型的更改。我的观点是,正则表达式不能解决他在XQuery解决方案中所说的弱点。但是此外,除非您在表达式中添加足够的上下文,否则正则表达式会发现误报。它还可能会无意中匹配注释,属性字符串或CDATA部分中的内容。
我的问题是,您使用什么技术来进行屏幕抓取?您为什么选择该解决方案?是否有一些令人信服的理由使用它?还是从不使用另一个?除了上面显示的以外,还有第三种选择吗?
PS:为争辩起见,假设没有Web服务API或其他更直接的方式来获取所需的内容。
最佳答案
出于经理的原因,我将使用正则表达式,外加一些内容(更便于移植,更便于外部程序员遵循,等等)。
您的反对论点错失了他的解决方案在局部变化方面是脆弱的,而您的解决方案在全局变化方面却是脆弱的。任何破坏他的意志都会破坏你的意志,反之亦然。
最后,将slop/flex集成到他的解决方案中要容易得多(例如,如果您必须处理输入中的多个细微变化)。
关于regex - 屏幕抓取: regular expressions or XQuery expressions?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/646484/