zoukankan      html  css  js  c++  java
  • 爬虫的框架

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

    上一篇大至 介绍了一下爬虫的框架设计,从这一篇开始着重介绍如何使用这个爬虫。

    数据抽取定义

    之前也有人反应说用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"
                    }
                ]
            }
        ]
    复制代码
    1. Entities 是数组,表示一个页面可以抽取出多个数据对象
    2. 第一个Entity的第一个Field是string(100)的数据类型(常用数据类型)
    3. 第一个Entity的第二个Field是一个数据对象

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

    是否够灵活?

    也有人反应说Attrbiute+模型的抽取不够灵活,不能满足大部分情况。其实最灵活的就是使用核心库即Core这个DLL,在这个项目里,实现了爬虫的基本逻辑,URL调度、去重,Html的Selector,基本的下载器,多线程控制等等。就是说,你要自由、灵活我也给你的呀。

    如何使用核心库

    我们在上一篇也说过,实现一个完整的业务爬虫需要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("
    ", "");
                    results.Add(video);
                }
                page.AddResultItem("VideoResult", results);
            }
        }
    复制代码

    这里就需要注意4点

    1. public Site Site { get; set; } 是必需的,并且不需要市值,会在Spider类的初始化时设值
    2. Page 对象传过来的时候,已经是加载好下载的HTML到Selectable属性中了,所以你只需要调用Seletable的接口并传入合适的查询XPATH,CSS, JSONPATH,REGEX就可以查询到你想到值,并且Selectable是可以循环调用
    3. Selectable的GetValue传入true时会把结果去HTML标签
    4. 把你在此处组装好的对象,如上面的 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();
            }
    复制代码

    F5运行项目,结果如下

    如何翻页、抽取目标页

    上面的例子只爬取了一个页面,那么如何从页面中抽取翻页的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("
    ", "");
                    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的使用,包含基本登录,手动登录
    • 分布式的使用
  • 相关阅读:
    webservice接口示例(spring+xfire+webservice)
    SoapUI 测试接口演示
    XML 文档结构必须从头至尾包含在同一个实体内
    Oracle url编码与解码
    【中山市选2010】【BZOJ2467】生成树
    synchronized与static synchronized 的差别、synchronized在JVM底层的实现原理及Java多线程锁理解
    自己动手写搜索引擎
    PopupWindow底部弹出
    JAVA集合类型(二)
    双卡手机发送短信
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5525869.html
Copyright © 2011-2022 走看看