beautifulsoup_使用BeautifulSoup抓取NBA数据介绍

f9fe15153a15db5bf3515ff96dfd5a7c.png

fcf726df6844055d65e6a1a3fd7ed1ee.png

图片来自Unsplash,作者 NeONBRAND 

感谢你在我们设置环境时保持耐心。现在我们开始编码和操作数据。以下是这篇文章的计划:

  • 设置虚拟环境

  • 在该虚拟环境中安装ipython、jupyter、beautifulsoup4和pandas 

  • 学习抓取、组织和保存web数据

设置虚拟环境

我们为什么要这么做?虚拟环境只是作为python项目的隔离环境。它们允许你为不同的项目使用不同版本的模块,而不会导致版本之间的冲突。让我们从下载virtualenv开始。你可以打开终端并输入以下命令来下载:

5293160bf931576424905d16d568f2a2.png

现在,切换到medium_tutorials文件夹,我们将激活一个新的虚拟环境。我们通过输入以下命令来做到这一点:

85ae80cab0abeeb86ba415889854d105.png

cd9ebe52c051dd319e92d6065c8097f7.png

创建一个虚拟环境

现在虚拟环境已经创建好了,我们再输入以下命令:

02bba37549e43a1b1e00319e5a96fcf0.png

你可以看到,当我们激活该虚拟环境时,它会在命令行开头显示(.venv)。小事一桩。

e513c0b5541f6e8ecc79ba6299c4232b.png

进入虚拟环境

在虚拟环境中安装包

你已经安装或随python发行版附带的包通常在你的新的虚拟环境中是不可用的。我们来通过在我们的虚拟环境中安装ipython来实现我们的新空间的功能:

2ac04853b222017466f489076b3341e3.png

3e673c7a06abcfa67ce7c196e14faf16.png

在我们的虚拟环境中安装ipython

现在我们开始安装Jupyter,以便我们可以开始使用notebook:

f28824bd667eb82847317dd82c6fddcb.png

安装了Jupyter后,我们可以在我们的虚拟环境中安装一个Jupyter内核:

353dd0288718414fa7ad1cb364a98d60.png

最后,我们来安装BeautifulSoup4、requests和pandas,这样我们就可以开始抓取数据并执行一些基本的计算:

0fcf7df0cb60f57a37dd63f4c4597eda.png

是时候开始编码了!

https://media.giphy.com/media/5VKbvrjxpVJCM/giphy-downsized.gif 

Notebook设置

首先在项目文件夹中创建一个名为web_scraping的新文件夹,并切换到该目录,然后进入终端输入以下命令来启动jupyter notebook:

5f379e019e2b47dfda8a7d0034e62a7a.png

这将启动带有一个文本菜单的浏览器,该文本菜单中带有说明notebook列表是空的的文本。让我们通过点击右上角的“new”,然后点击Notebook下的.venv来改变这一点。

191cc928ce0c28b3ee2bc2114583037c.png

使用虚拟环境内核创建notebook

现在我们有了一个使用虚拟环境的空白notebook。在开始编写代码之前,我们创建一些快速的文档说明。首先,我们单击屏幕顶部的名称“Untitled”来重命名我们的notebook。我们将其命名为web_scraping_tutorial。

fbe1c31fe975d3b934613fb229369e22.png

重命名我们的notebook

接下来,我总是喜欢在notebook顶部的单元格中简单描述notebook的用途。我们可以用Markdown来写,这样格式就会很漂亮。要进入markdown模式,你可以从“Code”旁边的下拉菜单中选择“Markdown”,或者选择单元格并按下control+m, m。

如果你从未使用过markdown,它允许你使用基本命令来轻松地格式化文本。如果你想学习其基本语法,请阅读这里(https://www.markdownguide.org/basic-syntax/  ),你不需要在它上面花费太多时间。否则,跟着我说的做就好了。

我输入了一些初始描述文本。你可以看到左边的markdown版本和右边的结果格式:

d393081c7f2e26fa745690976361884c.png7a99ba8a7bb37e81ce8ed617337603f1.png

Markdown文本和结果输出

导入模块

现在我们导入计划使用的模块。我们将导入用于提取html的requests、用于解析的BeautifulSoup4、用于操作数据表的pandas以及在保存数据时操作目录的os。

如果你不熟悉python基础或导入模块,那你现在就需要返回去学习一些教程。我在之前的文章中已经链接了这些教程,但是我强烈推荐Sentdex的Youtube教程和treehouse。

总之,导入应该是这样的:

4e42206f60af34c89f4b17832e10e820.png

模块已经导入,准备抓取数据!

从篮球参考请求数据

我们需要了解html的基础知识,以便从web上获取数据。如果您对html比较熟悉,那么你就可以开始了。如果你以前没有见过html或需要快速复习一下,这个12分钟的视频应该足以让你理解我们在做什么:

视频地址:https://youtu.be/bWPMSSsVdPk

现在我们只需要找到一个想要从中提取数据的页面。我们来看看篮球参考上James Harden的2018-19赛季的篮球比赛记录。单击该链接并复制url。我们的代码需要这个。在下一个单元格中,输入以下代码:

50cded23f4deb3651cb1defe3cac9f76.png

这段代码会将我们的url文本保存为一个名为url的变量。然后,我们将该url变量传递到requests库的get函数中,并将响应保存为page。最后一行的page调用将给出服务器响应。它应该会打印出,这是一个成功的服务器响应。

你不必遵循下面的几个部分,但如果你查看下面的截图,你会看到当我调用page.content时,它会返回一个以b '开头的杂乱的数据字符串。在Python中使用type函数,我们看到这是在返回字节,并且这些字节非常混乱。让我们开始使用BeautifulSoup来清理这个数据,并使这些字节变得有用。

da7052db3893dfe777b41993e81fddaa.png

我们获得了数据,而且很杂乱!

使用BeautifulSoup清理数据

我们已经在代码中导入了BeautifulSoup,所以现在只需将页面内容传递给它。我们将通过以下代码来实现:

98a0f6b1cff385f2afb0817b2f52bf4d.png

这里,我们将page.content数据传入BeautifulSoup并使用html解析器。我们将这个输出保存为soup。然后我们只需美化我们的soup并打印输出。你也可以始终检查原始的soup变量。它的数据与美化后的版本相同,只是不那么漂亮。

我们已经在BeautifulSoup中解析了内容,但是我们如何知道在哪里可以找到我们需要的数据呢?我们可以滚动html文本,也可以通过简单的cmd-f来从html中的比赛记录页面中找到特定的值。Harden在本赛季的第一场比赛中打了34比43,这是非常特别的,所以我们来在html中搜索这个值。

dcaff453eae471bdcfc7e403db678772.png

搜索值比一直滚动更容易

我们首先注意到,stat包含在一个表数据标记中。此外,你还将看到一个值为“mp”的data-stat元素。查看下一个td标记,你将看到另一个值为“fg”的data-stat元素。如果搜索这些标记的其余部分,你会看到它们与在线表格的列是相对应的。

公正的警示——下一段脚本不是最优化的,但是我要做的是为我们想要获取的所有data-stat值创建一个列表。一个更好的方法应该是从该html中提取这些元素,但我们现在不担心这个。一旦我们将stats放置在一个列表中,我们将使用一个嵌套的列表推导式来获取James Harden的stats。这是代码:

6488bb1e4d66ae443b0a38bb4dfaae64.png

我们来分解这个stats_list变量,这样我们都清楚这里发生了什么。当你在Python中学习循环时,它们通常是这样的:

da00b38933bf1bc00510116fe1967832.png

通过一个列表推导式,我们可以执行同样的操作,同时保持代码更简洁更短小:

5a5335926c75cfccea0c51a66df3f3e6.png

它更简洁,因为它能马上告诉我们正在执行的操作,而且通常更快。一般的经验法则是,如果列表推导式易于理解,则使用列表推导式而不是for循环。如果需要多个嵌套列表推导式或高级逻辑,请使用较慢的代码简洁的if语句。无论如何,通过上面的代码,我们将从内部列表推导式开始:

61336c40d7e4aa70ad40d284e6ec2f7b.png

这段代码的意思是,为在搜索soup文本时找到的每个表数据元素获取表数据元素的文本值,并找到具有与我们的stat值相等的data-stat元素的所有表数据元素。由于stat值未被定义,这时外部列表就发挥作用了。我们将在这里使用伪代码:

abf810120d8d29d6b4a980115bd794a4.png

.

我们知道内部代码获取的是data-stat 等于 stat的表数据值。这段代码只是为我们的stat列表中的每一个stat运行这个过程。运行此代码后,我们可以检查我们的stats_list变量,如下所示:

25bc3ff3f70a1a8d03dfdf2662edb2ba.png

stats_list输出

从嵌套列表到一个Pandas DataFrame

使用Pandas,我们可以很容易地将数据放入一个DataFrame,这使得查看和操作数据变得很容易。

让我们从尝试直接从stats_list创建一个DataFrame开始,并查看前5行:

e0bd7d97d19d9319f3fd8f7778405158.png

e5e504ff22e7cb63b614116b00465545.png

将测试负载初始化到一个DataFrame中

你可以马上看出这个数据看起来不太正确。实际上,我们看到有82列。对于我们的目的,数据没有正确地定向。让我们对数据进行转置,并查看前10行。

f593893f6ea83c89bfb6503c5ac0c404.png

c16af1d70db0d20409dc9b43f19431d3.png

将测试负载转置为一个DataFrame

乍一看,这看起来很棒,但是请查看第4-6行。你可以看到第0列中没有加载任何数据。当我们对照篮球参考上的比赛记录来看这一点时,你会发现Harden在这些比赛中是不活跃的。尽管哈登处于不活跃状态,但我们的DataFrame显示的是stats。

这里的问题源于数据的html结构。当一个球员处于非活跃状态时,篮球参考只发送一次不活跃值,并且它会跨越结果列之后的所有列。我们需要转换一些数据并重新创建我们的dataframe。

修复我们的数据拉取并最终化DataFrame

如果你查看比赛记录,你会注意到无论玩家是否处于不活跃状态,对于整个结果列的比赛(g)来说,数据都是完整的。只有当玩家处于活跃状态时,比赛开始到加时的列才会被填入。我们来根据这个区分器将数据重新拉入单独的列表。

44f84e50b3b945a4759dcd2d90e0a5ac.png

这与我们在上面为stats_list变量使用的代码相同,但是代替了循环遍历每个stat,stats_left变量会查看前7个stats, 而stats_right变量则循环遍历其余的stats。

现在,我们将把左边的值放入一个pandas DataFrame中,并查看前5行,以确保它正确运行。

7a48a0b8920c447a6870967ca5a09580.png

17d731a4d0251920789bb6183f6be2f2.png

这看起来不错。现在,我们只需要编写一段快速的代码,以便当Harden处于非活动状态时插入空格。让我们来试一试:

549c81635f4ebc06f4640ec24208e401.png

我们把这段代码分解一下,确保它是清楚的。现在,使用列表推导式肯定会使我们的代码难以阅读,所以我们使用了一个常规循环。第一行只是说明我们将获取df_left的长度并将其传递给range函数。我们知道这个长度是82,因为这个赛季有82场比赛。因此当i在0-81范围内时,我们将查看df_left的game_season列,并看看第i列是否为空。如果是,我们将运行另一个列表推导式。我们来单独看看这个列表推导式,确保它是清楚的:

2ce8980a281b1043f059366cf4ded1cd.png

记住stats_right是一个嵌套列表。因此,我们将在stats_right的索引值i处为stats_right中的每个stats插入一个空格(即df_left[' game_season ']为空的相同索引值)。

现在,让我们把这些数据的右边的值放在它们自己的DataFrame中,然后我们将合并这两个DataFrame:

4adadbe3d48884d97fbc6ba245d98c16.png

460b016b8b1b4350ea71ef95f0260ff0.png

使用有效数据完成的DataFrame

现在我们有了一个工作的DataFrame !让我们做一个简单的测试来确保这些数字是有意义的。我们来计算一下Harden每场比赛的平均得分:

dda8ecfb7315318a1dcc784bbffb356c.png

这有点新奇。因为所有的值作为字符串读取,所以我们必须将这些得分变为整数。然而,我们不能将空格变为整数,所以我们只选择Harden参加了的比赛分值。然后我们取pts列的平均值,并把它四舍五入到一位小数点。这个值为:36.1。

19e58d9def9ffb59d40440ee8ceacc6b.png

保存DataFrame

最后一步是保存这个dataframe。首先,让我们在web_scraper文件夹中创建一个名为game_logs的新文件夹。我们导航到该文件夹,然后,在这里将我们的dataframe保存为一个csv。

59de09c4570a1dd412441dd9ede106b0.png

第一行只是使用从当前位置到game_logs文件夹的相对路径来更改目录。下一行在我们的DataFrame上调用to_csv()方法。然后,我们对输出进行命名,并告诉python不进行索引。

不想编写自己版本的代码?那就在github上下载这个版本(https://github.com/hardwoodconvergence/medium_tutorials  )。

接下来是什么

在本教程中,我们讨论了很多基础知识。我们学习了如何设置虚拟环境、抓取网站、使用列表解析操作列表、将数据存储在dataframe中以及将数据保存在一个csv中。接下来,我们将使用Harden的比赛记录来计算一些指标并创建基本的图表。在我们从一个小数据集中获得信息之后,我们将继续寻找更快、更简单的方法来访问更多的数据并扩展我们的分析。

事情将会从这里开始,因为我们将花费更多的时间来处理实际的篮球数据,而花更少的时间来设置我们的环境。我很期待,希望你也是!

谢谢你的关注。如果你从本教程中学到了任何东西,请点击拍手按钮并与朋友分享!???

英文原文:https://medium.com/hardwood-convergence/intro-to-virtual-environments-and-scraping-nba-data-with-beautifulsoup-6ce745f8c26e
译者:一瞬
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值