-
Notifications
You must be signed in to change notification settings - Fork 14
Home
数据接入框架,纯Golang(1.5+)编写。
你肯定碰到过数据抓取的相关问题,比如臃肿的规则、与业务无关的多进程多线程逻辑、访问被服务器限制、模拟登陆、浏览器识别等等。goDataAccess旨在缓解数据抓取的痛点,让开发者更加舒适的抓取到想要的内容。
数据接入听起来并不是那么接地气,简单的说是抓取、抽取、入库等一系列操作的集合。最终将我们想要的内容存储下来。为啥要数据接入?出于各种各样的原因,总是需要一些网络上的资源。我们希望把网络上的资源接入进现有的服务中来,以提供更好的服务。如果你所从事的是科研工作,则更加避免不了数据的抓取了,因为你所提出的模型总是需要进行实验验证的。所以,goDataAccess值得你花3-5分钟的时间尝试一下:)
goDataAccess主要由三部分组成,spider、agent、da。

spider的主要功能是抓取,这里实现了一种类似Scrapy的抓取框架。agent是代理模块,基于goDataAccess/spider开发,通过cli.go完成代理的更新、验证和代理服务(RPC)的启动。da基于goDataAccess/spider和goDataAccess/agent,可以使用提供的API完成特定业务的数据接入工作。
spider是一个抓取框架,类似Python下的Scrapy,架构图如下所示。如果你使用过Scrapy,则很容易的使用goDataAccess/spider。

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(目前提供的配置参数有这些)等。
你可能会有疑惑,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完成页面的解析功能,engine默认会使用LazyProcesser,即返回整个页面。你也可以编写自己的Processer完成特定内容的抽取。最终抽取的内容需要通过AddItem方法告诉engine。(为了简化Processer的编写,后面会有QuickEngine和extractor哦,不要走开)
downloader通常情况下不需要重写,主要负责页面的下载。scheduler是一个内存队列,通常也不需要修改。可以通过SetDownloader、SetScheduler来设置自定义的模块。
为了简化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对现有的模块进行了封装。通过加载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主要为spider提供代理服务(也可以提供给其他的程序,协议为http),架构如下。

可以通过agent/run_agent.go启动代理更新和验证,通过agent/run_server.go启动代理服务(需要配合spider的proxy_plugin.go使用,可以访问http://127.0.0.1:1234查看可用代理)。
agent内置了代理抓取规则,代理更新基于rule/update.json,代理验证基于rule/validate.json。通过查看rule下的文件,可以发现,代理的更新和验证基于quick_engine编写。
proxy_plugin.go的使用,可以参考百度百科的抓取。
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中。