天天看点

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

本节书摘来自华章计算机《数据科学r语言实践:面向计算推理与问题求解的案例研究法》一书中的第2章,第2.7节,作者:[美] 德博拉·诺兰(deborah nolan)  邓肯·坦普·朗(duncan temple lang)  更多章节内容可以访问云栖社区“华章计算机”公众号查看。

图2-20 2012樱花公路赛男子组比赛结果的页面源码截屏。截屏显示的是2012樱花公路赛男子组结果网页的html源码,它和2011年女子组比赛结果(见图2-21)的格式不是很相似,但两者都是在html文档中通过

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

图2-21 2011年樱花赛女子组结果页面的源码截图。该图是2011年樱花公路赛女子组结果的html源码截屏。注意给出的时间是比赛中点处(5 mile)和两个比赛完成时间(time和net tim)。还要注意最右边的列标记为s。尽管和2012年男子组比赛结果的格式不同,但是他们都是在html文档中通过

getnodeset()函数返回一个列表,其中的每个元素都对应文档中的一个

下面检查txt中的内容。我们首先确定其中包含多少字符,然后检查它的开始和结束位置。代码如下:

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

结果显示我们成功地从web页面中提取出了信息。我们还看到以rn结尾的单独行,可以利用这些字符将690 904个字符分割成独立的字符串,每个字符串与表中的行对应。方法如下:

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果
《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

现在已经成功地提取了表中的行作为一个字符向量中的元素。

下面让我们把代码整理成函数,使其可以应用到所有的28个web网页(从1999年到2012年的所有男子组和女子组页面)。函数以web页面的url作为输入,返回一个字符向量,其中每一行为一个元素,包括头部行和表的结果行。将前面的代码组织成一个函数:

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

函数的提取结果和之前的一样。现在我们可以将它应用到跨这些年度的所有男子组的比赛结果中。

假设有一个包含所有url的向量,那么就可以将我们的函数简单地应用于该向量。我们通过把基本的url与特定年份的信息结合在一起,创建这样的url向量:

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

这里有一个错误,提示prenode有问题。

为了找到关于错误原因的更多信息,我们通过设置recover()函数对象的error选项,把错误处理的功能打开,这样当有错误发生时recover()函数就会被调用。该函数允许我们访问活动的调用框,以便检查对象并查看结果是否如我们所预料。下面设置options(),并再次调用extractrestable()函数:

当错误发生时,以上内容显示了当前实际的函数调用集合的简单视图。这就是“调用栈”。第一条是对lapply()的顶层调用。第二条是对extractrestable()函数的实际调用。lapply()调用了extractrestable()函数,但是是使用名字fun进行调用,这是因为它是lapply()中的参数名,它包含了我们想要使用lapply()第一个参量中的所有元素而调用的这个函数。extractrettable()调用了几个函数,但是错误发生在第三个表达式xmlvalue(prenode[[ 1]]),它是当前调用栈的第三个也是最后一个元素。

recover()函数允许我们选择想要检查的调用。在selection提示符处,输入调用编号(如2)并按下回车键,那么将直接在指定调用的调用框中执行该函数。我们将可以检查(和更新)当前参数与局部变量的值,且可以在该位置执行任意代码。

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

结果显示在1999年的比赛结果页面中没有

我们重新创建urls向量,使其包含正确的web地址。我们将url地址合并到一起:

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

这回我们没有收到任何错误消息。当然,这只是因为没有运行错误,并不意味着已经能够正确地提取数据。我们需要检查结果集以查看其中是否包含我们所期望的信息。

首先检查每一个字符向量的长度。从网站上我们看到每年有几千名参赛选手完成比赛,所以我们期望在向量中有几千个元素。

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

但是,2000年和2009年的向量提取结果中只有一个元素。

这两年数据的文件名是正确的,因此需要进一步发掘原因。我们浏览2000年网页的源码,检查其格式是否符合我们预期。下面是2000年文档的前几行信息:

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

让我们重新组织html标签,利用缩进来检查是否有文件格式问题。下面是对于相同的内容以更直观的方式展现的结果:

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

这个文档不是规范的html文档。虽然htmlparse()函数可以修复很多畸形文档问题,比如,关闭

标签,根据标签名匹配实例等。然而,这个函数只能做到这些。注意上面文档中和

出现在

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

以上我们已经解决了2000年的问题,但是2009年的问题仍然存在。在此将这个问题留作练习,修改extractrestable()函数以处理该特殊情况。一旦修改了代码,便会发现2009年的表中有6659行。

既然已经有了可以处理男子组比赛结果页面的函数,可以尝试把它应用到女子组页面上。在操作时,我们发现除了2009年之外其他页面都能处理得很好。对于这种情况,不需要对女子组该年份的结果做任何特殊的处理。我们可以再次修改函数,使2009年女子组的结果能够得到缺省处理,而不是像2009年男子组结果那样需要特殊处理,在此我们将它留作练习。

我们保存数据以便进一步处理:

《数据科学R语言实践:面向计算推理与问题求解的案例研究法》一一2.7 从网上抓取比赛结果

最后,采用r数据格式保存字符向量列表的另一种方式是将字符向量写到普通的文本文件中。我们可以使用writelines()来完成上述工作。事实上,可以修改extractrestable()函数以接受一个file参量。如果提供了file参量,函数就把结果写到相应的文件中;如果file参量为null,那么函数就返回一个字符向量。同样,在此我们把这个关于改进的问题留作练习。

继续阅读