您的位置:首页 > 其它

[开源 .NET 跨平台 数据采集 爬虫框架: DotnetSpider] [二] 最基本,最自由的使用方式

2016-05-24 23:47 691 查看
上一篇大致 介绍了一下爬虫的框架设计,从这一篇开始着重介绍如何使用这个爬虫。

数据抽取定义

之前也有人反应说用Attribute+模型来定义抽取规则太花哨,实用性不强。实际上可能他没有仔细看到我的设计,我的核心抽取不是Attrbiute+模型,而是采用类似JSON的定义格式,可以实现各种嵌套,各种能想像到的复杂情况。参考最早一版定义(最新版有修改,设计思路没有变化)

"entities": [
{
"targeturls": [
{
"sourceregion": "",
"values": [
"http://shu.taobao.com/top/[\\d]+/search"
]
}
],
"expression": "//div[contains(@class,'mod')]",
"multi": true,
"selector": "xpath",
"schema": {
"databasename": "alibaba",
"tablename": "industry_rank"
},
"identity": "industry_rank",
"fields": [
{
"datatype": "string(100)",
"expression": "./h3[1]",
"name": "category",
"selector": "xpath",
"multi": false
},
{
"datatype": {
"fields": [
{
"datatype": "string(100)",
"expression": ".//a[1]",
"name": "keyword",
"selector": "xpath",
"multi": false
},
{
"datatype": "string(100)",
"expression": "./@data-rise",
"name": "rise",
"selector": "xpath",
"multi": false
}
]
},
"expression": ".//ol/li",
"multi": true,
"name": "results",
"selector": "xpath"
}
]
}
]


Entities 是数组,表示一个页面可以抽取出多个数据对象

第一个Entity的第一个Field是string(100)的数据类型(常用数据类型)

第一个Entity的第二个Field是一个数据对象

因此,爬虫的解析是非常自由化的。而Attrbiute+模型的抽取是先转换成了以上定义再传给解析类的,我设计这个解析类的原因也是考虑到跨语言的可能性的,只要能传正确的JSON过来,就能解析成一个正确的爬虫。所以只要有兴趣的人写上他们自己语言的Provider, 就是写几个Class序列化成JSON,就可以支持别的语言

如何使用核心库

我们在上一篇也说过,实现一个完整的业务爬虫需要4大模块:下载器(已有实现),URL调度(已有实现),数据抽取(需要自己实现),数据存储(需要自己实现),因此,你只需要实现2个模块就可以完成一个爬虫了

定义数据对象

public class YoukuVideo
{
public string Name { get; set; }
public string Volume { get; set; }
}


数据抽取的实现

只需要实现 IPageProcessor 这个接口就可以了

public class MyPageProcessor : IPageProcessor
{
public Site Site
{
get; set;
}

public void Process(Page page)
{
var totalVideoElements = page.Selectable.SelectList(Selectors.XPath("//li[@class='yk-col4 mr1']")).Nodes();
List<YoukuVideo> results = new List<YoukuVideo>();
foreach (var videoElement in totalVideoElements)
{
var video = new YoukuVideo();
video.Name = videoElement.Select(Selectors.XPath(".//li[@class='title']/a[1]")).GetValue();
video.Volume = videoElement.Select(Selectors.XPath(".//ul[@class='info-list']/li[3]")).GetValue();
video.Volume = video.Volume.Replace("\r", "");
results.Add(video);
}
page.AddResultItem("VideoResult", results);
}
}


这里就需要注意4点

public Site Site { get; set; } 是必需的,并且不需要设值,会在Spider类的初始化时设值

Page 对象传过来的时候,已经是加载好下载的HTML到Selectable属性中了,所以你只需要调用Seletable的接口并传入合适的查询XPATH,CSS, JSONPATH,REGEX就可以查询到你想到值,并且Selectable是可以循环调用

Selectable的GetValue传入true时会把结果去HTML标签

把你在此处组装好的对象,如上面的 YoukuVideo这个List, 存到page的ResultITem中,并指定一个KEY

数据存取

只需要实现 IPipeline,在这里,我们需要用到在 PageProcessor存入数据的KEY,通过这个KEY把数据对象取出来,之后你想把这个数据存文件或是MYSQL,MSSQL,MONGODB就由你自己实现了

public class MyPipeline : IPipeline
{
private string _path;

public MyPipeline(string path)
{
if (string.IsNullOrEmpty(path))
{
throw new Exception("XXXX");
}

_path = path;

if (!File.Exists(_path))
{
File.Create(_path);
}
}

public void Process(ResultItems resultItems, ISpider spider)
{
foreach (YoukuVideo entry in resultItems.Results["VideoResult"])
{
File.AppendAllText(_path, JsonConvert.SerializeObject(entry));
}
}

public void Dispose()
{
}
}


运行爬虫

写好上面两个必需的模块之后,我们就可以运行这个爬虫了。首先需要下载最新的DotnetSpider的代码并编译,编译成功后会把DLL移动到solution文件夹下的output文件夹。我们建立一个空的Console程序,引用必要的DLL如下图



再把上面3个类添加到Project中



运行代码如下,需要注意必须要添加StartUrl, 这是爬虫的第一个起始URL,如果你可以初始计算出所有的翻页URL,也可以在这里一定完全初始化。

public static void Main()
{
HttpClientDownloader downloader = new HttpClientDownloader();
var site = new Site() { EncodingName = "UTF-8" };
site.AddStartUrl("http://www.youku.com/v_olist/c_97_g__a__sg__mt__lg__q__s_1_r_0_u_0_pt_0_av_0_ag_0_sg__pr__h__d_1_p_1.html");
Spider spider = Spider.Create(site, new MyPageProcessor(), new QueueDuplicateRemovedScheduler()).AddPipeline(new MyPipeline("test.json")).SetThreadNum(1);
spider.Run();
}


运行项目,结果如下



如何翻页、抽取目标页

上面的例子只爬取了一个页面,那么如何从页面中抽取翻页的URL或者其它的目标页呢?我们只需要在PageProccessor中解析你的目标页,并加入到Page对象的TargetRequests这个List中即可。我们做如下改动:

public class MyPageProcessor : IPageProcessor
{
public Site Site
{
get; set;
}

public void Process(Page page)
{
var totalVideoElements = page.Selectable.SelectList(Selectors.XPath("//li[@class='yk-col4 mr1']")).Nodes();
List<YoukuVideo> results = new List<YoukuVideo>();
foreach (var videoElement in totalVideoElements)
{
var video = new YoukuVideo();
video.Name = videoElement.Select(Selectors.XPath(".//li[@class='title']/a[1]")).GetValue();
video.Volume = videoElement.Select(Selectors.XPath(".//ul[@class='info-list']/li[3]")).GetValue();
video.Volume = video.Volume.Replace("\r", "");
results.Add(video);
}
page.AddResultItem("VideoResult", results);

foreach (var url in page.Selectable.SelectList(Selectors.XPath("//ul[@class='yk-pages']")).Links().Nodes())
{
page.AddTargetRequest(new Request(url.GetValue(), 0, null));
}
}
}


重新运行程序,可以看到,爬虫不停的开始翻页往下爬取了



总结

到这里最基本,最灵活的使用方法就结束了。是不是很简单?至于有朋友提到的要用到大量的if else, replace什么的你都可以在PageProcessor里做这个组装,抽取的工作。然后我个人感觉世上没有十全十美的东西 ,灵活就可能要更多的代码,而Attrbibute+模型的死板也不是一无是处,至少我用下来70%-80%都可以应付,更何况在Attribute上还可以配置各种各样的Formatter, 当然跟我的抓取对象大多结构化比较规范有关吧。大致缕一下后面要写的章节吧

HTTP Header、Cookie的设置,POST的使用

JSON 数据的解析

基于配置的使用(Extension项目)

WebDriverDownloader的使用,包含基本登录,手动登录

分布式的使用

项目地址

https://github.com/zlzforever/DotnetSpider
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: