Regex 屏幕抓取:正则表达式还是XQuery表达式?

Regex 屏幕抓取:正则表达式还是XQuery表达式?,regex,screen-scraping,xquery,Regex,Screen Scraping,Xquery,我在回答面试中的一些问答题,问题是我将如何做屏幕抓取。也就是说,从网页中挑选内容,假设您没有更好的结构化方式直接查询信息(例如web服务) 我的解决方案是使用XQuery表达式。表达式相当长,因为我需要的内容在HTML层次结构中相当深。在找到一个具有id属性的元素之前,我必须以公平的方式搜索祖先。例如,在Amazon.com页面上搜索产品维度如下所示: //a[@id="productDetails"] /following-sibling::table //h2[contains(child:

我在回答面试中的一些问答题,问题是我将如何做屏幕抓取。也就是说,从网页中挑选内容,假设您没有更好的结构化方式直接查询信息(例如web服务)

我的解决方案是使用XQuery表达式。表达式相当长,因为我需要的内容在HTML层次结构中相当深。在找到一个具有
id
属性的元素之前,我必须以公平的方式搜索祖先。例如,在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()
这是一个非常糟糕的表达,但这就是为什么Amazon提供了web服务API。无论如何,这只是一个例子。问题不是关于亚马逊,而是关于屏幕抓取

面试官不喜欢我的解决方案。他认为它很脆弱,因为亚马逊改变页面设计可能需要重写XQuery表达式。调试一个与它所应用的页面中的任何内容都不匹配的XQuery表达式是很困难的

我并不反对他的说法,但我不认为他的解决方案有任何改进:他认为最好使用正则表达式,搜索装运重量附近的内容和标记。例如,使用Perl:

$html =~ m{<li>\s*<b>\s*Product Dimensions:\s*</b>\s*(.*?)</li>}s;
$html=~m{
  • \s*\s*产品维度:\s*\s*(.*)
  • }s;
    我的反驳是,这也容易受到Amazon更改HTML代码的影响。他们可以用大写字母(
  • )拼写HTML标记,或者添加CSS属性,或者将
    更改为
    ,或者将标签“产品维度:”更改为“维度:”或许多其他类型的更改。我的观点是正则表达式不能解决他在我的XQuery解决方案中指出的缺点

    但除此之外,正则表达式可以发现误报,除非向表达式添加足够的上下文。它还可能无意中匹配恰好位于注释、属性字符串或CDATA节中的内容

    我的问题是,你们用什么技术来刮屏?你为什么选择这个解决方案?是否有令人信服的理由使用它?或者永远不要使用另一个?除了我上面展示的那些,还有第三种选择吗


    PS:为了便于讨论,假设没有web服务API或其他更直接的方式来获取所需的内容。

    出于经理给出的原因,我会使用正则表达式,再加上一些(更可移植,外部程序员更容易遵循,等等)

    你的反驳忽略了一点,即他的解决方案在局部变化方面是脆弱的,而你的解决方案在全球变化方面是脆弱的。任何破坏他的东西都有可能破坏你的,但反之亦然


    最后,将slop/flex构建到他的解决方案中要容易得多(例如,如果您必须处理输入中的多个微小变化)。

    我会使用正则表达式,但这只是因为大多数HTML页面都不是有效的XML,所以您永远无法使用XQUERY


    我不知道XQuery,但在我看来它像一个XPATH表达式。如果是这样的话,它看起来有点贵,有这么多的“/”操作符。

    我用它来报废。

    我发现CSS搜索表达式比这两种表达式都更容易阅读。在您选择的语言中可能至少存在一个库,它将解析页面并允许您编写CSS指令来定位特定元素。如果附近有一个合适的类或ID钩子,那么表达式就非常简单。否则,抓取看起来合适的元素并遍历它们以找到您需要的元素


    至于易碎品,它们都是易碎品。根据定义,屏幕抓取取决于该页面的作者,而不是大幅更改其布局。选择一种可读性强且以后易于更改的解决方案。

    一种用于屏幕刮片的非脆性解决方案?祝面试官好运:仅仅因为正则表达式扔掉了很多上下文并不意味着它们不那么脆弱:只是它们在其他方面脆弱。脆弱性甚至可能不是一个缺点:如果源网页中发生了变化,如果您的解决方案引发警报,而不是试图以一种聪明(且不可预测)的方式进行补偿,您通常会得到更好的结果。正如你所说的。这些事情总是取决于你的假设:在这种情况下,取决于什么构成可能的变化


    我很喜欢:您可以容忍非XHTML兼容的网页,并结合XPath的表达能力

    试试JTidy或beautifulsou对我来说很好。
    当然//XPATH Expersion的废弃成本非常高。

    正则表达式速度非常快,可以处理非XML文档。这些都是针对XQuery的非常好的观点。然而,我认为使用一些XHTML转换器,比如tidy,或者更简单的XQuery,就像您的最后一部分:

    //b[contains(child::text(), "Product Dimensions:")]/following-sibling::text()
    
    这是一个很好的选择

    问候,


    要处理html页面,最好使用HTMLAgilityPack(以及一些Linq代码)。这是解析所有元素和/或使用XPath进行直接搜索的好方法。在我看来,它比正则表达式更准确,更容易编程。以前我有点不愿意使用它,但它很容易添加到您的项目中,我认为这是处理html的de-factor标准


    祝你好运

    这是避免基于XML的web抓取的主要原因。没有哪个XML处理器比浏览器更宽容。该页面只需打破一条格式良好的规则,就可以使XQuery完全无用。谢谢,是的,Pontus Gagge在另一个答案中建议使用HTML Agility Pack。我想知道HTML Agility Pack在内部使用了什么——XPath、正则表达式或其他一些自定义DOM解析或其他东西