跳转至

Python-2023-13 关键词提取与可视化

内容梗概

这节课完成爬虫大作业的剩余两部分:在上节课爬到的豆瓣电影 title 和 url 基础上,逐个访问电影详情页、用 BeautifulSoup 提取剧情简介并存为 txt 文件;然后用 jieba 的 TF-IDF 算法提取所有简介的关键词并汇总排序;最后用 wordcloud 画词云做可视化。课上还穿插了两个重要思想:一是这个"抓取—分析—可视化"三段式框架可以任意替换模块,扩展后就是舆情系统的基本逻辑;二是模块化设计意识——每个模块的输出应该持久化存储到本地。结尾明确了作业的基本要求和进阶要求。

知识点详解

作业框架回顾与扩展思路(约 00:00–02:40)

  • 作业三部分:① 抓豆瓣电影的剧情介绍;② 用 TF-IDF(最基本的算法)对简介做关键词提取;③ 把关键词画成**词云**可视化。老师会提供实验报告供参考。
  • 三个模块可任意替换:抓豆瓣可以换成抓微博(GitHub 上有现成代码);关键词提取可以换成**情感计算**(用机器学习/深度学习模型判断内容的情感倾向,基础的三维度、好一点的五维度,都有现成算法);词云可以换成其他图表。
  • 把框架复杂化就是一个小型系统:分布式爬虫、更复杂的情感计算、分主题的主题提取、随时间变化的倾向分析,配上河流图、散点图等更丰富的可视化——市面上大多数舆情系统的基本逻辑就是这样。
  • 进阶例子:分析微博正文与评论的情感倾向是否冲突——统计显示假新闻的正文情感倾向往往与评论对立,可作为虚假新闻检测的一个维度,这已经是研究生科研课题的方向。本课只讲最基础的框架。

Jupyter Notebook 启动与环境变量问题(约 02:40–04:20)

  • 启动方式:建好分支文件夹(如 0x03),在终端里进入该目录运行 jupyter notebook。
  • 常见报错:运行后一堆红字提示找不到 jupyter——没设置环境变量,读不到 Anaconda 的二进制文件。两种解决方式:① 手动添加环境变量(回顾前面章节);② 直接用 Anaconda 自带的命令行(环境变量已配好),cd 到目标目录再运行。
  • 老师强调学习态度:视频只是参考,遇到和视频对不上的地方不要停止思考,要自己想办法解决。

抓取剧情简介(约 04:20–33:00)

  • 上节课回顾:通过豆瓣数据接口拿到 JSON(注意把接口里的 offset 改成 0 才能看到第一条),遍历后把每部电影的 title 和 url 存入 movie_info,汇总到 result 列表;但还没有简介信息。
  • 思路:对每部电影再用 requests.get 访问它的详情页 url,拿到 response(变量名用 r)后用 r.text 取页面文本(即 HTML 源码),交给 BeautifulSoup 解析:
  • soup = BeautifulSoup(r.text, "html.parser")——把 HTML 传给 BeautifulSoup,用自带的 html.parser 解析引擎;
  • soup.select("CSS选择器") 定位元素——右键"检查"找到剧情简介所在元素 id 为 link-report-intra。
  • select 的返回值是列表(约 15:38):列表包含 CSS 选择器选中的所有元素。因为 HTML 中 id 必须唯一,所以按 id 选择只会返回一个元素,取列表的 0 号元素即可(div = soup.select(...)[0])。
  • get_text()(约 17:21):提取元素内的纯文本、扔掉所有 HTML 标签,得到干净的简介文字。查文档是必备技能,老师鼓励大家自己看 BeautifulSoup 文档。
  • 更精确的定位(约 19:49):简介区有两个 span——short(默认显示的短简介)和 all hidden(点"展开全部"后的完整简介),直接 get_text 会把两份都拿到。用开发者工具的**复制 Selector** 功能拿到 all hidden 的选择器,只取完整版。
  • 报错与异常处理(约 21:51–27:30):正式爬取时报 list index out of range——select 没找到 span.all hidden 元素,列表为空却取 0 号元素。原因:有些电影简介本身很短,没有"展开全部",页面上只有 short 甚至只有一个普通 span。
  • 排错方法:先加日志输出("正在处理电影 {title},URL: {url}"),找到报错的那部电影,打开页面检查它的真实结构,再写处理逻辑。
  • 分流逻辑:先获取 all hidden 元素列表 span_list,如果列表为空(长度为 0)就退而取父元素,统一存入同一个变量;父元素每个页面都有,保证列表一定非空,再取 0 号元素 e.get_text() 就不会出错。
  • 持久化存储(约 20:43):把简介存入以电影名命名的 txt 文件:with open(title + ".txt", "w", encoding="utf-8") as f: f.write(intro)。
  • Jupyter 操作提醒:想只看一条结果就在循环里加 break(注意两层循环要两个 break),不要点"终止内核"——那会把后台 kernel 关掉,后续操作全废;中断用 Ctrl+C 或 Kernel Interrupt,必要时 Restart Kernel。
  • 整理:爬完手动把 txt 归入 movies 文件夹;更好的做法是在写文件时就 open("movies/" + title + ".txt", ...)(while 循环开始前先建好文件夹)。

模块化设计思想(约 33:43–35:00)

  • 为什么强调把简介写进 txt 而不是直接在内存里传给下一步?每个模块的输出最好持久化存储(写进文件/数据库/JSON/XML)。
  • 好处:做第二步、第三步时不用反复爬取(否则中断后重爬容易被豆瓣封);模块间用"上一个模块的输出作为下一个模块的输入"解耦。这是做作业、工作、科研合作写单独模块时都要有的意识——交付的东西最好是离线可操作的结果。

TF-IDF 关键词提取(约 34:59–48:30)

  • 用 **jieba 分词**自带的 TF-IDF 模块(jieba 文档里有"基于 TF-IDF 算法的关键词抽取"示例,可直接参考)。Anaconda 不自带 jieba,需 pip install jieba——可以在 Anaconda 里 new 一个 Terminal 装,或在终端初始化虚拟环境后装。
  • 遍历文件:用 glob 匹配 movies 目录下所有 .txt(呼应之前"遍历目录"的作业);读文件与写文件对应:open(path, "r", encoding="utf-8"),f.read() 无参数读全部。
  • 文本清洗(约 37:04):用字符串的 replace 方法依次去掉"豆瓣"(版权信息残留)、英文空格、中文空格(比英文空格宽,要单独替换)、换行符(分词对标点足够,换行无影响)。
  • 提取:jieba.analyse.extract_tags(content, topK=20, withWeight=True):
  • topK:取重要程度前多少名的词,默认 20,可不写;
  • withWeight:默认 False 只返回关键词列表(按重要程度排序);设为 True 返回**(关键词, 权重)元组的列表**——因为画词云需要权重值。
  • 权重汇总(约 46:00):每篇简介单独提取,同一关键词在不同简介中权重不同,需要累加。做法:定义空字典 result,遍历所有关键词元组,if key not in result: result[key] = value 否则 result[key] += value。
  • 排序(约 48:14):字典乱序,用内置函数 sorted:
  • 先用 result.items() 把字典还原成 (key, value) 列表;
  • sorted(..., key=lambda item: item[1], reverse=True)——key 参数指定排序依据,用**匿名函数 lambda** 取每个元素的一号元素(权重);reverse=True 倒序让权重高的在前;
  • 结果可再转回字典。
  • 结果解读:悬疑/剧情片高频词如探员、警局、妻子、女儿、改编——主角多为家庭关系、多涉及案件、常由小说改编。

停用词与用户词典(约 54:09–1:00:30)

  • "本片"、人名(杰克、约翰、夏洛克)等词对分析主题没有意义,是"污染",引入 jieba 的两个词典机制:
  • 用户词典 jieba.load_userdict("user_words.txt"):告诉分词工具哪些词不要拆开(每行一个词)。例:外国人名"羽生结弦"容易被拆成"羽生/结弦",放进自定义词典就能保住;中文分词博大精深,组合情况复杂。
  • 停用词 jieba.analyse.set_stop_words("stopwords.txt"):分析时忽略的词——"的、得、地"、他/她/它等高频指代词,以及"本片"、主角名、"电影"等不想出现在结果里的词。
  • 词典文件放在当前目录(demo 文件夹),迭代修改:跑一遍 → 看结果里还有哪些污染词 → 加进 stopwords → 再跑,直到结果干净。

词云可视化(约 1:00:42–1:06:30)

  • 用 wordcloud 库(不是 Anaconda 自带,需 pip install wordcloud)。
  • 必须设置中文字体(约 1:03:46):WordCloud 默认用英文字体,中文会显示成方块(英文字体只需设计 26 个字母,中文核心汉字有 3500 个)。参数 font_path 指定字体路径——Windows 字体在系统字体目录下(课上用仿宋),Mac 需自行查找系统字体路径。
  • 创建词云:WordCloud(font_path=..., width=..., height=..., max_words=80),可设置图片宽高和最多展示的词数。
  • 把汇总排序后的字典扔进去生成词云(generate_from_frequencies(result)),可存为图片文件;用 matplotlib 直接展示——Jupyter Notebook 能实时在单元格下方显示图,不必去文件管理器双击打开,这是 Notebook 很好用的特性。
  • 生成的词云直观印证结论:探员、警局、家庭关系、改编等词占比大;残留的污染词(人名等)继续通过停用词词典迭代去除。

作业要求(约 1:06:33–1:10:40)

  • 提交内容:代码仓库(git 分支)里包含词云图、Jupyter Notebook(可以传 GitHub)、爬下来的 movies 文件夹(不用爬太多,老师爬了 135 个,至少有这个过程)。
  • 基本要求:照着视频把三步功能完整复现一遍即可。
  • 进阶要求(替换任意模块):
  • 简单:换一个豆瓣电影类型抓(动画、悬疑、凶杀等,别和老师抓的重复);
  • 中等:改抓微博——GitHub 上有很多现成代码,考验是把别人的代码跑起来打通(鼓励找现成模块不算抄袭,但跑不通等于没做);
  • 更进阶:爬虫用 Scrapy 框架重写;情感计算跑个模型。第二步做得足够复杂的话,可视化做几个简单图表即可。
  • 老师寄语:学完这门课后看到网上任何 Python 代码都能跑起来,就算出师了。

示例与演示

  • 抓取模块改造:上节课的接口请求代码 → 去掉 result 列表 → 对每部电影 requests.get(url) → BeautifulSoup 解析 → select 定位 link-report-intra → 精确到 span.all hidden → get_text 取纯文本 → 空列表分流处理 → with open 写 txt。
  • 排错演示:list index out of range → 加日志定位到《窃听风暴》→ 页面检查发现没有"展开全部" → 写空列表判断。
  • 关键词提取:glob 遍历 movies/*.txt → read + replace 清洗 → extract_tags(content, topK=20, withWeight=True) → 字典累加权重 → sorted(result.items(), key=lambda item: item[1], reverse=True) 排序。
  • 词典配置:新建 user_words.txt 与 stopwords.txt,load_userdict / set_stop_words 载入,迭代加词(本片、杰克、约翰、夏洛克、电影……)。
  • 词云:WordCloud 设置 font_path(仿宋)、width/height、max_words=80,喂入结果字典,matplotlib 实时出图。

重点与难点

  • **select 返回列表**及"id 唯一所以取 0 号元素"的逻辑容易绕;list index out of range 的排错套路(加日志 → 定位页面 → 分析结构 → 异常分流)是通用技能。
  • 页面结构不统一(有的电影没有"展开全部")是真实爬虫的常态,必须做空值判断。
  • 模块输出持久化:中间结果落盘,避免重复爬取被封,也方便分阶段开发——老师特别强调的工程意识。
  • TF-IDF 提取时 withWeight=True 才能拿到画词云所需的权重;多文档汇总要用字典累加。
  • sorted + lambda + reverse 对字典按值排序的组合写法是重点语法。
  • 中文处理的两个坑:中文空格与英文空格不同要分别清洗;WordCloud 必须指定中文字体 font_path,否则全是方块。
  • 环境变量问题(jupyter 命令找不到)再次出现,要求能独立解决。

关联内容

  • 直接续接《Python-2023-12 爬虫之豆瓣》:用其爬到的电影 title/url 作为输入。
  • 前置章节知识:BeautifulSoup 与 CSS 选择器(爬虫章节)、文件读写与 with open、glob 遍历目录(此前的作业)、字典操作与 sorted/lambda(函数进阶相关内容)、第三方库安装与虚拟环境、Jupyter Notebook 使用。
  • 词云可视化呼应课程可视化部分;扩展方向提到的 Scrapy 在爬虫章节视频中讲过。
  • 本课是爬虫+可视化大作业的收尾课,作业框架(抓取—分析—可视化)被点明可扩展为舆情系统/科研方向。