一、背景目的

互联网的兴起,知识的获取变得越来越便利,然而大量信息有时候会对我们的选择造成干扰,通过其他用户的点击评阅可以作为一个有效的参考,方便人们搜寻到有效信息,本项目基于豆瓣图书TOP250进行数据分析

二、数据获取

通过python爬虫获取豆瓣图书top250的书名、网址链接、评分、点评数、一句话简介评语

# 导入相应的库文件
from lxml import etree
import requests
import csv
import time
# 创建csv
fp = open(\'/Users/cc/Desktop/doubanbook.csv\', \'wt\', newline=\'\', encoding=\'utf-8\')
writer = csv.writer(fp)
writer.writerow((\'name\', \'url\', \'author\', \'publisher\', \'date\', \'price\', \'date\', \'price\', \'rate\', \'comment\'))
# 构造url
urls = [\'https://book.douban.com/top250?start={}\'.format(str(i)) for i in range(0, 250, 25)]
headers = {
    \'User-Agent\': \'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 \'
                  \'(KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36\'
}
for url in urls:
    html = requests.get(url, headers=headers)
    selector = etree.HTML(html.text)
    infos = selector.xpath(\'//tr[@class="item"]\')
    for info in infos:
        name = info.xpath(\'td/div/a/@title\')[0]
        url = info.xpath(\'td/div/a/@href\')[0]
        book_infos = info.xpath(\'td/p/text()\')[0]
        author = book_infos.split(\'/\')[0]
        publisher = book_infos.split(\'/\')[-3]
        date = book_infos.split(\'/\')[-2]
        price = book_infos.split(\'/\')[-1]
        rate = info.xpath(\'td/div/span[2]/text()\')[0]
        comments = info.xpath(\'td/p/span/text()\')
        comment = comments[0] if len(comments) != 0 else "空"
        time.sleep(2)
        writer.writerow((name, url, author, publisher, date, price, date, price, rate, comment))
fp.close()

 三、数据预处理

1. 格式处理:刚爬虫下来的数据直接通过excel打开是乱码形式,通过记事本(另存为ANSI格式),再通过EXCEL(数据,查询新建。从文本)打开可观察相关信息

2. 使用numpy、pandas进行数据清洗处理

# 导入相关API工具
import
pandas as pd import numpy as np import seaborn as sns import matplotlib as mpl from matplotlib import pyplot as plt import warnings %matplotlib inline

# 读入文件
df_books1 = pd.read_csv(\'C:/Users/cc/Desktop/doubanbook.csv\')
print(df_books1.head())
print(df_books1.shape)
# 转化为DataFrame
pd.DataFrame(df_books1)

由表中数据观察可知,出版日期和价格特征重复,故删除重复特征,并对特征重新排序

df_books1 = pd.DataFrame(df_books1,columns=[\'name\',\'author\',\'publisher\',\'date\',\'price\',\'rate\',\'comment\',\'url\',])
df_books1

经分析数据发现缺少点评人数这一关键特征,通过爬虫重新获取点评人数这一特征

# 爬虫获取书名和评论人数
import
requests from lxml import etree import time with open (\'/Users/cc/Desktop/top2501.csv\',\'w\',encoding = \'utf-8\') as f: for a in range(10): url = "https://book.douban.com/top250?start={}".format(a*25) data = requests.get(url).text s = etree.HTML(data) file = s.xpath(\'//*[@id="content"]/div/div[1]/div/table\') for div in file: title = div.xpath(\'./tr/td[2]/div[1]/a/@title\')[0] num = div.xpath(\'./tr/td[2]/div[2]/span[3]/text()\')[0].strip(\'(\').strip().strip(\')\') time.sleep(2) f.write(\'{}, {}\n\'.format(title,num,))
#导入数据
df_books2 = pd.read_csv(\'C:/Users/cc/Desktop/top2501.csv\',names=[\'name\',  \'critics\',])
pd.DataFrame(df_books2)

将两个表格特征合并:

df_books = pd.merge(df_books1,df_books2 ,how=\'left\')
df_books

 去除critics后面的“人评价”

df_books[\'critics\'] = df_books[\'critics\'].str[0:7]   # 评论数不一致,截取长短不同,此方法不可取
df_books[\'critics\'] = df_books[\'critics\'].str.replace("人评价", "") # 通过str.replace替除“人评价”
df_books

由于书本价格相对较低廉,对消费者影响较小且该目录下书籍价格单位较多,故暂且不处理价格数据。

将时间中的年份提取出来单独作为一列

df_books[\'year\'] =df_books.date.str[:5]
df_books

查看元素数据类型:数据类型相同方可进行算术运算

df_books.info()

将数据转化为统一类型

# 将critics元素转化为float64类型
df_books.loc[:,\'critics\'] = df_books.loc[:,\'critics\'].astype(\'float64\') # float64类型方可进行描述性统计 df_books.info()

 四、数据分析与可视化

数据如下:

df_books = df_books[[\'name\',\'author\',\'rate\',\'critics\',\'publisher\',\'year\',\'comment\',\'price\',\'url\']]
df_books 

 通过describe对数据进行描述性统计(总数、均值、标准差、最小值、下四分位、中位数、上四分位、最大值)

df_books.describe()
sns.lmplot(x="rate", y="critics", data=df_books) # 散点图
sns.lmplot(x="rate", y="critics", data=df_books,x_jitter=.08) # x轴方向上抖动

       

 分析:平均评分在8.6,最高评分9.6,最低评分8.0

            最高点评人数440993,最低点评人数19747,平均点评人数62979

            评分可以反映一本书的好坏,而点评人数可以反映一本书的受众程度,从商业角度上来说,点评人数为重要特征。

按作者进行分类:

出书最多的前十名作者:

import matplotlib.pyplot as plt
plt.rcParams[\'font.sans-serif\']=[\'SimHei\'] #用来正常显示中文标签
author_df1 = pd.DataFrame(df_books.groupby(\'author\').name.count().sort_values(ascending=False).head(10)) #取前十
author_df1
author_df1.plot.barh(stacked=True) #横状直方图

            

 评分最高的前十名作者:

author_df2 = pd.DataFrame(df_books.groupby(\'author\').rate.mean().sort_values(ascending=False).head(10))
author_df2
author_df2.plot.barh(stacked=True

 

        

点评书最高的前十名作者

author_df3 = pd.DataFrame(df_books.groupby(\'author\').critics.mean().sort_values(ascending=False).head(10))
author_df3
author_df3.plot.barh(stacked=True)

      

分析:豆瓣图书top250中出书最多的作者是日本作家村上春树、其次为英国作家J.K.罗琳,第三名为王小波

           豆瓣图书top250中评分最高的作者是清朝曹雪芹、其次为日本尾田荣一郎,第三名为美国乔治·R.R.马丁

           豆瓣图书top250中评论数最多的作者是法国圣埃克苏佩里、其次为中国钱钟书,第三名为美国卡勒德·胡塞尼

 书籍评分与点评人数:

name_df2 = pd.DataFrame(df_books.groupby(\'name\').rate.max().sort_values(ascending=False).head(10))
name_df2

       

name_df3 = pd.DataFrame(df_books.groupby(\'name\').critics.mean().sort_values(ascending=False).head(10))
name_df3
name_df3.plot.barh(stacked=True)

        

书籍评分最高和点评人数最多并不一致,其中《活着》这本书在两者top间均有体现,商家在对此书的订购可以稍多一点,而读者也可以将此书列入自己书单。

 出版社出版书籍类型数目:

publisher_df =  df_books.groupby(\'publisher\').rate.agg([\'count\']).sort_values(by=\'count\',ascending=False)[:10]
publisher_df
publisher_df.plot.barh(stacked=True)

        

人民文学出版社:1951年3月成立于北京,系*专业文学出版机构,现为中国出版集团公司成员单位。

上海译文出版社:中国最大的综合性专业翻译出版社,成立于1978年1月1日,系世纪出版集团的成员。

南海出版公司:成立于1988年10月,是出版社会科学、文学艺术(包括外国文学、摄影美术)的具有一定规模的综合性出版社。

出版时间分析:

df_books[\'year\'] = df_books[\'year\'].str.replace("53.0", "1981")   # 异常值处理,替换为正确出版年
data = df_books.groupby(\'year\').name.agg([\'count\']).sort_values(by=\'count\',ascending=False)# 按统计数排序

data = df_books.groupby(\'year\').name.agg([\'count\']).sort_values(by=\'year\',ascending=True) # 按时间排序 data
data.plot.bar(stacked=True)

             

从1972至2018年,出版书籍数目随时间变化而提升,2007年达到高峰有22本,而之后猜测伴随电子书发展,出版量逐渐降低。

基于一句话点评做词云分析:

# 引入相关库包
import warnings warnings.filterwarnings(
"ignore") import jieba #分词包 import numpy #numpy计算包 import codecs #codecs提供的open方法来指定打开的文件的语言编码,它会在读取的时候自动转换为内部unicode import pandas as pd import matplotlib.pyplot as plt %matplotlib inline import matplotlib matplotlib.rcParams[\'figure.figsize\'] = (10.0, 5.0) from wordcloud import WordCloud#词云包

# 导入图书点评数据、分词
df = pd.read_csv("C:/Users/cc/Desktop/comment.csv", encoding=\'utf-8\') #词云文件存储位置,路径不允许中文文件夹存在
df = df.dropna()
content = df.comment.values.tolist() # 做词云的特征量 ,此处例如comment
#jieba.load_userdict(u"data/user_dic.txt")
segment=[]
for line in content:
    try:
        segs=jieba.lcut(line)
        for seg in segs:
            if len(seg)>1 and seg!=\'\r\n\':
                segment.append(seg)
    except:
        print (line)
        continue

# 去停用词 ‘空’
words_df=pd.DataFrame({\'segment\':segment})
#words_df.head()
# stopwords文件采用记事本,保存为utf-8格式
stopwords=pd.read_csv("C:/Users/cc/Desktop/stopwords.txt",index_col=False,quoting=3,sep="\t",names=[\'空\'], encoding=\'utf-8\')#quoting=3全不引用
stopwords.head()
words_df=words_df[~words_df.segment.isin(stopwords.空)]

# 统计词频
words_stat=words_df.groupby(by=[\'segment\'])[\'segment\'].agg({"计数":numpy.size})
words_stat=words_stat.reset_index().sort_values(by=["计数"],ascending=False)
words_stat.head(10)

# 做词云,系统自带图片
wordcloud=WordCloud(font_path="data/simhei.ttf",background_color="white",max_font_size=80)
word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values}
wordcloud=wordcloud.fit_words(word_frequence)
plt.imshow(wordcloud)

                

 

# 自定义背景图做词云
from
scipy.misc import imread matplotlib.rcParams[\'figure.figsize\'] = (15.0, 15.0) from wordcloud import WordCloud,ImageColorGenerator bimg=imread(\'C:/Users/cc/Desktop/entertainment.jpeg\') wordcloud=WordCloud(background_color="white",mask=bimg,font_path=\'data/simhei.ttf\',max_font_size=200) word_frequence = {x[0]:x[1] for x in words_stat.head(1000).values} wordcloud=wordcloud.fit_words(word_frequence) bimgColors=ImageColorGenerator(bimg) plt.axis("off") plt.imshow(wordcloud.recolor(color_func=bimgColors))

      

 通过词云可以看出,字体越大的关键词,说明其在所有关键词中出现的次数越多。出现次数最多的10个词语,分别为“中国”、“爱情”、“一个”、“就是”、“世界”、“生活”、“一种”、“史诗”、“时代”、“不是”。