利用stata调用python是stata16中的一个新增功能。对此,相信很多人和小编当初的想法一样,觉得该功能是多此一举。但是小编在深入了解学习之后发现,该功能简直是stata用户的福音。该功能使得,我们可以先利用python爬取数据,然后再利用用户所熟悉的stata去处理数据,因为stata在处理数据方面具有一定的优势。

那么今天我们就来看看,怎样利用stata调用python爬取数据,再用stata进行处理?今天试爬的数据是巨潮网上的预约年报的披露时间数据。

进入Python交互模式

首先做好准备工作,清空内存,创建好路径,进入路径,然后只需要输入python,即可进入python交互模式,具体程序如下:

clear

cap mkdir "D:爬虫A股年报披露时间"

cd "D:爬虫A股年报披露时间"

python

结果如图:




python打开stata的data python读取stata数据_Data


此时出现报错,报错信息提示,end命令缺失。这就是需要我们注意的地方,进入python交互模式之后,在dofile中的程序中不可以像之前stata程序一样一行一行运行,而必须将python和end命令(包括python和end命令)之间的所有行一起运行,即必须以end命令结尾。

Python爬取网络数据

(1)利用python爬取网页源代码


python打开stata的data python读取stata数据_json_02


大家可以进入巨潮资讯网(http://www.cninfo.com.cn/new/index),点击上图的数据—>定期报告预约披露,可以看到该网页包含190页的数据,为了方便起见,今天只爬取这190页的数据。


python打开stata的data python读取stata数据_json_03


为方便stata与python使用循环,下面将利用python语法封装函数。爬取网页源代码的程序如下:

def GetSourceCode(page) : #获取网页源代码

import requests
 import time
 url = "http://www.cninfo.com.cn/new/information/getPrbookInfo"
 headers = {
 "Accept":"*/*",
 "Accept-Encoding":"gzip, deflate",
 "Accept-Language":"zh-CN,zh;q=0.9",
 "Connection":"keep-alive",
 "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
 "Host":"www.cninfo.com.cn",
 "Origin":"http://www.cninfo.com.cn",
 "Referer":"巨潮资讯网",
 "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
 "X-Requested-With":"XMLHttpRequest"
 }
 postdata = {
 "sectionTime":"2019-12-31",
 "firstTime":"",
 "lastTime":"",
 "market":"szsh",
 "stockCode":"",
 "orderClos":"",
 "isDesc":"",
 "pagesize":20,
 "pagenum":page
 }
 html = requests.post(url, headers = headers, data = postdata)
 return html.text

(2)解析嵌套字典——jsonpath模块

我们要获取的数据如图所示:


python打开stata的data python读取stata数据_Data_04


面对多层嵌套字典的json文件数据的获取,都是使用json库解析,往往需要多层遍历比较繁杂。今天介绍一个,对于多层嵌套字典更简洁的解决方式——jsonpath模块的应用。首先安装第三方模块jsonpath,在python的命令窗口输入 pip install jsonpath,安装成功后即可。

然后开始解析上面GetSourceCode()函数获取的网页源代码,具体程序如下:

def GetList(html) : 
 import jsonpath 
 true = True 
 false = False
 page = eval(html) #eval函数就是将html转换为它原本的格式,这里是字典
 stkcd_list = jsonpath.jsonpath(page['prbookinfos'], "$..seccode") #$从根节点开始,..指不管什么位置,选择符合条件的内容,获取股票代码
 date1_list = jsonpath.jsonpath(page['prbookinfos'], "$..f002d_0102")#从根节点开始,获取所有Key为f002d_0102的值
 date2_list = jsonpath.jsonpath(page['prbookinfos'], "$..f003d_0102")
 date3_list = jsonpath.jsonpath(page['prbookinfos'], "$..f004d_0102")
 date4_list = jsonpath.jsonpath(page['prbookinfos'], "$..f005d_0102")
 date5_list = jsonpath.jsonpath(page['prbookinfos'], "$..f006d_0102")
 return stkcd_list, date1_list, date2_list, date3_list, date4_list, date5_list

(3)将数据存储于stata

但目前为止,我们已经利用python爬取到了股票代码和日期数据,接下来就是将数据全部存储于stata中。这需要调用stata中的sfi(StataFunction Interface)模块中的Data类。在Data类中,set族方法是设置当前数据的一些属性;add族方法是向当前数据中添加观察值或变量;store族方法是将数据保存到当前数据集中。

具体程序如下:

def Convert2dta(stkcd_list, date1_list, date2_list, date3_list, date4_list, date5_list) : #将Python获取的数据存储到Stata中
 from sfi import Data 
 Data.setObsTotal(len(stkcd_list)) #设置数据属性
 Data.addVarStr("stkcd", 6) #添加stkcd变量
Data.store("stkcd", None, stkcd_list)#存储stkcd变量
 Data.addVarStr("date1", 10)
Data.store("date1", None, date1_list)
 Data.addVarStr("date2", 10)
Data.store("date2", None, date2_list)
 Data.addVarStr("date3", 10)
Data.store("date3", None, date3_list)
 Data.addVarStr("date4", 10)
Data.store("date4", None, date4_list)
 Data.addVarStr("date5", 10)
Data.store("date5", None, date5_list)
最后需要一个调用以上所有函数的函数,程序如下:
def GetData(page) : #获取一页的数据 
 html = GetSourceCode(page)
 stkcd_list, date1_list, date2_list, date3_list, date4_list, date5_list = GetList(html)
 Convert2dta(stkcd_list, date1_list, date2_list, date3_list, date4_list, date5_list)
end

以end命令结束,我们就完成了python的调用,即停止调用python。

注意在stata中调用python时,python代码依旧需要严格遵守缩进规则,注释也是python中的注释方式(本文用#注释)。

使用stata处理数据

现在只需要调用以上程序即可获得指定数据。接下来就是stata命令,循环190页,获得每一页的数据,然后保存:

forvalues i = 1/190 {
 clear
 python: GetData(`i')
 save "`i'.dta", replace
}

运行程序即可获得如图所示数据集:


python打开stata的data python读取stata数据_python 多层包多模块_05


然后合并数据集:

forvalues i = 1/190 {

append using "`i'.dta"

}

改变数据类型:

destring stkcd, replace //destring 将字符型数据转换为数值型数据

forvalues i = 1/5 {

gen PredictedDate`i' = date(date`i', "YMD") //生成新的变量存储日期

format %dCY-N-D PredictedDate`i' //指定格式为年月日

}

drop date1 - date5 //删除原来变量

因为有部分股票变更过预约时间,如图:


python打开stata的data python读取stata数据_json_06


所以需要如下处理:

gen PredictedDate = PredictedDate1 // PredictedDate为最终预约时间PredictedDate1为首次预约时间

forvalues i = 2/5 {

replace PredictedDate = PredictedDate`i' if PredictedDate`i' != .

} //对变更过的,令最终日期为最后一个非缺失值

format %dCY-N-D PredictedDate

order stkcd PredictedDate //最后将stkcd PredictedDate进行排序

sort PredictedDate //数据按最终预约披露时间PredictedDate排序

结果如图所示:


python打开stata的data python读取stata数据_json_07


到这里,我们就顺利的用stata调用python攻取了玉(时间数据),并且将数据存储到了stata的数据集里,进行了进一步的处理,最后得到了年报最新预约的披露日期。看到这里,对于这个新功能,你是不是心动啦,赶快拿出stata试一试吧!

完整程序

clear //清空内存
cap mkdir "D:爬虫A股年报披露时间" //cap mkdir
cd "D:爬虫A股年报披露时间"
python
def GetSourceCode(page) : #获取网页源代码
 import requests
 import time
 url = "http://www.cninfo.com.cn/new/information/getPrbookInfo"
 headers = {
 "Accept":"*/*",
 "Accept-Encoding":"gzip, deflate",
 "Accept-Language":"zh-CN,zh;q=0.9",
 "Connection":"keep-alive",
 "Content-Type":"application/x-www-form-urlencoded; charset=UTF-8",
 "Host":"www.cninfo.com.cn",
 "Origin":"http://www.cninfo.com.cn",
 "Referer":"巨潮资讯网",
 "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36",
 "X-Requested-With":"XMLHttpRequest"
 }
 postdata = {
 "sectionTime":"2019-12-31",
 "firstTime":"",
 "lastTime":"",
 "market":"szsh",
 "stockCode":"",
 "orderClos":"",
 "isDesc":"",
 "pagesize":20,
 "pagenum":page
 }
 html = requests.post(url, headers = headers, data = postdata)
 return html.text
def GetList(html) : #利用jsonpath模块解析网页源代码 
 import jsonpath #jsonpath模块用于获取多层嵌套字典的值,不需要一层层遍历获取
 true = True #正确即返回数据
 false = False
 page = eval(html) #eval函数就是将html转换为它原本的格式——字典
 stkcd_list = jsonpath.jsonpath(page['prbookinfos'], "$..seccode") #$从根节点开始,..指不管位置,选择符合条件的内容,此行为获取股票代码
 date1_list = jsonpath.jsonpath(page['prbookinfos'], "$..f002d_0102") #从根节点开始,获取所有Key为f002d_0102的值
 date2_list = jsonpath.jsonpath(page['prbookinfos'], "$..f003d_0102")
 date3_list = jsonpath.jsonpath(page['prbookinfos'], "$..f004d_0102")
 date4_list = jsonpath.jsonpath(page['prbookinfos'], "$..f005d_0102")
 date5_list = jsonpath.jsonpath(page['prbookinfos'], "$..f006d_0102")
 return stkcd_list, date1_list, date2_list, date3_list, date4_list, date5_list
def Convert2dta(stkcd_list, date1_list, date2_list, date3_list, date4_list, date5_list) : #将Python获取的数据存储到Stata中
 from sfi import Data 
 Data.setObsTotal(len(stkcd_list)) #设置数据属性
 Data.addVarStr("stkcd", 6) #添加stkcd变量
Data.store("stkcd", None, stkcd_list)#存储stkcd变量
 Data.addVarStr("date1", 10)
Data.store("date1", None, date1_list)
 Data.addVarStr("date2", 10)
Data.store("date2", None, date2_list)
 Data.addVarStr("date3", 10)
Data.store("date3", None, date3_list)
 Data.addVarStr("date4", 10)
Data.store("date4", None, date4_list)
 Data.addVarStr("date5", 10)
Data.store("date5", None, date5_list)
def GetData(page) : 
 html = GetSourceCode(page)
 stkcd_list, date1_list, date2_list, date3_list, date4_list, date5_list = GetList(html)
 Convert2dta(stkcd_list, date1_list, date2_list, date3_list, date4_list, date5_list)
end
forvalues i = 1/190 {
 clear
 python: GetData(`i')
 save "`i'.dta", replace
}
clear
forvalues i = 1/190 {
 append using "`i'.dta"
}
destring stkcd, replace //destring 将字符型数据转换为数值型数据
forvalues i = 1/5 {
 gen PredictedDate`i' = date(date`i', "YMD") //生成新的变量存储日期
 format %dCY-N-D PredictedDate`i' //指定格式为年月日
}
drop date1 - date5
gen PredictedDate = PredictedDate1 
forvalues i = 2/5 {
 replace PredictedDate = PredictedDate`i' if PredictedDate`i' != . //对变更过的,令最终日期为最后一个非缺失值
}
format %dCY-N-D PredictedDate //最后将变量排序
order stkcd PredictedDate //数据按最终预约披露时间排序
sort PredictedDate