我正在回答一些面试的测验问题,问题是关于我如何进行屏幕抓取。也就是说,假设您没有更好的结构化方法来直接查询信息(例如网络服务),则从网页中挑选内容。
我的解决方案是使用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()
这是一个相当令人讨厌的表达方式,但这就是亚马逊提供 Web 服务 API 的原因。无论如何,这只是一个例子。问题不是关于亚马逊,而是关于屏幕抓取。
面试官不喜欢我的解决方案。他认为它很脆弱,因为 Amazon 对页面设计的更改可能需要重写 XQuery 表达式。调试与所应用的页面中的任何内容都不匹配的 XQuery 表达式是很困难的。
我并不反对他的说法,但我不认为他的解决方案有任何改进:他认为最好使用正则表达式,并搜索运输重量附近的内容和标记。例如,使用 Perl:
$html =~ m{<li>\s*<b>\s*Product Dimensions:\s*</b>\s*(.*?)</li>}s;
我的反驳是,这也容易受到亚马逊更改其 HTML 代码的影响。他们可以用大写字母拼写 HTML 标签(<LI>
),或者添加 CSS 属性或更改<b>
to <span>
或者将标签“产品尺寸:”更改为“尺寸:”或许多其他类型的更改。我的观点是,正则表达式并不能解决他在我的 XQuery 解决方案中指出的弱点。
但此外,正则表达式可能会发现误报,除非您向表达式添加足够的上下文。它还可能无意中匹配注释、属性字符串或 CDATA 部分中的内容。
我的问题是,你们使用什么技术来进行屏幕抓取?您为什么选择该解决方案?有什么令人信服的理由来使用它吗?或者从不使用另一个?除了我上面展示的之外,还有第三种选择吗?
PS:为了论证,假设没有 Web 服务 API 或其他更直接的方式来获取所需的内容。