“智能”的解析和使用网站数据的方法?

33

如何智能解析网页搜索结果返回的数据?

举个例子,假设我想创建一个网络服务,通过解析多个图书供应商网站的搜索结果来查找在线书籍。我可以获取页面的原始HTML数据,并进行一些正则表达式操作,使数据适用于我的网络服务,但如果任何一个网站更改了页面的格式,我的代码就会出现错误!

RSS确实是一个很好的选择,但许多网站没有基于XML/JSON的搜索。

是否有任何工具包可以帮助自动传播页面上的信息?一个疯狂的想法是使用模糊AI模块识别搜索结果页面上的模式,并相应地解析结果...


关于编程语言,我精通PHP,但如有必要,我也愿意使用ASP.NET。感谢所有的回复! - bluebit
一个好的正则表达式在使用中可以出奇地灵活和宽容。一种好的技巧是匹配数据项之前的区域,然后使用懒惰量词将数据放入捕获组中,最后再匹配数据之后的区域。如果您以灵活的方式定义了前/后匹配,它们可以很好地处理格式的变化。www.regular-expressions.info提供了一些关于这个和其他技术的好解释。 - BobMcGee
12个回答

24

我最近进行了一些工作,以下是我的经验。

有三种基本方法:

  1. 正则表达式。
    • 最灵活,易于处理结构松散的信息和变化的格式。
    • 难以进行结构/标签分析,但易于进行文本匹配。
    • 内置数据格式验证。
    • 维护较其他方法更困难,因为需要为要用于提取/转换文档的每个模式编写一个正则表达式。
    • 通常比第二种和第三种慢。
    • 适用于类似格式的项目列表。
    • 良好的正则表达式开发/测试工具和一些示例页面会很有帮助。我在这里对RegexBuddy有好话要说。请尝试他们的演示版。
    • 我在这方面取得了最大的成功。灵活性让您可以使用野生、丑陋的HTML代码。
  2. 将HTML转换为XHTML并使用XML提取工具。清理HTML,将其转换为合法的XHTML,并使用XPath/XQuery/X-whatever查询它作为XML数据。
    • 工具:TagSoup,HTMLTidy等
    • HTML到XHML转换的质量非常重要,而且高度可变。
    • 如果您想要的数据是由HTML布局和标记结构化的(HTML表中的数据、列表、DIV/SPAN组等),则最佳方案。
    • 最适合获取链接结构、嵌套表格、图片、列表等。
    • 应该比选项1快,但比选项3慢。
    • 如果内容格式更改/不固定,但文档结构/布局不变,则效果很好。
    • 如果数据没有由HTML标记结构化,那么就会遇到麻烦。
    • 可以与选项1一起使用。
  3. 解析器生成器(ANTLR等) - 创建用于解析和分析页面的语法。
    • 我没有尝试过这个方法,因为它不适用于我的混乱页面。
  • 如果HTML结构高度结构化,非常固定、规律且从不改变,则最为适宜。
  • 如果文档中存在易于描述的模式,但它们不涉及HTML标记且涉及递归或复杂行为,则使用此选项。
  • 不需要XHTML输入。
  • 通常是吞吐量最快的。
  • 学习曲线陡峭,但易于维护。
  • 我尝试过使用Web Harvest来进行第二个选项的操作,但我觉得他们的语法有点奇怪。这是一种混合了XML和一些伪Java脚本语言的方式。如果您喜欢Java,并且喜欢XML风格的数据提取(XPath,XQuery),那么这可能适合您。


    编辑:如果使用正则表达式,请确保使用具有惰性量词和捕获组的库!PHP较旧的正则表达式库缺少这些内容,而它们对于在HTML的开放/关闭标记之间匹配数据至关重要。


    3

    您没有说明使用的编程语言。在Java领域,您可以使用TagSoup和XPath来帮助最小化痛苦。这里有一个来自this blog的示例(当然,随着您的需求变得更加复杂,XPath可能会变得更加复杂):

    URL url = new URL("http://example.com");
    SAXBuilder builder = new SAXBuilder("org.ccil.cowan.tagsoup.Parser"); // build a JDOM tree from a SAX stream provided by tagsoup
    Document doc = builder.build(url);
    JDOMXPath titlePath = new JDOMXPath("/h:html/h:head/h:title");
    titlePath.addNamespace("h","http://www.w3.org/1999/xhtml");
    String title = ((Element)titlePath.selectSingleNode(doc)).getText();
    System.out.println("Title is "+title);
    

    我建议将XPath表达式外部化,这样如果网站发生更改,您就有一定的保护措施。
    以下是一个XPath示例,我绝对不会用它来屏幕抓取此网站。不可能,不是我做的:
    "//h:div[contains(@class,'question-summary')]/h:div[@class='summary']//h:h3"
    

    3
    没有一个固定的HTML结构来解析,我不想维护查找数据的正则表达式。你可以通过一个正确的构建树的解析器来解析HTML。然后选择元素......这样更容易维护。
    显然,最好的方法是引擎输出一些带有固定标记的XML,您可以解析和验证它。我认为一个具有一些“在黑暗中”探测所产生的树的HTML解析库比正则表达式更容易维护。
    这样,你只需要检查<a href="blah" class="cache_link">...变成<a href="blah" class="cache_result">...或其他什么。
    底线是,使用正则表达式搜索特定元素将会很困难。更好的方法是构建类似于页面的DOM模型,并寻找标记中的字符数据的“锚点”。
    或者向该网站发送电子邮件,说明需要XML API......你可能会被雇佣!

    如果正确使用,正则表达式是可维护的。一些类型允许嵌入注释,这可以非常有帮助。您还可以使用捕获组和惰性量词来匹配前后的结构元素,并在中间捕获数据(使用惰性量词)。这些行为很像DOM或树解析,但不需要干净的XML。 - BobMcGee

    2
    您没有提到您使用的技术栈。如果您正在解析HTML,我建议使用解析库: 还有一些网站可以做到您所说的事情-商业和免费的。它们会爬取网站并提供Web服务接口。
    而一个通用的Web服务,可以提供一些屏幕抓取功能是Yahoo Pipes。上一个关于此问题的Stackoverflow问答

    2

    虽然不是百分之百可靠,但你可以考虑使用解析器,例如Beautiful Soup。如果页面布局发生变化,它不会神奇地找到相同的信息,但比编写复杂的正则表达式容易得多。请注意,这是一个Python模块。


    1

    您考虑过使用 HTML 操作库吗?Ruby 有一些非常不错的库,例如 hpricot

    如果使用好的库,您可以使用 CSS 选择器或 XPath 指定页面上需要的部分。这比使用正则表达式更加健壮可靠。

    下面是 hpricot wiki 上的示例:

     doc = Hpricot(open("qwantz.html"))
     (doc/'div img[@src^="http://www.qwantz.com/comics/"]')
       #=> Elements[...]
    

    我相信你可以在 .NET 或 Python 等编程语言中找到一个能够实现类似功能的库。


    1

    不幸的是,“爬取”是最常见的解决方案,就像你所说的尝试从网站解析HTML。您可以检测页面的结构更改并标记警报以供您修复,因此他们端口的更改不会导致错误数据。在语义网络成为现实之前,这几乎是确保大型数据集的唯一方法。

    或者,您可以坚持使用API提供的小型数据集。雅虎正在努力通过API提供可搜索的数据(请参阅YDN),我认为Amazon API开放了很多书籍数据等等。

    希望这有点帮助!

    编辑:如果您使用PHP,我建议使用SimpleHTMLDOM。


    1

    尝试谷歌搜索屏幕抓取+您喜欢的编程语言。 我知道一些Python选项,您可能会找到您喜欢的编程语言的等效选项:

    • Beatiful Soup
    • mechanize:类似于perl WWW:Mechanize。提供类似浏览器的对象与网页交互
    • lxml:python绑定到libwww
    • scrapemark:使用模板来获取页面片段
    • pyquery:允许您在xml / xhtml文档中进行jQuery查询
    • scrapy:用于编写爬虫和解析网页的高级抓取和网络爬虫框架

    根据要抓取的网站,您可能需要使用上述一种或多种方法。


    0

    http://www.parselets.com 上的 Parsley 看起来相当不错。

    它允许你使用 JSON 定义“parslets”,从而定义在页面上搜索什么内容,然后将这些数据解析出来。


    4
    链接不能保持六年? - waterlooalex

    0

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接