为了账号安全,请及时绑定邮箱和手机立即绑定

从慕课网实战课程评论中提取课程标签 (scrapy + pandas + matplotlib)

标签:
Python

1.爬取课程评价

编写scrapy爬虫,爬取慕课网所有实战课程评价, Spider代码如下:

# -*- coding: utf-8 -*-
import scrapy
from scrapy import Request

class CommentSpider(scrapy.Spider):
    name = 'comment'
    allowed_domains = ['coding.imooc.com']
    start_urls = ['http://coding.imooc.com/']

    def parse(self, response):
        # 解析实战课程列表页
        for sel in response.css('div.shizhan-course-wrap > a'):
            course_id = sel.xpath('./@href').re_first('(\d+).html')
            url = response.urljoin(sel.xpath('./@href').extract_first())
            name = sel.css('p.shizan-name::attr(title)').extract_first()

            base_item = {
                'id': course_id,
                '课程名': name,
            }

            url = 'class/evaluation'.join(url.split('class'))
            yield Request(url, callback=self.parse_comment, meta={'base_item': base_item})

        next_url = response.xpath('//div[@class="page"]/a[contains(., "下一页")]/@href').extract_first()

        if next_url:
            yield Request(response.urljoin(next_url), callback=self.parse)

    def parse_comment(self, response):
        # 解析实战评价页面
        base_item = response.meta['base_item']

        if not response.meta.get('recommend', False):
            response.meta['recommend'] = True
            for sel in response.css('div.evaluation-recommend li p.content::attr(title)'):
                item = base_item.copy()
                item['评论'] = sel.extract() 
                yield item

        for sel in response.css('ul.cmt-list p.cmt-txt::text'):
            item = base_item.copy()
            item['评论'] = sel.extract() 
            yield item

        next_url = response.xpath('//div[@class="page"]/a[contains(., "下一页")]/@href').extract_first()
        if next_url:
            yield Request(response.urljoin(next_url), callback=self.parse_comment, meta=response.meta)

运行爬虫,将爬取结果保存至json文件:

$ scrapy crawl comment -o comment.json

爬取完成后,在ipython中查看json文件按中的爬取结果:

>>> import json
>>> comment_list = json.load(open('comment.json')
>>> comment_list
[{'id': '125',
  '评论': '学的差不多了,课程先讲技术框架以及小的案例,Thymeleaf模板引擎,发现这个相比freemaker,与springboot有非常好的兼容。Elasticsearch全文搜索框架是我最想看的太火了最近,Spring Data JPA数据操作相关,Spring Security权限管理,总之干货很多,用这些框架实现的功能也比较完整。我比较满意的是代码都是一步步敲的,包括环境搭建都有,对新人很友好。',
  '课程名': 'Spring Boot技术栈博客企业级前后端'},
 {'id': '125',
  '评论': '课程的结构很好,先介绍要使用的技术框架,springboot、Thymeleaf、Elasticsearch、SpringDataJPA,然后通过Demo入门,完成从前端到后台的一站式开发,是不错的课程',
  '课程名': 'Spring Boot技术栈博客企业级前后端'},
 {'id': '125',
  '评论': '1. 通过短短十多个小时的时间,把springboot、Thymeleaf、Elasticsearch、SpringDataJPA等过了一遍,并讲明白了这些东西是用来干嘛的、怎么用的。对于新手,节省了不少时间;\n2. 通过对这些技术的整合,从0到1开发出一个博客系统,使明白了该如何分析需求、设计api、实现业务逻辑等;\n3. 一点小缺憾是在开发整个系统的时候,没有涉及缓存技术,而缓存技术在实战开发上是肯定会用上的;\n4. 市面并不缺把各种技术揉碎了讲的书籍,比如springboot是如何实现自动注入的,但把各个技术整合,从0到1出作品,讲实战的比较少。\n老魏老师总体讲的非常不错,好评。',
  '课程名': 'Spring Boot技术栈博客企业级前后端'},
 {'id': '125',
  '评论': '老师讲的很细致,内容很丰富,最近项目做的养老服务平台,用到了全文搜索,学习之后对公司框架有了新的认识。老师在群里也为各个学生答疑解惑,真的感谢。',
  '课程名': 'Spring Boot技术栈博客企业级前后端'},
 {'id': '125',
  '评论': '老师课程安排的不错,讲解很详细,可以搭建一个自己的博客系统出来',
  '课程名': 'Spring Boot技术栈博客企业级前后端'},
 {'id': '125',
  '评论': '课程很好,内容也很多,很丰富学习到不少内容的入门的内容!',
  '课程名': 'Spring Boot技术栈博客企业级前后端'},
 {'id': '125',
  '评论': '老师讲的很不错,涉及到的知识点也比较新,我才学了前面6章,但是在自己动手写的过程中还是有很多坑要踩,老师答疑很及时,也很有耐心,我都问的不好意思了,最后还是支持老师,希望继续更新,也希望自己能脱离视频完全写一遍!!',
  '课程名': 'Spring Boot技术栈博客企业级前后端'},
 {'id': '125',
  '评论': '这个课程知识点很多,老师讲解的很深入,其中很多之前也接触过,也使用过,但听了老师的讲解还是有很多收获,给老师点赞!',
  '课程名': 'Spring Boot技术栈博客企业级前后端'},
 {'id': '125',
  '评论': '老师讲的课通俗易懂,技术面覆盖广,真心不错啊。。。。',
  '课程名': 'Spring Boot技术栈博客企业级前后端'},
 {'id': '125',
  '评论': '课程的结构很好,先介绍要使用的技术框架,然后通过Demo快速入门,完成从前端到后台的一站式开发,是不错的课程',
  '课程名': 'Spring Boot技术栈博客企业级前后端'},

... 省略中间输出...

{'id': '75',
  '评论': '本人是.Net程序员,近期刚想自学微信小程序,刚好发现imooc推出了微信小程序的实战课程,计划性的在周末购买了本课程,一气看完。首先感谢七月老师的精心讲解,通俗易懂。不解渴的地方是课程没有完全剪辑完,但好在已经达到入门水平,自己可以动手配合API做应用了。最后本人推荐想从事微信小程序开发的朋友学习本门课程,原因:1、万事开头难,入门一样技能,花费的时间要比入门后深入学习花费的时间要多得多,由其像微信小程序才公测,资料少,最主要是坑多,本课程学习比百度论坛学习系统的多,从时间上至少要节约N倍时间。2、价格是大众价格,性价比是非常高的。3、从时效性讲,现在学习跟以后学习的价值是不一样的,你懂得。',
  '课程名': '微信小程序入门与实战  常用组件 API 开发技巧 项目实战'},
 {'id': '75',
  '评论': '老师很用心,讲得很详细,别的实战课程我的看到老师的车尾灯都算不错了,这个实战我一直紧跟在老师后头,稳如狗',
  '课程名': '微信小程序入门与实战  常用组件 API 开发技巧 项目实战'},
 {'id': '75',
  '评论': '小程序适合我这样的前端空白者学习,第一次学习前端技术,老师讲解很细致,不仅有知识,还有方法。',
  '课程名': '微信小程序入门与实战  常用组件 API 开发技巧 项目实战'},
 {'id': '75',
  '评论': '课程讲解的很细致,很适合新手入门,非常感谢。',
  '课程名': '微信小程序入门与实战  常用组件 API 开发技巧 项目实战'},
 {'id': '75',
  '评论': '老师讲的很清楚,对于我这个0基础的人也容易懂。',
  '课程名': '微信小程序入门与实战  常用组件 API 开发技巧 项目实战'},
 {'id': '75',
  '评论': '如果有可能,我就评个10+1分!',
  '课程名': '微信小程序入门与实战  常用组件 API 开发技巧 项目实战'},
 {'id': '75', '评论': '老师很有耐心', '课程名': '微信小程序入门与实战  常用组件 API 开发技巧 项目实战'},
 {'id': '75', '评论': '讲得很透彻,非常感谢', '课程名': '微信小程序入门与实战  常用组件 API 开发技巧 项目实战'},
 {'id': '75', '评论': '近期开放大概是什么时候开放', '课程名': '微信小程序入门与实战  常用组件 API 开发技巧 项目实战'},
 {'id': '75', '评论': '老师讲的好不错,值得信赖', '课程名': '微信小程序入门与实战  常用组件 API 开发技巧 项目实战'}]

2.提取课程标签

  • 利用pandas对评论数据进行处理
  • 利用jieba.analyse提取对每个课程所有评论的标签
  • 利用matplotlib和wordcloud对课程标签进行展示
import pandas as pd
from matplotlib import pyplot as plt
from wordcloud import WordCloud

import jieba.analyse

# 加载爬取到的评论导一个DataFrame。
df = pd.read_json('comment.json')

# 根据课程id分组,拼接所有评论后调用,extract_tags提取标签。
grouped = df.groupby('id')
f = lambda s: dict(jieba.analyse.extract_tags(s.str.cat(), 10, withWeight=True, allowPOS=('a', 'an')))
res = grouped['评论'].apply(f)

# 将所得结果依然按课程id分组,利用matplotlib和wordcloud生成图片。
res_grouped = res.groupby('id')
n = len(res_grouped)
figure, axes = plt.subplots(n, 2, figsize=(6 * 2, 4 * n))
figure.subplots_adjust(0.05, 0.01, 0.95, 0.99, wspace=0, hspace=0.4)

font_path = '/usr/share/fonts/truetype/wqy/wqy-microhei.ttc'
wordcloud = WordCloud(font_path)

for i, (gid, s) in enumerate(res_grouped):
    ax_left, ax_right = axes[i]

    course_name = df.loc[df['id'] == gid, '课程名'].unique()[-1]
    figure.set_label(course_name)

    ax_left.set_title(course_name)

    s.reset_index(level=0, drop=True, inplace=True)
    s.plot.bar(ax=ax_left)

    for label in ax_left.xaxis.get_ticklabels():
        label.set_rotation(0)
        label.set_fontsize(10)

    font_path = '/usr/share/fonts/truetype/wqy/wqy-microhei.ttc'
    img = wordcloud.generate(' '.join(s.index))

    ax_right.set_title('课程标签')
    ax_right.axis("off")
    ax_right.imshow(img, aspect='auto', interpolation='bilinear')

figure.savefig('res.png')

运行以上脚本后, 打开结果图片res.png, 显示如下:
图片描述

点击查看更多内容
30人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消