利用stata调用python是stata16中的一个新增功能。对此,相信很多人和小编当初的想法一样,觉得该功能是多此一举。但是小编在深入了解学习之后发现,该功能简直是stata用户的福音。该功能使得,我们可以先利用python爬取数据,然后再利用用户所熟悉的stata去处理数据,因为stata在处理数据方面具有一定的优势。
那么今天我们就来看看,怎样利用stata调用python爬取数据,再用stata进行处理?今天试爬的数据是巨潮网上的预约年报的披露时间数据。
进入Python交互模式
首先做好准备工作,清空内存,创建好路径,进入路径,然后只需要输入python,即可进入python交互模式,具体程序如下:
clear
cap mkdir "D:爬虫A股年报披露时间"
cd "D:爬虫A股年报披露时间"
python
结果如图:
此时出现报错,报错信息提示,end命令缺失。这就是需要我们注意的地方,进入python交互模式之后,在dofile中的程序中不可以像之前stata程序一样一行一行运行,而必须将python和end命令(包括python和end命令)之间的所有行一起运行,即必须以end命令结尾。
Python爬取网络数据
(1)利用python爬取网页源代码
大家可以进入巨潮资讯网(http://www.cninfo.com.cn/new/index),点击上图的数据—>定期报告预约披露,可以看到该网页包含190页的数据,为了方便起见,今天只爬取这190页的数据。
为方便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模块
我们要获取的数据如图所示:
面对多层嵌套字典的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
}
运行程序即可获得如图所示数据集:
然后合并数据集:
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 // 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排序
结果如图所示:
到这里,我们就顺利的用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