本帖研究網(wǎng)頁為'http://health.gmw.cn/2012-10/03/content_5266132.htm',意在提取該網(wǎng)頁中全國各省降雨量信息,部分截圖如下:
大致步驟就是用filename fileref url '網(wǎng)頁地址'獲取網(wǎng)頁代碼信息(包含有待提取數(shù)據(jù)),再用infile fileref將字符代碼讀入變量中,接著根據(jù)待提取數(shù)據(jù)的特點(diǎn)對(duì)寫入的觀測進(jìn)行“數(shù)據(jù)清洗”,最后獲得所需數(shù)據(jù)觀測。
先針對(duì)該過程中可能出現(xiàn)的問題,做一下簡單說明:
1.本人所用SAS軟件為多國語言9.2版,剛開始運(yùn)行含有filename fileref url '網(wǎng)頁地址'及infile fileref時(shí),很不友好的顯示錯(cuò)誤:無法連接主機(jī)。這一問題困惑我好久。最后看到有前輩發(fā)帖,從一個(gè)網(wǎng)站http://ftp.sas.com/techsup/download/hotfix/f9_sbcs_prod_list.html#034098下載相關(guān)hot fix(F9BA26)以后,得以解決。
2.若未在infile語句中加encoding='utf-8',得出的觀測亂碼。
3.正則表達(dá)式并不是必須的,但是用起來簡潔明了,與一些字符函數(shù)配合使用,絕對(duì)可以達(dá)到你想要的提取目的。
4.大家進(jìn)入網(wǎng)頁后,點(diǎn)擊右鍵,查看源代碼(有些是源文件),這個(gè)源代碼就是我們需要寫入數(shù)據(jù)集的文件。先用
filename fileref url 'http://health.gmw.cn/2012-10/03/content_5266132.htm';
5.怎樣將網(wǎng)頁源文件代碼寫入數(shù)據(jù)集?用infile+input。不過根據(jù)寫入方式不同,后續(xù)清洗數(shù)據(jù)的程序自然也不一樣了。由于源代碼中每一個(gè)input line的形式為<...>!!!<...>或者<...><...>(大家可以觀察網(wǎng)頁的源代碼),而我們需要的數(shù)據(jù)就包含在!!!里面。而由于一個(gè)網(wǎng)頁包含的信息太多,也有可能找到的!!!不包含所需數(shù)據(jù)。為了“清洗”數(shù)據(jù)方便,在這里我采用了一個(gè)比較笨的方法,通過觀察源代碼中待提取數(shù)據(jù)的大致范圍,如第一個(gè)待提取字符串"黑龍江"出現(xiàn)在第184個(gè)input line,而最后一個(gè)"120”(澳門人均降水) 則出現(xiàn)在第623個(gè)input line,其他input line我們不需要,可以考慮在infile語句中加入firstobs=184 obs=623。
注意:由于網(wǎng)頁可能發(fā)生小的變化,firstobs=與obs= 的值可能不準(zhǔn)確,從而影響結(jié)果。建議查看源代碼確定相應(yīng)值。
這里介紹兩種不同的寫入方式。
a.以'>'為分隔符,寫入后每個(gè)觀測就形如<...或者!!!<...,而后者是我們所需保留的觀測。根據(jù)!!!<...寫出對(duì)應(yīng)正則表達(dá)式進(jìn)行清洗。考慮用正則表達(dá)式'/.+/'。
此種方式編程如下:
/*.............................................................................................................................*/
filename fileref url 'http://health.gmw.cn/2012-10/03/content_5266132.htm';
data a;
infile fileref lrecl=10000 dlm='>' encoding='utf-8' firstobs=184 obs=623;
length text $1000;
input text $ @@;
run;
data newa;
if _n_=1 then prx=prxparse('/.+</');
retain prx;/*必須要用retain 否則下次循環(huán)時(shí)prx置為空值而產(chǎn)生錯(cuò)誤*/
set a;
if prxmatch(prx,text);/*篩選那些不符合正則表達(dá)式形式的觀測值*/
text=substr(text,1,find(text,'<')-1);/*從合適觀測中提取所需數(shù)據(jù)的字符形式*/
drop prx;
run;
/*.................................................................................................................................*/
b.源代碼文件中每一個(gè)input line整體作為一個(gè)值,這樣就保留了原來形式<...>!!!<...>或者<...><...>,根據(jù)>!!!<寫出對(duì)應(yīng)表達(dá)式進(jìn)行清洗?紤]用正則表達(dá)式'/>.{1,8}</'(數(shù)據(jù)位數(shù)最多為8)。
此種方式編程如下:
/*................................................................................................................................*/
filename fileref url 'http://health.gmw.cn/2012-10/03/content_5266132.htm';
data b;
infile fileref lrecl=10000 encoding='utf-8' firstobs=184 obs=623 length=len;
input text $varying1000. len;
run;
data newb;
if _n_=1 then prx=prxparse('/>.{1,8}</');
retain prx;
set b;
call prxsubstr(prx,text,position,length);
if position;
text=substrn(text,position+1,length-2);
keep text;
run;
/*...............................................................................................................................*/
以上兩種方式主要看各位的習(xí)慣吧。得到了篩選后的數(shù)據(jù)集work.newa(work.newb),數(shù)據(jù)集只含有1個(gè)變量text。而網(wǎng)頁中則有6個(gè)變量。這是就需要對(duì)數(shù)據(jù)集work.newa做寫什么了。
法1.set操作:
/*.................................................................................................................................................................*/
data new;
set newa(rename=(text=text1) firstobs=1);
set newa(rename=(text=text2) firstobs=2);
set newa(rename=(text=text3) firstobs=3);
set newa(rename=(text=text4) firstobs=4);
set newa(rename=(text=text5) firstobs=5);
set newa(rename=(text=text6) firstobs=6);
if not anydigit(text1);
label text1='名稱(1)' text2='人口' text3='面積' text4='年降水量' text5='總降水量' text6='人均降水';
run;
/*.............................................................................................................................................................*/
注意:為避免重復(fù),上述6個(gè)set語句完全可以用宏語句來代替,程序如下:
%macro t(n);
%do i=1 %to &n;
%str(set n(rename=(text=text&i) firstobs=&i);)
%end;
%mend;
data new;
%t(6)
if not anydigit(text1);
label text1='名稱(1)' text2='人口' text3='面積' text4='年降水量' text5='總降水量' text6='人均降水';
run;
法2.分組transpose:
/*...............................................................................................................................................................*/
data t;
set newa;
f=ceil(_n_/6);/*引入新變量f作為分組變量*/
run;
proc transpose data=t out=new(drop=_name_ f) prefix=text;
var text;
by f;/*由于數(shù)據(jù)集t中f已經(jīng)按序排列,故不必再用sort過程*/
label text1='名稱(1)' text2='人口' text3='面積' text4='年降水量' text5='總降水量' text6='人均降水';
run;
/*...............................................................................................................................................................*/