先说一下包名:Beautiful Soup?在 Web 开发中,“tag soup(标签汤)”一词指结构或语法上不规范的网页 HTML 代码。Beautiful Soup 最擅长的,就是把“标签汤”再次变得优雅,并轻松从中提取信息!事实上,使用该包时创建并查询的主要对象就叫 BeautifulSoup。创建“汤”之后,我们可以用它的 .get_text() 方法来提取文本。
# Import BeautifulSoup from bs4from bs4 import BeautifulSoup
# Create a BeautifulSoup object from the HTML
soup = BeautifulSoup(html,"html5lib")type(soup)技术支持
'\n Moby Dick; Or the Whale, by Herman Melville\n '技术支持
或者获取页面中所有 < a > 标签(超链接)中的 URL:
# Get hyperlinks from soup and check out first several
soup.findAll('a')[:8]技术支持
[<a href="#link2H_4_0002">ETYMOLOGY.</a>,<a href="#link2H_4_0003">EXTRACTS(Supplied by a Sub-Sub-Librarian).</a>,<a href="#link2HCH0001">CHAPTER1. Loomings.</a>,<a href="#link2HCH0002">CHAPTER2. The Carpet-Bag.</a>,<a href="#link2HCH0003">CHAPTER3. The Spouter-Inn.</a>,<a href="#link2HCH0004">CHAPTER4. The Counterpane.</a>,<a href="#link2HCH0005">CHAPTER5. Breakfast.</a>,<a href="#link2HCH0006">CHAPTER6. The Street.</a>]技术支持
您现在想做的是从 soup 中提取文本,而 .get_text() 方法正是为此而生。
获取文本,打印出来,看看它。是您要的内容吗?
# Get the text out of the soup and print it
text = soup.get_text()#print(text)技术支持
接下来,作为热身,您将使用 Python 内置包 re,从句子“peter piper picked a peck of pickled peppers”中提取所有以“p”开头的单词。
# Import regex packageimport re
# Define sentence
sentence ='peter piper pick a peck of pickled peppers'# Define regex
ps ='p\w+'# Find all words in sentence that match the regex and print them
re.findall(ps, sentence)技术支持
# Initialize new list
words =[]# Loop through list tokens and make lower casefor word in tokens:
words.append(word.lower())# Print several items from list as sanity check
words[:8]技术支持
您希望获得 words 中所有不在sw 中的单词列表。实现方式之一是遍历 words 的所有元素,若该词不在sw 中,就将其加入新列表:
# Initialize new list
words_ns =[]# Add to words_ns all words that are in words but not in swfor word in words:if word notin sw:
words_ns.append(word)# Print several list items as sanity check
words_ns[:5]技术支持
defplot_word_freq(url):"""Takes a url (from Project Gutenberg) and plots a word frequency
distribution"""# Make the request and check object type
r = requests.get(url)# Extract HTML from Response object and print
html = r.text
# Create a BeautifulSoup object from the HTML
soup = BeautifulSoup(html,"html5lib")# Get the text out of the soup and print it
text = soup.get_text()# Create tokenizer
tokenizer = RegexpTokenizer('\w+')# Create tokens
tokens = tokenizer.tokenize(text)# Initialize new list
words =[]# Loop through list tokens and make lower casefor word in tokens:
words.append(word.lower())# Get English stopwords and print some of them
sw = nltk.corpus.stopwords.words('english')# Initialize new list
words_ns =[]# Add to words_ns all words that are in words but not in swfor word in words:if word notin sw:
words_ns.append(word)# Create freq dist and plot
freqdist1 = nltk.FreqDist(words_ns)
freqdist1.plot(25)技术支持
本周早些时候,我做了一场 Facebook Live 编码跟练。在其中,我们用一些基础的自然语言处理方法,绘制了小说《白鲸》中最常出现的单词。在此过程中,我们也体会到时刻关注流程、以如下数据科学流水线来思考问题的有效性:
在本文中,您将学习如何构建一个数据科学流水线,以绘制《白鲸》(以及许多其他小说)的词频分布。
提示:如果您想回看这场 Facebook Live,请查看下面的视频;您可以直接跳到第 12 分钟,Hugo 出场并正式开始。
我们不会直接给您小说文本:您将学习如何使用 Python 包
requests从网站 古腾堡计划(基本上是一个大型书籍语料库)抓取小说,并使用BeautifulSoup从这些网页数据中提取小说文本。然后,您将深入使用自然语言工具包(nltk)来分析这些小说。在此过程中,您会了解自然语言处理(NLP)中的重要概念,如分词与停用词。完成之后,您将能够可视化古腾堡计划上任意小说的词频分布。而您所掌握的 NLP 技能,同样适用于数据科学家经常遇到的大量数据,因为世界上相当大比例的数据是非结构化数据,其中包含大量文本。
例如,下面这张词频分布图会来自哪部作品呢?
本文由一个 Jupyter Notebook 生成;您可以在此仓库中找到它。如果您有任何想法、反馈和/或感想,欢迎在 Twitter 上联系我:@hugobowne。
预备步骤
按照 README.md 中的说明,完成系统环境的准备与配置。
1. 陈述您的问题
在小说《白鲸》中,哪些词出现得最频繁?它们各自出现了多少次?
2. 获取您的数据
您的原始数据是梅尔维尔小说《白鲸》的文本。您会如何把这本约 800 词的书的文本导入到 Python 中?
其实有多种方式,但首先要知道,这份文本在网上的 古腾堡计划上可免费获取。我们去那里,尝试找到《白鲸》,然后将相关的 URL 存入您的 Python 命名空间:
现在您已经有了 URL,需要去获取该网站的 HTML。
注意:HTML 是超文本标记语言(Hypertext Markup Language)的缩写,是 Web 的标准标记语言。
您将使用
requests来完成,它是最流行且实用的 Python 包之一。您可以在 DataCamp 的《Python 数据导入进阶(第 2 部分)》课程中了解更多。根据
requests的官网:而以下组织声称在内部使用
requests:此外,
您将对该网站发起一个
GET请求,这意味着您从它那里“获取”数据。使用浏览器访问网页时,实际上也是在这么做。还有其他类型的请求,例如POST请求,但这里不涉及。requests通过其get函数让这一切变得很简单。现在就发起请求并查看返回对象的类型。这是一个
Response对象。您可以在requests快速入门指南中看到,Response对象有一个text属性,可以从中获取 HTML!让我们这么做,并打印 HTML 看看:好的!这些 HTML 并不完全就是您要的内容。不过,它确实包含了您要的:《白鲸》的文本。接下来您需要做的是对这份 HTML 进行整理,以从中提取出小说。
3. 整理数据以回答问题
第 1 部分:从 HTML 中获取文本
这里您将使用
BeautifulSoup包。其官网写道:看起来很有希望!
先说一下包名:Beautiful Soup?在 Web 开发中,“tag soup(标签汤)”一词指结构或语法上不规范的网页 HTML 代码。Beautiful Soup 最擅长的,就是把“标签汤”再次变得优雅,并轻松从中提取信息!事实上,使用该包时创建并查询的主要对象就叫
BeautifulSoup。创建“汤”之后,我们可以用它的.get_text()方法来提取文本。从这些 soup 对象中,您可以提取出关于所抓取网站的各种有趣信息,例如标题:
或者把标题作为字符串获取:
或者获取页面中所有 < a > 标签(超链接)中的 URL:
您现在想做的是从
soup中提取文本,而.get_text()方法正是为此而生。获取文本,打印出来,看看它。是您要的内容吗?
注意,现在这几乎就是您所需要的。
它是小说的文本,但开头有一些不需要的内容,末尾也有一些不需要的内容。您可以选择移除它们。不过,这些内容相对于《白鲸》正文来说非常少,因此在第一近似下,保留它们也无妨,本文将采取这种做法。若要得到更稳健的结果,我建议将其移除。
既然您已经获得了目标文本,现在是时候统计每个单词出现的次数,并绘制所需的词频直方图了:自然语言处理来帮忙!
第 2 部分:用 NLP 从文本中提取单词
您将使用自然语言工具包
nltk来:步骤 1:分词
您希望对文本进行分词,也就是说,将其拆分为单词列表。实质上,您想根据空白字符将文本分割开来。
为此,您将使用一个强大的工具:正则表达式。正则表达式(简称 regex)是一种字符序列,用于定义搜索模式。它们一向以难懂著称,最好的介绍方式是通过示例。
匹配所有以“p”开头的单词的正则表达式是“p\w+”。我们来拆解一下:
结合起来,“p\w+”会匹配所有以“p”开头、其后跟随字母数字和下划线的子串。在大多数有意义的英文文本中,这通常对应于以“p”开头的单词。
接下来,作为热身,您将使用 Python 内置包
re,从句子“peter piper picked a peck of pickled peppers”中提取所有以“p”开头的单词。看起来不错。现在,如果“p\w+”是匹配以“p”开头单词的正则,那么匹配所有单词的正则是什么?
现在由您来对上面的 Peter Piper 示例句子完成这个任务。
现在您可以对包含《白鲸》文本的字符串
text做同样的事情:注意:也可以使用 自然语言工具包
nltk来完成:好!您已接近目标。不过请注意,上面示例中的“Or”首字母是大写“O”,而在其他地方可能不是,但“Or”和“or”您希望计作同一个词。因此,您需要构建一个包含《白鲸》所有单词的列表,并将所有大写字母转为小写。字符串方法
.lower()会很有用:步骤 2:移除停用词
通常会移除英语中高频出现的词,如“the”、“of”、“a”(称为停用词),因为它们不那么有趣。关于这些技术的更多内容,请查看我们的《Python 自然语言处理基础》课程。
nltk包提供了英文停用词列表,您现在将其保存为sw,并打印其前几个元素。如果这里报错,请运行命令
nltk.download('stopwords')在您的系统上安装停用词资源。您希望获得
words中所有不在sw中的单词列表。实现方式之一是遍历words的所有元素,若该词不在sw中,就将其加入新列表:4. 回答您的问题
我们的问题是:“在小说《白鲸》中,哪些词最常见?它们出现了多少次?”
现在,您可以用
nltk仅用两行代码就绘制出《白鲸》的词频直方图。为此:nltk.FreqDist()创建一个频率分布对象;plot()方法。5. 呈现您的解决方案
有意思的是,在使用
nltk回答我们的问题时,我们实际上已经用一种便于交流的方式呈现了解决方案:一幅词频分布图!您可以直接读出最常见的词及其频率。比如,“whale”(鲸)是在排除停用词后,小说中最常见的单词(这不意外),出现次数超过 1200 次!加餐
既然您已经看到古腾堡计划上有很多小说都可以绘制词频直方图,那么把整个流程写成一个函数就很有意义:
现在用这个函数来绘制古腾堡计划上其他文本的词频分布:
结语
在本文中,您学习了如何构建数据科学流水线,以绘制《白鲸》(以及许多其他小说)的词频分布。您学习了使用 Python 包
requests从 古腾堡计划(大型书籍语料库)抓取文本,并使用BeautifulSoup从网页数据中提取小说。随后,您使用自然语言工具包(nltk)对小说进行了分析。在此过程中,您了解了自然语言处理(NLP)的重要方面,如分词与停用词。现在,您已经能够可视化古腾堡计划上任意小说的词频分布。而您所发展的 NLP 技能,同样适用于数据科学家经常遇到的大量数据,因为世界上相当大比例的数据是非结构化数据,其中包含大量文本。本文由一个 Jupyter Notebook 生成;您可以在此仓库中找到它。如果您有任何想法、反馈和/或感想,欢迎在 twitter 上联系我:@hugobowne。也请告诉我您构建的那些很酷的项目。
查看 DataCamp 的《使用 Python(与 Beautiful Soup)进行网页抓取》和《如何使用 Python 抓取亚马逊》教程。