以同程旅游为例的爬虫入门

以同程旅游为例的爬虫入门

在海量数据处理课程中,我们需要自行爬取一些旅游网站上的旅游攻略并聚合到我们自己构建的搜索引擎中,我负责的是同城旅游中的游记。使用的爬虫框架是 Scrapy,简单来说,爬虫框架就是一个帮助你访问网页内容然后根据特定规则把需要的信息抽取出来的工具。

爬取静态页面

网页主要分为两种,一是静态页面,整个 HTML 的内容是固定的,获取到的就是所有内容,处理起来也没有太大难度;二是动态生成的页面,初始获取的并不是完整内容,随着用户在页面上的交互会动态地调整内容。Python 和 Scrapy 的安装过程就不赘述了,没有需要特别注意的地方。首先我们通过静态页面来练练手,官网的入门教程就是很好的例子。

回到我们要爬取的同城旅游的游记中来,一篇游记的网页基本上算是一个静态网页(动态加载图片对于网页内容分析没有太大影响),比如这一篇江西游就是一个典型的简单的静态页面,直接使用 Scrapy 自带的命令行进行测试:

  • 首先使用 Scarpy 分析工具爬取这个页面:
    scrapy shell "http://www.ly.com/travels/157861.html"

  • 分析其 HTML 源码中的核心内容,主要有图片和文字,针对这两种内容构造合适的选择器,可以理解为构造特定的规则。这里的规则构建过程可以直接在 Chrome 中使用 XPath 插件进行快速尝试。

  • 这里以 XPath 为例,对于图片,发现其链接都出现在 <img>data-img-src 中(从命名中也能猜到八九不离十)。运行:
    response.xpath('//img/@data-img-src').extract(),得到所有图片链接。

  • 文字同理,发现游记中的文字不多,出现在含有 id 属性的 <p> 的文本中。但是有一些其他的无意义的内容也有相同特征,所以需要细化规则比如限制 id 属性必须含有 txt 字段。运行:
    response.xpath("//p[contains(@id, 'txt')]/text()").extract(),得到游记中的文字。

爬取动态内容

对于动态页面就稍微复杂了,主要是对于目标网页的直接请求所返回的内容并不是所需要的全部内容。这时候的解决思路是使用第三方库模拟用户操作,对动态变化后的网页再分析,以此拼接出所需要的全部内容,比较常见的有 Scrapy + Selenium + Phantomjs 的组合库。但是还有个取巧的方法,不管动态网页如何变化,在变化过程中一定需要再次向后端请求新的数据,如果能直接分析出这个数据接口并加以使用,就完全不需要那么费劲了。

同城旅游的搜索结果页面就是一个典型的动态页面,比如直接分析一个搜索请求:

http://www.ly.com/travels/travel/searchResult?k=北京

其返回的内容中并不含有搜索结果,而且分页也是一个明显的动态加载过程,这确实令人绝望 :]。但是在监控动态加载时的请求我们发现了一个很像数据接口的链接,而且参数也非常的标准:

www.ly.com/travels/travel/getSearchYouJiList?k=北京&pindex=1&psize=1

经过尝试发现 psize 最大只能取 100pindex 的取值范围可以从返回的 pageCount 中得到,只要注意不要爬取得太频繁就不会被封(比如测试的时候短时间多次爬取所有北京的游记)。

分析数据接口返回的 JSON,只需要使用 id 字段就能构建目标游记的完整链接:

http://www.ly.com/travels/{id}.html

至此完成了对同程旅游上指定城市的所有游记的爬取工作了,主要还是针对网页源代码和网络请求的分析工作。爬虫源代码参见 Github