[DotnetSpider 系列目录]

上一篇介绍的基本的使用方式,自由度很高,但是编写的代码相对就多了。而我所在的行业其实大部分都是定题爬虫, 只需要采集指定的页面并结构化数据。为了提高开发效率, 我实现了利用实体配置的方式来实现爬虫

创建 Console 项目

利用NUGET添加包

DotnetSpider2.Extension

定义配置式数据对象

  • 数据对象必须继承 SpiderEntity
  • EntityTableAttribute中可以定义数据名称、表名及表名后缀、索引、主键或者需要更新的字段
  • EntitySelector 定义从页面数据中抽取数据对象的规则
  • TargetUrlsSelector定义符合规则(正则)的目标链接, 用于加入到队列中

定义一个原始的数据对象类

public class Product : SpiderEntity
{
}
使用Chrome打开京东商品页 http://list.jd.com/list.html?cat=9987,653,655&page=2&JL=6_0_0&ms=5#J_main
  1. 使用快捷键F12打开开发者工具
  2. 选中一个商品,并观察Html结构

可以看到每个商品都在class为gl-i-wrap j-sku-item的DIV下面,因此添加EntitySelector到数据对象Product的类名上面。( XPath的写法不是唯一的,不熟悉的可以去W3CSCHOLL学习一下, 框架也支持使用Css甚至正则来选择出正确的Html片段)。

   

        [EntitySelector(Expression = "//li[@class='gl-item']/div[contains(@class,'j-sku-item')]")]
public class Product : SpiderEntity
{
}
  1. 添加数据库及索引信息

            [EntityTable("test", "sku", EntityTable.Monday, Indexs = new[] { "Category" }, Uniques = new[] { "Category,Sku", "Sku" })]
    [EntitySelector(Expression = "//li[@class='gl-item']/div[contains(@class,'j-sku-item')]")]
    public class Product : SpiderEntity
    {
    }
  2. 假设你需要采集SKU信息,观察HTML结构,计算出相对的XPath, 为什么是相对XPath?因为EntitySelector已经把HTML截成片段了,内部的Html元素查询都是相对于EntitySelector查询出来的元素。最后再加上数据库中列的信息

            [EntityTable("test", "sku", EntityTable.Monday, Indexs = new[] { "Category" }, Uniques = new[] { "Category,Sku", "Sku" })]
    [EntitySelector(Expression = "//li[@class='gl-item']/div[contains(@class,'j-sku-item')]")]
    public class Product : SpiderEntity
    {
    [PropertyDefine(Expression = "./@data-sku")]
    public string Sku { get; set; }
    }
  3. 爬虫内部,链接是通过Request对象来存储信息的,构造Request对象时可以添加额外的属性值,这时候允许数据对象从Request的额外属性值中查询数据

            [EntityTable("test", "sku", EntityTable.Monday, Indexs = new[] { "Category" }, Uniques = new[] { "Category,Sku", "Sku" })]
    [EntitySelector(Expression = "//li[@class='gl-item']/div[contains(@class,'j-sku-item')]")]
    public class Product : SpiderEntity
    {
    [PropertyDefine(Expression = "./@data-sku")]
    public string Sku { get; set; } [PropertyDefine(Expression = "name", Type = SelectorType.Enviroment)]
    public string Category { get; set; }
    }
配置爬虫(继承EntitySpider)
    public class JdSkuSampleSpider : EntitySpider
{
public JdSkuSampleSpider() : base("JdSkuSample", new Site
{
//HttpProxyPool = new HttpProxyPool(new KuaidailiProxySupplier("快代理API"))
})
{
} protected override void MyInit(params string[] arguments)
{
Identity = Identity ?? "JD SKU SAMPLE"; ThreadNum = ;
// dowload html by http client
Downloader = new HttpClientDownloader(); // storage data to mysql, default is mysql entity pipeline, so you can comment this line. Don't miss sslmode.
AddPipeline(new MySqlEntityPipeline("Database='mysql';Data Source=localhost;User ID=root;Password=;Port=3306;SslMode=None;"));
AddStartUrl("http://list.jd.com/list.html?cat=9987,653,655&page=2&JL=6_0_0&ms=5#J_main", new Dictionary<string, object> { { "name", "手机" }, { "cat3", "" } });
AddEntityType<Product>();
}
}
  1. 其中AddStartUrl第二个参数Dictionary<string, object>就是用于Enviroment查询的数据

  2. TargetUrlsSelector,可以配置数据链接的合法性验证,以及目标URL的获取。如下表示目标URL的获取区域是由XPATH选择,并且要符合正则表达式 &page=[0-9]+&

            [EntityTable("test", "jd_sku", EntityTable.Monday, Indexs = new[] { "Category" }, Uniques = new[] { "Category,Sku", "Sku" })]
    [EntitySelector(Expression = "//li[@class='gl-item']/div[contains(@class,'j-sku-item')]")]
    [TargetUrlsSelector(XPaths = new[] { "//span[@class=\"p-num\"]" }, Patterns = new[] { @"&page=[0-9]+&" })]
    public class Product : SpiderEntity
    {
    [PropertyDefine(Expression = "./@data-sku")]
    public string Sku { get; set; } [PropertyDefine(Expression = "name", Type = SelectorType.Enviroment)]
    public string Category { get; set; }
    }

  1. 添加一个MySql的数据管道,只需要配置好连接字符串即可

    context.AddPipeline(new MySqlEntityPipeline("Database='test';Data Source=localhost;User ID=root;Password=1qazZAQ!;Port=3306"));
完整代码
    public class JdSkuSampleSpider : EntitySpider
{
public JdSkuSampleSpider() : base("JdSkuSample", new Site
{
//HttpProxyPool = new HttpProxyPool(new KuaidailiProxySupplier("快代理API"))
})
{
} protected override void MyInit(params string[] arguments)
{
Identity = Identity ?? "JD SKU SAMPLE"; ThreadNum = ;
// dowload html by http client
Downloader = new HttpClientDownloader(); // storage data to mysql, default is mysql entity pipeline, so you can comment this line. Don't miss sslmode.
AddPipeline(new MySqlEntityPipeline("Database='mysql';Data Source=localhost;User ID=root;Password=;Port=3306;SslMode=None;"));
AddStartUrl("http://list.jd.com/list.html?cat=9987,653,655&page=2&JL=6_0_0&ms=5#J_main", new Dictionary<string, object> { { "name", "手机" }, { "cat3", "" } });
AddEntityType<Product>();
}
} [EntityTable("test", "jd_sku", EntityTable.Monday, Indexs = new[] { "Category" }, Uniques = new[] { "Category,Sku", "Sku" })]
[EntitySelector(Expression = "//li[@class='gl-item']/div[contains(@class,'j-sku-item')]")]
[TargetUrlsSelector(XPaths = new[] { "//span[@class=\"p-num\"]" }, Patterns = new[] { @"&page=[0-9]+&" })]
public class Product : SpiderEntity
{
[PropertyDefine(Expression = "./@data-sku", Length = )]
public string Sku { get; set; } [PropertyDefine(Expression = "name", Type = SelectorType.Enviroment, Length = )]
public string Category { get; set; } [PropertyDefine(Expression = "cat3", Type = SelectorType.Enviroment)]
public int CategoryId { get; set; } [PropertyDefine(Expression = "./div[1]/a/@href")]
public string Url { get; set; } [PropertyDefine(Expression = "./div[5]/strong/a")]
public long CommentsCount { get; set; } [PropertyDefine(Expression = ".//div[@class='p-shop']/@data-shop_name", Length = )]
public string ShopName { get; set; } [PropertyDefine(Expression = ".//div[@class='p-name']/a/em", Length = )]
public string Name { get; set; } [PropertyDefine(Expression = "./@venderid", Length = )]
public string VenderId { get; set; } [PropertyDefine(Expression = "./@jdzy_shop_id", Length = )]
public string JdzyShopId { get; set; } [PropertyDefine(Expression = "Monday", Type = SelectorType.Enviroment)]
public DateTime RunId { get; set; }
}
运行爬虫
public class Program
{
public static void Main(string[] args)
{
JdSkuSampleSpider spider = new JdSkuSampleSpider();
spider.Run();
}
}

不到57行代码完成一个爬虫,是不是异常的简单?

代码地址

https://github.com/zlzforever/DotnetSpider 望各位大佬加星 

参与开发或有疑问

博文写得比较早, 框架修改有时会来不及更新博文中的代码, 请查看DotnetSpider.Sample项目中的样例爬虫

QQ群: 477731655

邮箱: zlzforever@163.com

[开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [三] 配置式爬虫的更多相关文章

  1. [开源 .NET 跨平台 数据采集 爬虫框架: DotnetSpider] [三] 配置式爬虫

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 上一篇介绍的基本的使用方式,虽然自由度很高,但是编写的代码相对还是挺多.于是框 ...

  2. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [一] 初衷与架构设计

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 五.如何做全站采集 为什么要造轮子 同学们可以去各大招聘网站查看一下爬虫工程师 ...

  3. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [五] 如何做全站采集?

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 五.如何做全站采集 如何做全站采集? 很多同学加群都在问, 如何使用Dotne ...

  4. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [二] 基本使用

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 五.如何做全站采集 使用环境 Visual Studio 2017 .NET ...

  5. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [四] JSON数据解析

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 五.如何做全站采集 场景模拟 接上一篇, JD SKU对应的店铺信息是异步加载 ...

  6. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] 学习

    http://www.cnblogs.com/jjg0519/p/6707513.html

  7. [开源 .NET 跨平台 数据采集 爬虫框架: DotnetSpider] [一] 初衷与架构设计

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 为什么要造轮子 同学们可以去各大招聘网站查看一下爬虫工程师的要求,大多是招JA ...

  8. [开源 .NET 跨平台 数据采集 爬虫框架: DotnetSpider] [二] 基本使用

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 使用环境 Visual Studio 2015 or later .NET 4 ...

  9. [开源 .NET 跨平台 数据采集 爬虫框架: DotnetSpider] [四] JSON数据解析

    [DotnetSpider 系列目录] 一.初衷与架构设计 二.基本使用 三.配置式爬虫 四.JSON数据解析与配置系统 场景模拟 假设由于漏存JD SKU对应的店铺信息.这时我们需要重新完全采集所有 ...

随机推荐

  1. WebSocket简单尝试

    System.Net.WebSockets.WebSocket 需要.NET 4.5,IIS8以上,Windows Server2008R2自带的IIS不支持,Windows8及Server2012以 ...

  2. Windows服务器搭建Redis

    1.下载安装Redis https://github.com/MicrosoftArchive/redis/releases 可以下载安装版(.msi)也可以下载解压版(.zip). 我直接下载的安装 ...

  3. 服务器较稳妥的磁盘阵列方案:RAID5+热备盘

    最近公司这边要整个数据中心,但是我们这边磁盘阵列的方案选择方面需要做好万全的测试 内部测试的服务器当初损坏的磁盘1个做的raid5直接换个新磁盘做替换rebuild就行了 但是现在想的方法是5+1的方 ...

  4. golang变量的注意

    方法内部的变量使用方法: /* 定义三个变量,它们分别初始化为相应的值 vname1为v1,vname2为v2,vname3为v3 编译器会根据初始化的值自动推导出相应的类型 */ vname1, v ...

  5. 五、git创建及合并分支

    1. 创建并切换到dev分支 git checkout -b dev // git checkout命令加上-b参数表示创建并切换,相当于以下两条命令 git branch dev git check ...

  6. 【BZOJ4946】[NOI2017]蔬菜(贪心)

    [BZOJ4946][NOI2017]蔬菜(贪心) 题面 BZOJ 洛谷 UOJ 题解 忽然发现今年\(NOI\)之前的时候切往年\(NOI\)的题目,就\(2017\)年的根本不知道怎么下手(一定是 ...

  7. 初探boost之timer库学习笔记

    timer   使用方法     #include <boost/timer.hpp> #include <iostream> using namespace std; usi ...

  8. 【Java多线程】AtomicLong和LongAdder

    AtomicLong简要介绍 AtomicLong是作用是对长整形进行原子操作,显而易见,在java1.8中新加入了一个新的原子类LongAdder,该类也可以保证Long类型操作的原子性,相对于At ...

  9. UVA1451 Average

    嘟嘟嘟 看到比值,就想到01分数规划,令\(ans = \frac{\sum a_i}{\sum l_i}\),其中\(l\)表示长度,所以\(l_i\)都是\(1\). 然后变一下型,得到\(\su ...

  10. pku1365 Prime Land (数论,合数分解模板)

    题意:给你一个个数对a, b 表示ab这样的每个数相乘的一个数n,求n-1的质数因子并且每个指数因子k所对应的次数 h. 先把合数分解模板乖乖放上: ; ans != ; ++i) { ) { num ...