Stata 网页表格爬取示例

Stata 网页表格爬取示例

本文以爬取东方财富网 CPI 数据为例,讲解如何使用 Stata 进行网页表格数据爬取。

Stata 虽非数据爬取利器,但是能够轻松解决一些小的数据爬取任务。数据爬取的本质无非是数据请求和数据处理,因此熟练使用 Stata 进行数据爬取往往也是很好的数据处理能力的象征。在实际应用中,我们经常需要爬取一些公开数据。这些数据一种常见展示方式是通过 HTML 表示呈现。一个简单的 HTML 表格示例如下:

1
2
3
4
<table>
<tr><td bgcolor="red">1</td><td bgcolor="yellow">2</td><td bgcolor="blue">3</td></tr>
<tr><td>1</td><td>2</td><td>3</td></tr>
</table>

东方财富网 CPI 数据的表格是这样的:

下面我将一步步讲解如何爬取这个表格。

准备工作

  1. Stata14.0 以上版本的;
  2. Chrome 浏览器;
  3. 想把数据爬下来的你。

网页分析

首先讲解如何爬取一个页面的表格。这个网页的网址是:

1
http://data.eastmoney.com/cjsj/cpi.html

在页面上右键选择显示网页源代码,很多浏览器都有查看网页源代码的功能,但是我还是最喜欢谷歌浏览器的。点击之后即可跳转至网页源代码界面:

也就是说你刚刚看到的网页的本质实际上是这些源代码,之所以我们能看到各种炫彩的页面,那是因为浏览器帮我们翻译了源代码。

下一步我们要做的事情就是找到这个表格在源代码的哪一块儿了,然后分析表格的特点,已方便在后面的 Stata 处理源代码的时候进行过滤。

一个经常被用来寻找目标的方法是使用查找功能。Ctr+F(Mac 是 Command + F)即可打开搜索框,我们注意到表格里面有月份两个字,所以我们就用月份进行查找。

我们首先在第 1987 行发现了这个词,仔细一看,这附近的代码就是表格的代码。

下一步就是我们先分析一下这部分代码的特点:

  1. 所有表格中的数据在源代码中都是单独位于一行的,所以我们不能从其所在行入手了;
  2. 表格数据的上一行要么有字符串 <td class= 要么有 <span。也可以发现,span 标签是控制文字颜色的。

经过以上的网页分析我们就可以开始进行网页表格爬取了。

开始爬取

总的来说,Stata 进行网页表格爬取分为 3 个步骤:

  1. 请求:把含有所需数据的源代码下载下来;
  2. 转码:很多网页并非使用 UTF-8 编码,直接读入 Stata 会出现乱码,因此可以预先进行 UTF-8 转码;
  3. 处理:这里主要是对字符串进行处理,常用操作有分割 (split)、转置 (sxpose)、提取 (正则表达式或直接字符串提取)等等。

请求

由于这个网页没有设置反爬机制,所以可以直接使用 copy 命令进行下载,copy 命令不仅可以下载网页,还可以下载文件(当然网页其实就是一个 html 文件)。更多用法可以 help copy。我们这里把要爬取的页面保存成一个名叫 temp.txt 的 txt 文件,为什么要起这个名字呢,因为爬完之后它就要被删除了,所以只是一个临时的文件。实际上 Stata 也可以创建临时文件,这样的文件会在运行结束的时候自动被删除,不过我觉得这是没有必要的,因为通常需要把 temp.txt 文件打开分析里面的内容。

1
2
3
4
clear all
* 设定工作目录
cd "你自己的工作目录(一个文件夹的路径)"
copy "http://data.eastmoney.com/cjsj/cpi.html" temp.txt, replace

转码

在我的 Stata 命令包—— finance 包中,我编写了一个简单的转码命令,这个命令包的安装办法为:

1
2
3
4
* 首先你需要安装 github 命令,这个命令是用来安装 GitHub 上的命令的
* net install github, from("https://haghish.github.io/github/")
* 然后就可以安装这个命令了
* github install czxa/finance, replace

安装成功之后,使用下面的命令就可以直接对 temp.txt 文件进行转码了:

1
utrans temp.txt

如果返回的结果是转码成功,则表示转码成功了!(感觉像在说废话。。。)

如果你不幸的因为各种各样的原因没能成功安装这个小命令,可以直接使用下面三句命令进行转码:

1
2
3
unicode encoding set gb18030
unicode translate temp.txt
unicode erasebackups, badidea

读入

下面我们就要把 temp.txt 文件读入 Stata 进行处理了,一个非常常用的读取方法是使用 infix 命令:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

这句命令的含义是创建一个格式为 strL 的变量 v,然后把 temp.txt 文件的每一行的前 1-20000 个字符(因为我们注意到 temp.txt 的每一行都没有超过 20000 个字符)读入变量 v 的每一个观测值。读入之后是这样的:

处理

首先根据上面我们进行网页分析发现的结论,我们保留符合 表格数据的上一行要么有字符串 "<td class=" 要么有 "<span" 规律的观测值:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

这一步处理后的结果:

实际上到这一步,我们已经把表格整理的挺干净了,不过这不像一个表格,我们需要进行这样的一个操作:我们已经注意到了 1-13 行实际是表格的第一行,14-26 行实际是表格的第二行。我们该怎么完成这样的一个操作呢?一个非常好用的命令是 post 命令。这个命令的功能就像它的名字一样——邮局。它可以实现把 v 的每个观测值发送到我们想要得到的表格的指定位置。

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

经过这个“邮局操作”,数据现在变成这个样子的了:

到这一步我们实际上已经完成了这个表格的爬取了,不过接下来我们再把数据整理成更加规整的 Stata 数据。

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

这样整理之后的数据集是这样的:

这样我们就爬好了单页面的表格。另外我们也注意到完整的表格有 8 页。我们点击下一页可以看到第二页的网址是:

1
http://data.eastmoney.com/cjsj/consumerpriceindex.aspx?p=2

显然 url 中的最后一个参数就是页数。每页的结构都是一致的,所以可以循环运行刚刚的代码把剩下 6 个页面的表格依次爬下来然后合并。

多页面爬取

纵向拼接示例

作为示例,我们再尝试用刚刚的代码爬第二页:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

这些代码运行之后可以得到一个和第一页爬取结果类似的表格,然后可以用 append 命令把这个表格纵向拼接到第一页爬取的数据集 CPI_final.dta 上:

1
2
append using CPI_final
save CPI_final, replace

循环拼接

为了连贯,我再把上面的代码重新写,因为有些代码可以在放在循环之后再运行,例如变量标签、变量名等。

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

爬取结果:

至此,这个爬取任务我们就算完成了。下面我们进行一个简单的应用 —— 数据展示。

数据呈现

假如我想观察 CPI 的走势,需要绘制一幅线图:

代码去哪了?

代码可以加入我的知识星球后从知识星球下载附件获取~
要了解如何加入我的知识星球,可以阅读关于界面或者添加我的微信咨询。

上面一些选项的含义:

  • ||: 用于分隔图层。
  • line: 用于绘制线图
  • tw: 全称是 twoway,用于组合多个图层
  • lc: 全称为 lcolor()用于控制线图的颜色
  • lp: 全称是 lpattern()用于控制线型
  • yline: 在指定位置画一条水平线
  • xline: 在指定位置画一条竖直线
  • ti: 全称是 title(),控制标题,size 用于控制标题文字大小,这里是 1.2 倍
  • leg: 全称是 legend(),控制图例,pos 用于控制图例的位置,这里是 6 点种方向,单行排列。
  • scatteri: 用于在指定的坐标处画个点。”2018 年 6 月”是这个点的标签, (12)用于指定这个标签位于点的方向,指定为 12 点钟方向。

知识星球链接:https://t.zsxq.com/Mn6E2j6

#

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×