11-预见变化
2.2.4 预见变化
抓取时经常会指向我们无法控制的服务器页面。这就意味着如果它们的HTML以某种方式发生变化后,就会使XPath表达式失效,我们将不得不回到爬虫当中进行修正。通常情况下,这不会花费很长时间,因为这些变化一般都很小。但是,这仍然是需要避免发生的情况。一些简单的规则可以帮助我们减少表达式失效的可能性。
- 避免使用数组索引(数值)
Chrome经常会给你的表达式中包含大量常数,例如:
//*[@id="myid"]/div/div/div[1]/div[2]/div/div[1]/div[1]/a/img
这种方式非常脆弱,因为如果像广告块这样的东西在层次结构中的某个地方添加了一个额外的 div 的话,这些数字最终将会指向不同的元素。本案例的解决方法是尽可能接近目标的 img 标签,找到一个可以使用的包含 id 或者 class 属性的元素,如:
//div[@class="thumbnail"]/a/img
- 类并没有那么好用
使用 class 属性可以更加容易地精确定位元素,不过这些属性一般是用于通过CSS影响页面外观的,因此可能会由于网站布局的微小变更而产生变化。例如下面的 class :
//div[@class="thumbnail"]/a/img
一段时间后,可能会变成:
//div[@class="preview green"]/a/img
- 有意义的面向数据的类要比具体的或者面向布局的类更好
在前面的例子中,无论是" thumbnail "还是" green "都是我们所依赖类名的坏示例。虽然" thumbnail "比" green "确实更好一些,但是它们都不如" departure-time "。前面两个类名是用于描述布局的,而" departure-time "更加有意义,与 div 标签中的内容相关。因此,在布局发生变化时,后者更可能保持有效。这可能也意味着该站的开发者非常清楚使用有意义并且一致的方式标注他们数据的好处。
- ID通常是最可靠的
通常情况下, id 属性是针对一个目标的最佳选择,因为该属性既有意义又与数据相关。部分原因是JavaScript以及外部链接锚一般选择 id 属性以引用文档中的特定部分。例如,下面的XPath表达式非常健壮。
//*[@id="more_info"]//text()
例外情况是以编程方式生成的包含唯一标记的 ID 。这种情况对于抓取毫无意义。比如:
//[@id="order-F4982322"]
尽管使用了 id ,但上面的表达式仍然是一个非常差的 XPath 表达式。需要记住的是,尽管ID应该是唯一的,但是你仍然会发现很多 HTML 文档并没有满足这一要求。