數據接入框架,純Golang(1.5+)編寫:goDataAccess

jopen 10年前發布 | 24K 次閱讀 Google Go/Golang開發 goDataAccess

數據接入框架,純Golang(1.5+)編寫。

簡介

你肯定碰到過數據抓取的相關問題,比如臃腫的規則、與業務無關的多進程多線程邏輯、訪問被服務器限制、模擬登陸、瀏覽器識別等等。goDataAccess旨在緩解數據抓取的痛點,讓開發者更加舒適的抓取到想要的內容。

數據接入聽起來并不是那么接地氣,簡單的說是抓取、抽取、入庫等一系列操作的集合。最終將我們想要的內容存儲下來。為啥要數據接入?出于各種各樣的 原因,總是需要一些網絡上的資源。我們希望把網絡上的資源接入進現有的服務中來,以提供更好的服務。如果你所從事的是科研工作,則更加避免不了數據的抓取 了,因為你所提出的模型總是需要進行實驗驗證的。所以,goDataAccess值得你花3-5分鐘的時間嘗試一下:)

架構

goDataAccess主要由三部分組成,spider、agent、da。

數據接入框架,純Golang(1.5+)編寫:goDataAccess

spider的主要功能是抓取,這里實現了一種類似Scrapy的抓取框架。agent是代理模塊,基于goDataAccess/spider開 發,通過cli.go完成代理的更新、驗證和代理服務(RPC)的啟動。da基于goDataAccess/spider和goDataAccess /agent,可以使用提供的API完成特定業務的數據接入工作。

Spider

spider是一個抓取框架,類似Python下的Scrapy,架構圖如下所示。如果你使用過Scrapy,則很容易的使用goDataAccess/spider。

數據接入框架,純Golang(1.5+)編寫:goDataAccess

https://github.com/zhangxiaoyang/goDataAccess/tree/master/spider/example里有示例,可以幫助你快速的編寫一個爬蟲,下面的代碼片段均來自于此。

spider中最重要的是engine,因為啟動一個爬蟲就意味著啟動一個engine,比如這樣子:

engine.NewEngine("crawl_baidu_and_print_it").SetStartUrl(url).Start()

通過SetXXX方法可以設置自定義的模塊,比如SetDownloader、SetProcesser、SetPipeline、SetStartUrls、SetStartUrl、SetConfig(目前提供的配置參數有這些)等。

pipeline

你可能會有疑惑,engine會把結果輸出到哪里呢?所以,你可以這樣(結果會被輸出到控制臺):

engine.NewEngine("crawl_baidu_and_print_it").SetStartUrl(url).AddPipeline(pipeline.NewConsolePipeline()).Start()

目前,pipeline提供FilePipeline和ConsolePipeline兩種輸出,你還可以編寫自己的pipeline,最后通過 AddPipeline方法告訴engine即可。還有一個SetPipeline方法在某些情況下會派上用場,該方法會刪除之前AddPipeline 添加的所有pipeline,并設置為此次調用所指定的pipeline。

processer

processer完成頁面的解析功能,engine默認會使用LazyProcesser,即返回整個頁面。你也可以編寫自己的 Processer完成特定內容的抽取。最終抽取的內容需要通過AddItem方法告訴engine。(為了簡化Processer的編寫,后面會有 QuickEngine和extractor哦,不要走開)

downloader / scheduler

downloader通常情況下不需要重寫,主要負責頁面的下載。scheduler是一個內存隊列,通常也不需要修改。可以通過SetDownloader、SetScheduler來設置自定義的模塊。

extractor

為了簡化Processer的編寫,spider內置了一個基于正則表達式的抽取模塊extractor。extractor有兩個重要的方法,SetScopeRule和SetRules。對于百度百科詞條詳情頁的抽取,使用如下:

items := extractor.NewExtractor().
    SetScopeRule(`(?s)<dt class="basicInfo-item name">.*?</dd>`).
    SetRules(map[string]string{
    "key":   `(?s)name">(.*?)</dt>`,
    "value": `(?s)value">(.*?)</dd>`,
}).
Extract(resp.Body)

SetScopeRule會將頁面分割成若干個相同的Scope,每一個Scope都符合規則(?s)<dt class="basicInfo-item name">.*?</dd>,然后再對每一個Scope執行SetRules的操作,這里會提取2個詞,第一個詞的規則是(?s)name">(.*?)</dt>,第二個詞的規則是(?s)value">(.*?)</dd>, 最終將結果轉換為items。因為每一個item都是key-value的結構,所以抽取的每一個詞都需要一個屬性名稱,這里分別叫做“key”、 “value”。extractor還提供其他的方法,比如TrimHtmlTags,該方法會剔除抽取內容中的html標簽,TrimBlank會剔除 首尾的所有空白字符。

quick_engine

可擴展在一定程度上就以為著繁瑣,鑒于此,quick_engine對現有的模塊進行了封裝。通過加載JSON配置文件可以直接啟動spider,比如這樣:

engine.NewQuickEngine("crawl_baidubaike_with_quickengine.json").Start()

一個典型的配置文件如下:

{
    "task_name": "crawl_baidubaike_with_quickengine",
    "start_urls": [
        "http://baike.baidu.com/view/3179.htm",
        "http://baike.baidu.com/subview/2632/19244814.htm"
    ],
    "rules": [
        {
            "url_match": "http://baike.baidu.com/view",
            "base_url": "http://baike.baidu.com",
            "item_rule": {
                "scope_rule": "(?s)<dt class=\"basicInfo-item name\">.*?</dd>",
                "kv_rule": {
                    "key": "(?s)name\">(.*?)</dt>",
                    "value": "(?s)value\">(.*?)</dd>"
                },
                "trim_func": "trim_html_tags"
            },
            "request_rule": {
                "scope_rule": "(?s)<ul class=\"slider maqueeCanvas\">.*?</ul>",
                "kv_rule": {
                    "url1": "href=\"(.*?)\""
                },
                "trim_func": "trim_html_tags"
            },
            "merge": true
        },
        {
            "url_match": "http://baike.baidu.com/subview",
            "base_url": "http://baike.baidu.com",
            "item_rule": {
                "scope_rule": "(?s).*",
                "kv_rule": {
                    "name": "(?s)<dd class=\"lemmaWgt-lemmaTitle-title\">.*?<h1>(.*?)</h1>.*?</dd>"
                },
                "trim_func": "trim_html_tags"
            },
            "request_rule": {
                "scope_rule": "(?s)<ul class=\"slider maqueeCanvas\">.*?</ul>",
                "kv_rule": {
                    "url1": "href=\"(.*?)\""
                },
                "trim_func": "trim_html_tags"
            },
            "merge": true
        }
    ],
    "output_file": "crawl_baidubaike_with_quickengine_output.txt",
    "config": {
        "concurrency": 20,
        "succ": "baidu"
    }
}

需要說明的是,request_rule表示從當前頁面抽取url并放入到scheduler中,當抽取的url為相對路徑時,會自動使用 base_url為前綴。scope_rule對應于extractor的SetScopeRule,kv_rule對應于SetRules。對于 request_rule的kv_rule,規則的key可以隨便指定,此處指定的是url1。merge=true表示將得到的多個item一起輸出 (list形式),merge=false則表示每一個item都單獨輸出(dict形式)。配置文件中的rules為一個列表,可以指定多個規則,規則 是否觸發根據url_match來判斷,url_match是一個正則表達式。多個規則根據url_match自上而下匹配,匹配成功則不再繼續向下匹 配。

Agent

可以通過agent/cli.go使用agent。

go run cli.go update # fetching free proxies
go run cli.go validate 'http://m.baidu.com' 'baidu' # picking available proxies which can be used to visit 'http://m.baidu.com'. If response bodies from proxies do not contain 'baidu', proxies will not be picked.
go run cli.go serve # RPC service at 127.0.0.1:1234

update、validate命令無需完全執行完,根據需求即可。agent內置了代理抓取規則,默認update命令會讀取該規則。可以通過添 加規則文件到agent/rule,格式需為update.xxx.json。validate則基于rule/validate.json執行。 update和validate命令基于quick_engine編寫。

最后通過serve命令啟動RPC服務,地址為127.0.0.1:1234。可以使用spider內置的plugin,即proxy_plugin.go,可以通過其與agent服務連接,參考百度百科的抓取

DA

da為數據接入模塊,可以使用spider和agent提供的API完成特定業務的數據接入工作。da中會不斷加入基于spider和agent編寫的數據接入代碼,目前有baike.baidu.com和bgp.he.net的示例代碼。

抓取bgp.he.net需要模擬瀏覽器,即包括Cookie和Javascript等認證操作。為此,spider內置了cookie_plugin.go,使用見https://github.com/zhangxiaoyang/goDataAccess/tree/master/da/bgp.he.net/bin/spider.go中。


項目主頁:http://www.baiduhome.net/lib/view/home/1450709012620

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!