集算器 SPL 抓取網頁數據

【摘要】
      集算器 SPL 支持抓取網頁數據,根據抓取定義規則,可將網頁數據下載到在本地進行統計分析。具體定義規則要求、使用詳細情況,請前往乾學院:集算器 SPL 抓取網頁數據!

網站上的數據源是我們進行統計分析的重要信息源。當我們瀏覽網頁,看到自己感興趣數據內容時,希望能夠快速抓取網頁上的數據,這對於數據分析相關工作來說極其重要,也是必備的技能之一。但是網絡數據抓取大多需要複雜的編程知識,操作也比較繁瑣。這裏介紹如何用集算器 SPL 快速抓取網頁數據。

1、基本流程圖
2、抓取網頁數據接口
3、定義規則
   A、web_info
   B、init_url
   C、help_url
   D、target_url
   E、page_url
4、抓取股票歷史數據
5、用戶自定義程序
   A、數據提取程序接口
   B.數據保存程序接口
   C、數據提取程序樣例
   D、數據保存程序樣例
   E、自定義程序的使用

1、基本流程圖

從給定的開始地址進行遍歷,將解析過濾後的網址放入下載地址隊列,分成網址頁 help_url 與下載頁 target_url, 網址頁只收集網址,下載頁即能收集網址,也能提取數據,把提取到的數據保存起來。抓取網頁數據直到遍歷地址爲空,則抓取工作結束。

2、抓取網頁數據接口
      web_crawl(jsonstr) 是抓取網頁數據接口,參數 jsonstr 是定義規則的字符串,抓取數據時,根據定義規則遍歷 URL、下載、提取、保存相關內容數據。
      本接口依賴集算器外部庫 webcrawlCli。它缺省安裝在集算器軟件的 esProc\extlib\webcrawlCli 路徑下,在集算器的外部庫設置中勾選 webcrawlCli 項, 重啓集算器後,就可以使用 web_crawl 接口。

web_crawl 簡單用法,如抓取指定股票數據,SPL 腳本 demo.dfx:

獲取股票代碼 600000 的數據文件:

文件內容:

3、定義規則
根據基本流程圖,將定義規則分成網站信息、初始網址、網址頁、下載頁、提取數據五部分。具體內容如下:
[
{web_info:{domain:‘www.banban.cn’, save_path:‘d:/tmp/data/webmagic’, thread_size:2, cookie:{name:“jacker”, laster:“2011”},
user_agent:‘Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:39.0) Gecko/20100101 Firefox/39.0’}},
{init_url:[‘_cybs.htmlhttps://www.banban.cn/gupiao/list’, ‘_sh.htmlhttps://www.banban.cn/gupiao/list’]},
{help_url:[‘gupiao/list_(sh|sz|cyb)\.html’, ‘/shujv/zhangting/’, ‘/agu/$’]},
{target_url:{reg_url:‘/agu/365\d’}},
{target_url:{filter:‘gupiao/list_(sh|sz|cyb)\.html’, reg_url:‘gupiao/[sz|sh]?(60000\d)/’,new_url:‘http://www.aigaogao.com/tools/history.html?s=%s’}},
{page_url:{filter:‘history.html\?s=\d{6}’, extractby: “//div[@id=‘ctl16_contentdiv’]/”}},
{page_url:{extractby: “//div[@id=‘content_all’]/”}},
{page_url:{filter:‘/agu/365\d’, extractby: “//div[@id=‘content’]/”}}
]

規則簡要說明:
web_info:網站信息, 根據要下載的網站,設置域名、本地存儲位置、用戶代理信息、用戶自定義程序等相關的信息。
init_url:初始網址, URL 遍歷的入口網址。
help_url:網址頁, 定義網址頁規則,收集網頁內容中的 URL,但不提取此頁面數據內容。
target_url:下載頁, 定義下載頁規則,收集網頁內容中的 URL,同時也提取此頁面的內容。
page_url:提取數據, 定義頁面內容提取規則,在下載頁 target_url 中根據此規則提取內容。

注意: json 書寫結構細節,節點 {} 中的 [] 表示 list 列表,節點 {} 中的 {} 表示 map 鍵值結構,書定時要注意,否則書寫不對易引起解析錯誤。

定義規則說明

A、web_info
設置要下載的信息,內容包括:
domain:設置域名。
save_path:文件存儲路徑。
user_agent:指用戶代理信息。 作用: 使服務器能夠識別客戶使用的操作系統及版本、CPU 類型、瀏覽器及版本、瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等。
sleep_time:抓取間隔。
cycle_retry_times:重試次數。
charset:設置編碼。
use_gzip:是否爲 gzip 壓縮。
time_out:抓取超時設置。
cookie_name:cookie 信息,鍵值結構。
thread_size:抓取時線程數。
save_post:是否要爲存儲的文件名稱追加編碼串,以防網名文件被覆蓋,缺省值爲 true。如 books/a.html, music/a.html, 都是要下載的頁面,保存時若此參數爲 true, 則存儲文件名分別爲 a_xxxcgk.txt,a_xabcdw.txt,文件不會被覆蓋;若爲 false, 保存文件名爲 a.txt, 後存儲的就會將已存在的同名文件覆蓋。
class_name:用戶自定義的存儲類。
class_argv:傳遞給 class_name 類的字符串參數。

B、init_url
初始的 URL。
爲 List 列表結構,可設置多個 URL.

C、help_url
網址頁主要是定義要收集的 URL 過濾規則, 符合規則的 URL 會被加入下載網址隊列,但是不會提取其具體內容。過濾規則支持正則表達式,如:
gupiao/list_(sh|sz|cyb)\.html 表示 URL 中只有包括字符串 gupiao/list_sh.html、gupiao/list_sz.html、gupiao/list_cyb.html 鏈接才能通過。
爲 List 列表結構,可定義多個規則。

D、target_url
下載頁是要抓取內容數據的 URL,需要從這個頁面裏提取內容。若此 URL 符合 help_url 過濾規則,那麼也會在本頁面中收集 URL。
約定定義規則格式:
{target_url:{filter: pageUrl, reg_url:urlRegex, new_url:newUrl}},
表示在符合 pageUrl 條件的頁面中,找出符合 urlRegex 條件的 href 鏈接,若 newUrl 定義了,則可與 urlRegex 過濾結果組合成新的 URL。
例如在頁面中找到鏈接 a_100.html 符合過濾條件 reg_url=a_(\d+)\.html, 則有 newUrl=b_%s.php, 那麼 urlRegex 過濾 a_100.html 的結果爲 100, 將與 newUrl 合併,新的下載頁爲 b_100.php。
其中 filter 表示定義過濾的 URL 規則;若無此定義,表示所有的 target_url 都要用此規則。
reg_url 表示要收集的 URL 規則,必寫;無 reg_url 的 target_url 規則則無意義。
new_url 表示定義新的頁面,需要與 reg_url 過濾結果結合成新的 URL。

舉例說明:
3.1 定義規則:{target_url:{filter:‘gupiao/list_(sh|sz|cyb)\.html’, reg_url:‘gupiao/([sz|sh]?6000\d{2})/’,new_url:‘http://www.raqsft.com/history.html?s=%s’}}
在下載頁 gupiao/list_sh.html 中包含如下內容:

  • 包鋼股份 (600010)
  • 四川路橋 (600039)
  • 保利地產 (600048)

A、gupiao/list_sh.html 符合 filter 條件
B、href 串符合 reg_url 條件,將產生 [600010, 600039, 600048]
C、過濾結果與 newUrl 生成新的 URL:
http://www.raqsft.com/history.html?s=600010
http://www.raqsft.com/history.html?s=600039
http://www.raqsft.com/history.html?s=600048
new_url 中的 %s 爲合併字符串的佔位符。

3.2 定義規則:{target_url:{reg_url:‘/ gupiao/60001\d’}},

在下載頁 gupiao/list.html 中包含如下內容:

  • 包鋼股份 (600010)
  • 四川路橋 (600039)
  • 保利地產 (600048)

href 中符合 reg_url 條件的,則收集到的 URL 爲: http://www.xxx.com/gupiao/600010/ 其它兩個 href 不符合過濾條件。 設置 filter 是爲了在過濾後的頁面中去收集 URL, 當 help_url 多時,過濾後縮小了範圍,提高了效率。 target_url 規則可定義多條,以適應不同的條件。

E、page_url
提取數據,主要作用於下載頁面內容提取,它表示使用這個抽取規則,將提取到的結果保存。定義此規則參考 xpath 使用說明。它只提取主要內容,但對內容細節還需要 className 類來抽取。
約定定義規則格式:
{page_url:{filter: pageUrl, extractby: contentReg, class: className }},
其中 filter 表示符合過濾條件的 url 規則,若無此定義,表示所有的 target_url 都要用此規則。
extractby 表示頁面內容提取規則。若定義 class,表示由 className 類執行內容提取;若 className=
”default”,  表示用當前缺省方式提取,也就是針對 table 表中的內容提取數據。若缺省提取不滿足需求,用戶可自定義類來實現,具體實現參考後面用戶自定義程序。
例如:extractby :“//div[@class=news-content]/text()”,從網頁中提取此節點下的數據。

page_url 可針對不同的頁面制定不同的規則。通過 filter 過濾後的頁面中去提取數據,減少要處理的 URL 數量,當 target_url 多時,能提高效率。

若無 extractby 規則,則表示提取 target_url 頁面中所有的內容。
若定義了多條 page_url 規則 ,則首個符合規則的內容將被提取。
假如 A 頁面內容的符合規則 R1,R2,R3, 提取內容時首先是 R2,則不再根據 R1、R3 規則提取數據。
說明:若沒有定義 target_url 規則,但當前頁面有適合的 page_url 規則,則此頁面的內容也會被提取。

4、抓取股票歷史數據

下面用抓取股票歷史數據來說明,web_crawl() 接口是如何應用的。基本操作:先獲取股票代碼,然後通過股票代碼查詢歷史數據,從下載頁面中提取數據後保存。A、在https://www.banban.cn/gupiao/list_xxx.html 頁面 help_url 提取上證、深證、創業板的股票代碼。
B 、將股票代碼與http://www.aigaogao.com/tools/history.html?s=%s 結合,生成需要下載網址 target_url.
C 、針對下載頁 target_url 中的內容提取。

D、顯示提取後的內容。

SPL 實現代碼 Stock.dfx:

加載其中的股票 600010 數據爲:

5、用戶自定義程序
      對於內容提取,缺省提供了對 html 中的 table 內容進行抽取。 但是世界上沒有千篇一律的網頁一樣,也沒有一勞永逸的提取算法。在使用網頁數據抓取過程中,你會碰到各種類型的網頁,這個時候,你就要針對這些網頁,來實現對應抽取方法。存儲方式類似,缺省提供的是文件保存,若想其它方式如數據庫存儲,還需要用戶自己開發程序。參考下面接口,可將自定義程序融入網頁數據抓取流程中。

A、數據提取程序接口

下載頁的內容組織形式多樣,各具不同,爲了適應更多的內容提取需求,用戶可自定義提取數據程序。
接口程序:
package com.web;

import us.codecraft.webmagic.Page;
public interface StandPageItem {
// 數據提取處理。
void parse(Page p);
}

需要實現 com.web.StandPageItem 接口 parse(Page p),數據提取在此實現。

B、數據保存程序接口
提取數據存儲方式種類繁多,各具不同,爲了適應更多的數據存儲需求,用戶可自定義數據存儲程序。
接口程序:
package com.web;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import us.codecraft.webmagic.pipeline.Pipeline;

public interface StandPipeline extends Pipeline {
    public void setArgv(String argv);
    public void process(ResultItems paramResultItems, Task paramTask);
}
同樣需要實現 com.web.StandPipeline 類中的 setArgv(), process()。
setArgv()輸入參數接口,process() 處理存儲數據接口。

C、數據提取程序樣例
實現 com.web.StandPage 接口 parse(Page p),
參考代碼:
package com.web;
import java.util.List;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.selector.Selectable;

public class StockHistoryData implements StandPageItem{
    @Override
    public void parse(Page page) {
         StringBuilder buf = new StringBuilder();
          List nodes = page.getHtml().xpath(“table/tbody/”).nodes();
          for(Selectable node:nodes){
              String day = node.xpath(“//a/text()”).get();
              List title = node.xpath(“//a/text() | tr/td/text()”).all();
              if (title.size()<5) continue;
              String line = title.toString().replaceFirst(“, ,”, “,”);
              buf.append(line+“\n”);
          }
          page.putField(“content”, buf.toString());
    }
}

將要保存的數據存放到 page 的字段 "content" 中,在保存處理時,將從字段 "content" 中獲取。

D、數據保存程序樣例
實現 com.web.StandPageline 類中的 setArgv(),process()
參考代碼:
package com.web;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import us.codecraft.webmagic.ResultItems;
import us.codecraft.webmagic.Task;
import org.apache.commons.codec.digest.DigestUtils;
import us.codecraft.webmagic.utils.FilePersistentBase;
public class StockPipeline extends FilePersistentBase implements StandPipeline {
    private Logger logger = LoggerFactory.getLogger(getClass());
    private String m_argv;
    private String m_path;   
    public static String PATH_SEPERATOR = “/”;
 
    static {
      String property = System.getProperties().getProperty(“file.separator”);
      if (property != null) {
        PATH_SEPERATOR = property;
      }
    }
   
    public StockPipeline() {
         m_path = “/data/webcrawl”;
    }
    // 獲取存儲路徑與存儲文件名前綴
    public void setArgv(String argv) {
         m_argv = argv;
         if (m_argv.indexOf(“save_path=”)>=0){
             String[] ss = m_argv.split(“,”);
             m_path = ss[0].replace(“save_path=”, ““);
             m_argv = ss[1];
         }
    }
   
    public void process(ResultItems resultItems, Task task) {
         String saveFile = null;
         Object o = null;
         String path = this.m_path + PATH_SEPERATOR + task.getUUID() + PATH_SEPERATOR;
         try {
         do{
             String url = resultItems.getRequest().getUrl();
             o = resultItems.get(“content”);
             if (o == null){
                  break;
             }
            
             int start = url.lastIndexOf(”/”);
             int end = url.lastIndexOf(“?”);
             if (end<0){
                  end=url.length();
             }  
            
             String link = url.substring(start+1, end);
             if (m_argv!=null && !m_argv.isEmpty()){
                 link = m_argv+“_”+link;
             }
             if (link.indexOf(“.”)>=0){
                 link = link.replace(“.”, “”);
             }
            // 加 md5Hex 爲防止重名
             String hex = DigestUtils.md5Hex(resultItems.getRequest().getUrl());
             saveFile = path + link+“
”+ hex +“.json”;
         }while(false);
         if (saveFile!=null){
             PrintWriter printWriter = new PrintWriter(new FileWriter(getFile(saveFile)));
             printWriter.write(o.toString());
             printWriter.close();
         }
         } catch (IOException e) {
             logger.warn(“write file error”, e);
         }
    }
}

E、自定義程序的使用
      將上述接口文件及 java 文件編譯後打包成 webStock.jar 文件,放在 esProc\extlib\webcrawlCli 路徑下重啓集算器。數據存儲程序,在 web_info 中配置;數據提取程序,在 page_url 中配置。下面是加載兩個自定義類程序的 dfx 腳本。
SPL 代碼腳本 mytest.dfx:

生成結果:

類似針對內容提取或數據存儲,參考上面程序的實現,用戶可自定義 java 程序。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章