数据接入框架,纯Golang(1.5+)编写:goDataAccess

jopen 8年前

数据接入框架,纯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.open-open.com/lib/view/home/1450709012620