豆瓣书籍数据爬取与分析
Posted 大师兄的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了豆瓣书籍数据爬取与分析相关的知识,希望对你有一定的参考价值。
前言
17年底,买了清华大学出版社出版的《Hadoop权威指南》(第四版)学习,没想到这本书质量之差,超越我的想象,然后上网一看,也是骂声一片。从那个时候其就对出版社综合实力很感兴趣,想通过具体数据分析各个出版社的出版质量,另外借此也可以熟悉大数据生态和相关操作。
豆瓣上的书籍数据刚好可以满足需求,所以有了思路:
1. 用python编写爬虫,爬取豆瓣上的书籍信息,并持久化到mysql数据库;
2. 使用sqoop将mysql里的数据导入hive;
3. 通过hive进行离线分析。
一、爬虫部分
这部分的代码已经传到个人的github:https://github.com/harrymore/DoubanBookSpider
1. 爬虫思路及架构
通过观察豆瓣网书籍的具体页面,我们可以发现,具体书籍网址的组成形式为:
https://book.douban.com/subject/bookid/,
其中bookid为具体的数字。第一种思路是设定一个比较大的数字,然后从1到这个数字的范围之内去遍历所有数字对应的网址,但是我们可以发现,这些书的id往往非常大,基本都是百万级别的数字,一个个去撞库非常不现实。
其实每本书都有很多标签,每个标签都汇集了同一类的所有书,要是可以获取到所有标签,然后根据这些标签一个个去遍历就可以获得豆瓣上所有的书了,当然不同标签之间肯定有重复的书,所以还要考虑去重的问题。
所以,这个爬虫的思路主要是:
1) 爬取总标签页(https://book.douban.com/tag/?view=cloud)获取所有标签,并持久化;
2) 通过上一步获取的标签,组成标签页的网址,进入标签页获得本页的所有书籍链接,通过书籍链接获取需要信息;
3) 对书籍信息进行标准化,持久化处理;
4) 爬完本标签,切到下一个标签,继续爬,重复2,3步;
5) 应对网站反爬虫机制;
6) 错误日志和程序崩溃处理。
编程语言选择python,持久化工具选择mysql数据库。
2. 数据库设计
1) 标签信息
表名为tag_info,用来保存从豆瓣爬下来的标签名字,另外,增加多两个字段用来表示进度,一个是当前页数,另一个是完成状态。
2) 书籍信息:
表名为book_info,保存了每本书的基本信息,包括书名、作者、出版社、评分、评分人数等。为了去重,唯一id采用了豆瓣网中书籍的id。
3. 爬虫框架及流程分析
在这个爬虫中使用的模块有 requests,BeautifulSoup,re,logging和MySQLdb,主要流程如下图所示。
1) 用requests模块向豆瓣网发起GET请求,获得网页返回的信息;
2) 把上一步返回的信息用BeautifulSoup模块进行分析,如果还需要进一步匹配过滤,传给re模块进一步加工,否则直接传给MySQLdb模块;
3) re模块对BeautifulSoup传过来的信息进行匹配处理,最后传给MySQLdb;
4) 用MySQLdb连接mysql数据库,将获得的书籍信息持久化到mysql中;
5) 用logging模块负责系统日志的输出和维护。
4. 应对豆瓣的反爬虫
实际上这次爬取数据,比计划多花了一倍时间,大部分时间在于应对豆瓣的反爬虫机制。
刚开始requests去请求数据的时候,准备了若干个header,然后每次请求都换一个。没过多久就开始返回403了,于是减低了爬取的频率,还是继续403。
查了半天资料,首次请求保存cookie,以后每次都修改cookiebid去请求,过一段时间还是被豆瓣检测出来了,有的页面直接返回空的或者定向到别的页面。
最后想到了代理,写了一个动态获取免费代理并验证的函数,不过免费的ip代理不仅慢而且不稳定,又不想买收费的代理服务。
后面查到了ADSL拨号服务器代理的相关文章,发现自己正是用ADSL上网,于是折腾了一番,写了一个断开路由器连接的函数,每当爬虫被豆瓣封杀的时候,就断开路由器连接重新获取ip,由此解决了爬虫正常运行的问题。当然,我这次爬取的数据量比较少,所以用这种方式还是能解决问题,如果是需要在短时间获取大量数据的,还是需要用代理的方式。
花了几天时间,最后终于完成了所有标签的爬取工作,爬到的数据去重后有6万条左右。因为各个标签之间肯定有重叠的部分,所以符合原来的预期。
二、使用sqoop将数据从mysql导入hive
1. 导入hive:
sqoop import --connect jdbc:mysql://localhost:3306/test --username root -P --split-by id --table book_info --target-dir /tmp/douban/book_info --hive-import --create-hive-table --hive-table douban.book_info --direct
2. 查看hive管理表结构
desc formatted book_info;
col_name data_type comment # col_name data_type comment id int book_name string author string publisher string translator string publish_date string page_num int isbn string score double rating_num int …(后面省略)
三、通过hive cli分析数据
1. 计算所有书籍的平均分
HiveQL语句:
SELECT AVG(score) AS avg_score FROM book_info WHERE score > 0 AND rating_num > 100;
为了准确,过滤掉没有评分和评分人数不足的,结果:
OK
avg_score
8.057803307115979
平均分在8分左右,估计一般用户都是看完一本觉得不错的书才上豆瓣进行评分。
2. 计算清华大学出版社书籍的平均分
HiveQL语句:
SELECT AVG(score) AS avg_score FROM book_info WHERE publisher =\'清华大学出版社\' AND score > 0 AND rating_num > 100;
结果:
OK
avg_score
8.167039106145252
结果显示清华大学出版社出版的平均分比总体的稍高,但是也没有很突出。
3. 计算平均分排名前十的出版社
HiveQL语句:
SELECT publisher, AVG(score) as avg_score, COUNT(id) AS book_num FROM book_info WHERE score > 0 AND rating_num > 100 GROUP BY publisher HAVING COUNT(id) > 10 ORDER BY avg_score DESC LIMIT 10;
结果:
publisher avg_score book_num 茜新社 9.157894736842104 19 山西古籍出版社 9.027272727272727 11 太田出版 8.933333333333334 15 浙江人民美术出版社 8.930769230769231 13 東立出版社有限公司 8.910526315789474 19 少年儿童出版社 8.898484848484848 66 上海辞书出版社 8.887500000000001 16 上海科学技术出版社 8.86875 16 白泉社 8.857692307692309 26 岳麓书社 8.845833333333331 24
可以看出排名前十的出版社平均分都在8.8以上,最高的平均分达9.16分。
4. 计算清华大学出版社的排名
HiveQL语句:
FROM ( SELECT publisher, count(id) as book_num, AVG(score) as avg_score, row_number() over(ORDER BY avg_score DESC) as rank_num FROM book_info WHERE score > 0 AND rating_num > 100 GROUP BY publisher HAVING count(id) > 10 LIMIT 200) t1 SELECT t1.* WHERE t1.publisher = \'清华大学出版社\';
结果:
t1.publisher t1.book_num t1.avg_score t1.rank_num
清华大学出版社 179 8.167039106145252 146
数据显示清华大学出版社的排名100名之内都排不进,而且如果把每个出版社出版书籍数量放宽一点来处理的话,结果会更难看一点。
四、小结
实际上只要找到合适的数据源,就能够通过这些数据挖掘出自己需要的东西。从数据采集到最后产出分析结果,整个过程相对来说还比较粗糙,sqoop和hive部分由于数据量不大,只是作为学习目的来检索,暂时未涉及到分区和分桶的操作,因为数据量小,查询也没作并行优化,等后面有时间再进行深入。
(完)
以上是关于豆瓣书籍数据爬取与分析的主要内容,如果未能解决你的问题,请参考以下文章