34

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

例如,假设我想创建一个 Web 服务,通过解析许多图书提供商网站的搜索结果来搜索在线图书。我可以获取页面的原始 HTML 数据,并执行一些正则表达式以使数据适用于我的 Web 服务,但如果任何网站更改页面的格式,我的代码就会中断!

RSS 确实是一个了不起的选择,但是许多站点没有基于 XML/JSON 的搜索。

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

4

11 回答 11

24

我最近做了一些,这里是我的经验。

有以下三种基本方法:

  1. 常用表达。
    • 最灵活、最容易与结构松散的信息和不断变化的格式一起使用。
    • 更难进行结构/标签分析,但更容易进行文本匹配。
    • 内置数据格式验证。
    • 比其他人更难维护,因为您必须为要用于提取/转换文档的每个模式编写一个正则表达式
    • 通常比 2 和 3 慢。
    • 适用于格式相似的项目列表
    • 一个好的正则表达式开发/测试工具和一些示例页面会有所帮助。我在这里对 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 输入
    • 最快的吞吐量,通常
    • 学习曲线大,但更容易维护

我已经修改了选项 2 的网络收获,但我发现它们的语法有点奇怪。XML 和一些伪 Java 脚本语言的混合。如果您喜欢 Java,并且喜欢 XML 样式的数据提取(XPath、XQuery),那可能适合您。


编辑:如果您使用正则表达式,请确保使用带有惰性量词和捕获组的库!PHP 的旧正则表达式库缺少这些,它们对于匹配 HTML 中的打开/关闭标记之间的数据是必不可少的。

于 2009-08-03T17:39:52.857 回答
3

如果没有要解析的固定HTML 结构,我会讨厌维护用于查找数据的正则表达式。通过构建树的适当解析器来解析 HTML 可能会更幸运。然后选择元素......这将更易于维护。

显然,最好的方法是来自引擎的一些 XML 输出,带有可以解析和验证的固定标记。我认为一个对生成的树进行一些“暗中”探测的 HTML 解析库比正则表达式更易于维护。

这样,你只需要检查<a href="blah" class="cache_link">...变成<a href="blah" class="cache_result">...或其他什么。

底线,使用正则表达式 grepping 特定元素将是严峻的。更好的方法是构建一个类似于 DOM 的页面模型,并在标签中寻找字符数据的“锚点”。

或者向该站点发送一封电子邮件,说明 XML API 的案例……您可能会被录用!

于 2009-08-03T17:10:05.880 回答
3

你没有说你使用的是什么语言。在 Java 领域,您可以使用TagSoup和 XPath 来帮助减少痛苦。此博客中有一个示例(当然,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"
于 2009-08-03T17:14:13.267 回答
2

您还没有提到您正在使用哪种技术堆栈。如果您正在解析 HTML,我会使用解析库:

还有一些 Web 服务可以完全按照您的说法进行 - 商业和免费。他们抓取网站并提供网络服务接口。

提供一些屏幕抓取功能的通用网络服务是 Yahoo Pipes。以前的stackoverflow问题

于 2009-08-03T17:14:43.640 回答
2

它不是万无一失的,但您可能希望查看诸如Beautiful Soup之类的解析器。如果布局发生变化,它不会神奇地找到相同的信息,但它比编写复杂的正则表达式要容易得多。请注意,这是一个 python 模块。

于 2009-08-03T17:15:42.673 回答
1

您是否考虑过使用 html 操作库?Ruby 有一些非常不错的。例如

有了一个好的库,您可以使用 CSS 选择器或 xpath 指定您想要的页面部分。这些将比使用正则表达式更强大。

来自 hpricot wiki 的示例:

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

我相信您可以找到一个在 .NET 或 Python 等中执行类似操作的库。

于 2009-08-03T17:12:51.647 回答
1

不幸的是,“抓取”是最常见的解决方案,正如您所说的试图从网站解析 HTML。您可以检测到页面的结构更改并标记警报以供您修复,因此其末尾的更改不会导致数据错误。在语义网成为现实之前,这几乎是保证大型数据集的唯一方法。

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

希望能有所帮助!

编辑:如果你使用 PHP,我会推荐 SimpleHTMLDOM

于 2009-08-03T17:14:32.020 回答
1

尝试使用谷歌搜索屏幕抓取+您喜欢的语言。我知道 python 的几个选项,你可能会找到你喜欢的语言的等价物:

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

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

于 2009-08-03T18:12:33.557 回答
0

如果您可以使用Tag Soup之类的东西,那将是一个开始的地方。然后,您可以将页面视为 XML API,有点。

它有一个 Java 和 C++ 实现,可能会工作!

于 2009-08-03T17:14:31.520 回答
0

http://www.parselets.com上的 Parsley看起来很漂亮。

它允许您使用 JSON 定义“parslets”,您可以定义在页面上查找的内容,然后它会为您解析出这些数据。

于 2009-09-23T21:16:16.890 回答
0

正如其他人所说,您可以使用构建 DOM 表示并使用 XPath/XQuery 查询它的 HTML 解析器。我在这里发现了一篇非常有趣的文章:Java 理论与实践:使用 XQuery 进行屏幕抓取 - http://www.ibm.com/developerworks/xml/library/j-jtp03225.html

于 2010-10-21T11:05:33.390 回答