之前做了一些数据抓取的工作,期间也踩了一些坑,所以有了这篇文章。
动态网页数据源获取
需要抓取的页面是使用 React JavaScript 框架开发的,所有的页面都是客户端渲染而成,这也就导致我只能看到一个个的 data-id ,没有办法直接获取数据。这就涉及到一个我之前没有接触过的领域——动态网页爬虫。 一番 Google 之后,我了解到动态网页爬虫大致上可以通过以下两种方法实现:
- 分析网页代码结构和请求,找到数据源的请求链接
- 调用Webkit渲染之后再进行抓取
第二种方法相当于在命令行中跑一个浏览器,一个页面一个页面的打开,效率可想而知。再加上待抓取页面的 DOM 结构本来就比较复杂,没有添加相应的 class 和 id,导致即使渲染出来了想要抓到自己需要的数据也非常费劲。
于是只能采用第一种方案:分析了一下网页的代码之后发现所有的数据都是通过一个接口返回的。使用 Chrome 审查工具中的
Network
工具可以获取到所有的网络请求,在里面搜索
JSON
,找到了一个 JSON 的请求。点开一看正是我们需要的数据,解决了动态网页数据源的问题。
分类不统一
这个坑主要出在自己对目标网页的数据特性挖掘的不够。一开始以为目标网页是按照一个特定的分类来区分的,但是后来发现这个标准并不统一,最后抓取到的数据不在一个维度上。正当自己准备开工写很多特判的时候发现,如果从另外一个维度来索取数据的话,所有的数据都是统一的。 在这个案例中,就是将人为的分类切换成通过价格来获取数据,通过选择所有价格,就能获取到所有的数据,不需要再对不同维度的分类进行特判。 这个与其说是技术问题,更多的是一个经验的问题。
页面内部JS执行
这个坑就比较有趣了。 目标网页除了通过一个特定的接口获取数据之外,还会在页面内部通过 JavaScript 来直接传递数据。背后的技术考量不得而知,但是摆在我面前的问题就是我要如何获取这些 JavaScript 代码中的数据。 思考了一下之后想到了两种方案:
- 自行匹配需要的字符串
- 通过 phatomjs 等工具执行页面内部的 js 代码,并输出需要的数据变量
自行匹配的问题在于,我需要匹配的字符串的格式不一,很难直接匹配出我需要的数据。而通过 phatomjs 执行,就能比较好的解决这个问题。
一个比较脏的解决方案是这样的:
-
下载整个HTML页面到
test.html -
通过 bs4 获取到所有的
<script>标签内部的内容 -
将我们需要的那个标签输出到一个
data.js文件中 -
之后把将数据构造成 json 的 js 代码写入
data.js文件 - 通过 phatomjs 来执行代码
-
将输出通过
json.loads载入并 append 到我们的数据数组中
这样,我们就获得了页面内部js代码中数据的json形式。
phatomjs 中执行的代码最后,千万要记得加上
phatom.exit(),否则不会自行退出。
phatomjs报错
https://cli.xuanwo.io/Tools/phatomjs.html#qxcbconnection-could-not-connect-to-display
当代码放到服务器上运行时候,出现了这样的报错:
QXcbConnection: Could not connect to display
这是因为源中的phatomjs默认运行在图形界面下,只需要在运行前执行:
export QT_QPA_PLATFORM=offscreen
即可。
线程调度
这个坑就比较隐蔽了,重复调试了很久。