提取信息时,因为批量下载工具下载的文件并不是按照股票代码命名,因此,首先必须将每个文件对应的股票代码识别出来,存放到Sas数据文件(file_code)中,我们用宏read_dm实现,提取标题信息则用宏read_lsgg实现,并保存到Sas数据文件lsgg1中(宏代码请参见附录)。
为了提取“共几页”的信息,并使程序具有通用性,我们设置标识pageNO,等于1则提取该信息并产生其它页面的url列表。具体程序代码由于较长,请参见附录。
3.4 下载其它页面临时公告
这一步是下载所有上市公司除第一页外的临时公告,操作方法和3.2一样,只不过这里是导入3.3产生的保存在E盘子目录“上市公司数据”的列表文件“临时公告其它页url列表.lst”。假设下载的临时公告文件保存在E:\downloads\lsgg
_page_other,注意这里产生的临时公告文件一定要和3.2产生的临时公告文件分开保存。
3.5 提取其它页的临时公告标题
这一步和3.3的原理一样,值得注意的是(1)要将提取的信息保存到另一个Sas数据文件(lsgg2_)中,以免将3.3中提取的信息覆盖了;(2)将pageNO标识设为空,因为不需要再提取“共几页”的信息;(3)存放批量下载工具下载文件的目录不再是E:\downloads\lsgg_page1,而是E:\downloads\lsgg_page_other。因此只需将附录中的Sas程序第2行至第4行
%let path=E:\downloads\lsgg_page1;
%let pageNO= 1;
%let gg=lsgg1;
改为
%let path=E:\downloads\lsgg_page_other;
%let pageNO= ;
%let gg=lsgg2_;
即可,其它不变,再次运行,即可完成其它提取其它页面的临时公告标题信息的任务,并保存到Sas数据文件lsgg2_中。
3.6 合并数据并查找减持公告
将两次提取的数据合并到lsgg中,代码如下:
Data lsgg; Set lsgg1 lsgg2_; Run;
至此,数据收集工作就完成了,所有上市公司的全部临时公告标题信息保存在Sas数据文件lsgg中,可以将该文件保存在适当的地方,以便今后使用。这个文件不仅可以用于识别减持,还可以用于其它很多方面,比如可转债的研究、收购兼并的研究,特别用事件研究方法研究一系列的公告效应时,这是非常有用的,因为我们可以提取准确的事件日期。
4 结论
当我们进行金融、会计研究时,如果商业数据库不能提供全部所需的数据,或者在没有购买商业数据库时,我们可以利用flastget、迅雷、网络蚂蚁等批量下载工具,结合使用Sas程序,可以以低成本的方式获得具有代表性的样本数据。本文结合如何收集上市公司“大小非”减持数据进行了实例说明,并在Sas8.2的环境下通过。这是我们在研究过程中的一些心得,我们拿出来和正在研究道路上辛勤探索的同仁们分享,虽然我们的收集数据的程序从效率上来说并不是最好的,但确实是有效的。希望能起到抛砖引玉的作用。
参考文献
[1] Whisenant, S., S. Sankaraguruswamy, and K. Raghunandan. Evidence on the joint determination of audit and non audit fees[J]. Journal of Accounting Research, 2003, 41(4), 721-744.
[2] 朱世武.SAS编程技术与金融数据处理[M].北京:清华大学出版社,2003.
[3] 朱世武.基于Sas系统的金融计算[M].北京:清华大学出版社,2004.
附录:提取上市公司第一页临时公告和“共几页”信息的Sas程序代码 option nosource nodate nonotes;
%let path=E:\downloads\lsgg_page1;
%let pageNO= 1;
%let gg=lsgg1;
%let url=http://company.p5w.net/gszl/lsgg.asp?pageNo=;
filename filelist pipe "dir &path. /b";
data filename; length filename $30.; infile filelist;
input filename @@;
if substr(filename,length(filename)-3,4)='.asp' ;
file "&path.\t.txt"; put '%read_dm(' filename ');';
run;
data file_code; delete; run;
%macro read_dm(fname);*将下载的文件与上市公司对应;
data temp;
length filename $50; filename="&fname." ;
infile "&path.\&fname."; input line $char256. @@;
if substr(line,1,7)='
n=_n_;name=substr(line,8,index(line,'(')-8);
code=substr(line,index(line,'(')+1,6);end;
if n>0;
drop n line;
run;
data file_code; set file_code temp; run;
%mend read_dm;
%include "&path.\t.txt";
data file_code; set file_code; if code=' ' then delete;
file "&path.\tt.txt"; put '%read_lsgg(' filename ',' name ',' code ');'; run;
proc sql;
create table lsgg(code char(6) format=$6. label='股票代码',
name char(8) format=$8. label='股票简称',
date num format=yymmdd10. label='公告日期',
lsgg char(200) format=$200. label='临时公告');
quit;
data urllst2_; delete; run;
%macro read_lsgg(hf_name, hname, hcode);*提取临时公告标题信息;
%if &pageNO.=1 %then %do;
data temp; code="&hcode.";
infile "&path\&hf_name." lrecl=850;
input line $char850.@@;
if index(line,"当前第")>0 then do;
n=substr(scan(line,1,'页'), length(scan(line,1,'页')),1);
sumn=scan(scan(line,2,'页'),2,'共'); output; end;
drop line; run;
data urllst2_; set urllst2_ temp; run;
%end;
data temp ; length code $6. name $8.;
code="&hcode.";name="&hname.";
format date yymmdd10.; length lsgg $200.;
retain n;
infile "&path.\&hf_name." lrecl=850;
input line $char850.@@;
if line='' then return;
if index(line,"公司临时公告")>0 then n=_n_ ;
else if index(line,"当前第")>0 then n=.;
if index(line,'href')>0 then nn=_n_; else nn=.;
if n>0 and nn>0 then do;
lsgg=tranwrd(scan(line,3,'>'),'
if index(line,'-')>0 then date=mdy(scan(line,2,'-'),scan(scan(line,3,'-'),1,'/'),substr(scan(line,1,'-'),length(scan(line,1,'-'))-3,4));
output;end;
drop line n nn;
run;
proc append base=lsgg data=temp;
%mend read_lsgg; %include "&path.\tt.txt";
proc delete data=temp filename file_code;
run;
%macro url;
%if &pageNO.=1 %then %do;
data urllst2_; set urllst2_; length url $100.;
if sumn=1 or n>=2 then return;
do j=2 to sumn;
url="&url."||trim(left(j))||'&zqdm='||code;
output;end; run;
data urllst2_; set urllst2_;
file "E:\上市公司数据\临时公告其它页url列表.lst";