这篇文章提到的源码可以在我的github^0上面找到, 项目名称是whosdatedwho_crawler.
这篇东西是什么鬼
以下是废话.
所有东西的存在都是有原因的. 就算你是在发呆, 也有“我什么事情都不想干”这个原因. 而之所以会有这篇文章, 全都是因为我太懒了.
学校有一门奇怪的课程叫思政课社会实践, 说白了就是社会调查. 很多人都可以周期性的感知到这门课的存在, 因为每隔一段时间在你的qq聊天列表的某个群里就会蹦出来一个“社会调查问卷, 帮忙填一下, 谢谢!!!”, 而且后面一定会跟着一个红包. 但是我是懒的, 而且我也很穷. 不可能会去设计这么一份问卷然后一个一个群用红包去拜托别人. 但是作业还是要做的. 且我的良心不允许我作假. 于是, 我就希望能找到这样一个调查课题, 它所需的信息可以很方便的获取到. 而这个时候, 刚好某老实巴交的男演员被人绿了, 而且他一被绿全中国都知道了, 这让我得到了一个结论:
名人的婚恋八卦是互联网上最不缺乏的资源.
于是, 我想起了一个神奇的网站www.whosdatedwho.com^1, 这上面收录了大量(大概翻了一下, 发现深不见底, 一直到19世纪60年代的记录都有)好莱坞明星(其实也不限好莱坞, 比如秦凯跟何姿的engagement上面也有记录)的恋爱, 分手, 订婚, 结婚和生小孩的信息, 而且过半数的条目里面都会有关于这对couple的各种信息对比, 包括括国籍, 身高, 职业, 年龄等, 可以说是丰富的八卦来源. 于是, 我便开始着手编写爬虫, 把上面的数据爬下来. 有了这玩意, 就可以研究诸如”身高差对好莱坞明星恋情长度的关系”, “年龄差对好莱坞明星恋情长度的关系”之类的问题了.
这篇文章记录了寻找whosdatedwho.com的记录查询接口, 分析网页结构, 数据表设计以及构建爬虫的过程.
废话到此结束.
寻找whosdatedwho.com的记录查询接口
我们爬一个网站的时候, 并不是乱爬的, 理想的情况是:这个网站有一个可翻页的列表, 翻页可以通过改变url中的page之类的参数来控制, 每一页有固定数目的通向详情页面的链接. 这样的话, 我们的爬虫就只需要一页一页地把详情页面的链接抠出来, 然后再跟着这些链接进入到详情页面去爬取需要的信息.
在whosdatedwho的首页中间可以看到一个大大的”Latest Events”, 旁边跟着一个小小的”See More”. 直觉告诉我们这个see more里面会有我们想要得东西. 进去之后发现到了http://www.whosdatedwho.com/timeline, 而这里的确有一个列表, 但是是下拉加载更多的那种. 这个下拉加载更多的玩意儿对于爬虫来说并没有什么用处, 除非我在爬虫里面加上js解释器, 然后再向页面发送模拟的下拉信息, 不过这样太洒了, 我不打算这样做. 我们知道, 凡是这种东西肯定是用ajax或者websocket做出来的, 所以我们只要分析一下源码找到相应的数据获取接口就行了. 逛了了一圈发现这个无限延长的列表在`#ff-7c01f37bfcc5c8dc3e81f5359fd5b212 > div.ff > div.ff-latest-list, 于是我在这个节点上加了一个on subtree modifications断点, 然后下拉, 发现代码停在这样一个地方:
|
|
调用栈如下:
|
|
看了以下变量a的值, 发现这是一个img节点, 图像内容是一个圈圈, 看来是下拉的时候出现的那个表示“加载中”的圈圈. 这不是我们想要的, 于是我们让它继续执行. 很快, 代码又停在了同样的地方, 但是此时调用栈已经变成了这样:
|
|
ajax四个大字映入眼帘. 进到到infscr_ajax_callback, 发现代码停在这个地方:
|
|
看来就是这里没跑了. 查看desturl的值, 发现是?page=2&_block=page.latestEvents
. 也就是说, 这个page=2就是翻页的关键. 于是我把2改成3试了一下, 发现可以正常加载新的内容. (我也尝试过把&_block=page.latestEvents
去掉, 不过发现去掉之后不能正常工作.)
于是, 们得到了想要的东西:
第$k$页记录的url为: http://www.whosdatedwho.com/timeline?page=$k$&_block=page.latestEvents
设计数据表
在确认了数据能够抓取之后, 在确定下一步抓取计划之前, 需要确定你要抓取些什么, 以及在何处抓取. 通过观察, 可以发现列表页面有的信息为:
- 事件类型, 包括: Hookup, Breakup, Engagement, Marriage, Child, Divorce
- 日期
- 双方姓名
- 进入到详情页面的链接
随便进入到一个详情页面, 发现里面能够提供的信息有:
- 姓名
- 年龄
- 身高
- 星座
- 职业
- 发色
- 瞳色
- 国籍
- 匹配度
- 是否事实
- 持续时间
数据用传统的关系型数据库存储, 可以设计如下数据表:
whosdatedwho
+--------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+---------+-------+
| name1 | varchar(64) | YES | | NULL | |
| name2 | varchar(64) | YES | | NULL | |
| gender1 | varchar(8) | YES | | NULL | |
| gender2 | varchar(8) | YES | | NULL | |
| height1 | smallint(6) | YES | | NULL | |
| height2 | smallint(6) | YES | | NULL | |
| age1 | tinyint(4) | YES | | NULL | |
| age2 | tinyint(4) | YES | | NULL | |
| zodiac1 | varchar(16) | YES | | NULL | |
| zodiac2 | varchar(16) | YES | | NULL | |
| occupation1 | varchar(64) | YES | | NULL | |
| occupation2 | varchar(64) | YES | | NULL | |
| haircolor1 | varchar(32) | YES | | NULL | |
| haircolor2 | varchar(32) | YES | | NULL | |
| eyecolor1 | varchar(32) | YES | | NULL | |
| eyecolor2 | varchar(32) | YES | | NULL | |
| nationality1 | varchar(64) | YES | | NULL | |
| nationality2 | varchar(64) | YES | | NULL | |
| event | varchar(64) | YES | | NULL | |
| date | date | YES | | NULL | |
| duration | tinyint(4) | YES | | NULL | |
| score | tinyint(4) | YES | | NULL | |
+--------------+-------------+------+-----+---------+-------+
相应的SQL语句为:
|
|
构建抓取xpath
我们采用xpath来定位信息承载节点, 这个东西纯粹是个体力活. 以详情页面中的couple comparison部分为例, 在#ff-couple-comparison
中, 可以看到name相关的部分是这样的:
|
|
其结构特点为: 由一个担任标题作用的#row collapse引导出接下来的几个包含信息的#row collapse, 信息藏在一对h5标签之后. 虽然每个页面有的信息不尽相同, 但是我们可以通过遍历这些#row collapse来判断出现了哪些信息. 比如上面出现了Name, 就可以知道下一个#row collapse肯定包含了名字信息, 所以我就可以在下一个#row collapse中提取相关信息, 然后再从下下个#row collapse开始继续往下遍历, 直至遍历完这一系列#row collapse.
需要注意的一点是, couple comparison中男女出现的位置是是不一定的, 有时男的在左, 有时女的在左, 有时男的既在左又在右, 所以需要进行判断, 判断的方法是读取height一栏中图片的alt属性(Male or Female).
具体的xpath可以参见源码.
构建爬虫
其实到了这一步基本上已经水到渠成了. 爬虫使用python+scrapy实现. 需要注意的一点是, 并不是每一个item都包含了所有的字段, 所以在向数据库插入数据时不能简单地用一个字符串模板来构建sql语句, 需要根据有的字段动态构建, 代码如下;
|
|
还有就是要注意转义, 别自己把自己给注入了.
实际爬取
接下来只需要crapy crawl whosdatedwho
就可以去找个阴凉的地方喝茶慢慢等了. 爬虫的速度还是很不错的, 睡了个午觉, 起来来玩了会儿手机, 就有了33330条记录, 从1995到2016, 对于这种过家家的作业而言, 这3万多条数据足够了.