这一章详细讲解编码过程

那么接下来就是码代码了,GO

新建NetCore WebApi项目 空的就可以

NuGet安装

Install-Package AngleSharp  

或者界面安装

using。。

默认本地装有mysql或者有远程开放的mysql数据库,如何安装mysql,园区有很多文章都详细说明。

配置文件添加mysql连接 appsettings.json

{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"MySql": "server=localhost;user id=root;pwd=root;database=dreaminfo;"
}
}

新建实体类,这里由于比较简单,所以创建到一起,实际工作中最好不要这样,可读性较差

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks; namespace WebAPI.Models
{
public class Dream
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public string Summary { get; set; }
public string CateName { get; set; }
public DateTime? CreateTime { get; set; }
}
public class DreamInfo
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int FkDreamId { get; set; }
public string DreamName { get; set; }
public string Name { get; set; }
public string Content { get; set; }
public DateTime? CreateTime { get; set; }
}
}

安装,mysql的ef支持

Install-Package Pomelo.EntityFrameworkCore.MySql

创建DBContext

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks; namespace WebAPI.Models
{
public class MainDBContext : DbContext
{
public MainDBContext(DbContextOptions<MainDBContext> options) : base(options)
{ }
private string connection;
public MainDBContext(string connection) => this.connection = connection;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!string.IsNullOrWhiteSpace(connection))
optionsBuilder.UseMySql(connection);
}
public DbSet<Dream> Dream { get; set; }
public DbSet<DreamInfo> DreamInfo { get; set; }
}
}

配置服务

 public void ConfigureServices(IServiceCollection services)
{
var mysqlCon = Configuration.GetSection("ConnectionStrings:MySql").Value;
services.AddDbContext<MainDBContext>(l => l.UseMySql(mysqlCon, b => b.MigrationsAssembly("Dream"))); //跳转查看
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

然后是数据库迁移 ,这里使用的是codefirst,所以创建好实体类之后在实体类及EF存在的程序集执行Add-Migration命令,我这里做的比较简单,有的如果是按照框架来设计,可能实体类被设计在单独的类库里

这里是直接在webapi里面

执行之后会多出来迁移的的文件,然后执行Update-Database就可以生成数据库拉。

后期如果数据库有变更还是同样的操作

工具》打开Nuget包管理器》程序包管理控制台 选中EF所在类库

Add-Migration Update-
//然后等待变更文件生成之后执行
Update-Database

然后我们看下数据库

我们刷新下,数据库和对应的表都有了。

获取页面内容

新建一个空的API控制器DreamController

然后创建获取类别数据的方法

        /// <summary>
/// 定义一个获取列表数据的方法,需要传递一个列表页面的url地址
/// </summary>
/// <param name="rul"></param>
public void GetData(string url)
{
//这个跟我之前使用的浏览器驱动类似,也是通过选择器和xpath来爬取数据
//区别在于那个是模拟真人操作,这个是通过通过HttpWebRequest直接请求
var html = GetHtml(url);
//创建一个(可重用)解析器前端
var parser = new HtmlParser();
var document = parser.Parse(html);
//找到一个页面有多少个dream信息
var mengList = document.QuerySelectorAll("#list > div.main > div.l-item > ul > li");
//循环获取梦的信息
for (var i = ; i < mengList.Length; i++)
{
var meng = new Dream();
meng.CateName = "人物";
//名称
meng.Name = mengList[i].QuerySelector("h3 > a").TextContent;
//简介
meng.Summary = mengList[i].QuerySelector("p").TextContent;
//连接
meng.Url = mengList[i].QuerySelector("h3 > a").GetAttribute("href");
meng.CreateTime = DateTime.Now;
_context.Dream.Add(meng);
_context.SaveChanges();//可以单个保存,也可以获取当前页数据之后保存一次,可优化的点有很多,这里不再详细描述
}
}

但是这里获取的都是单页的数据,我们继续上一章说的,使用选择器里面的.next来寻找翻页按钮附带的连接

然后看看最后一页是什么样式

发现最后一页就没有下一页样式了,就获取不到值了,好的 那么我们开始翻页

至于翻页 还有第二种思路,就是直接获取这种类别下的最后一页的页码,然后循环就行了,似乎比较简单,我们就用这一种

完善后的方法

 /// <summary>
/// 定义一个获取列表数据的方法,需要传递一个列表页面的url地址
/// </summary>
/// <param name="rul"></param>
public void GetData(string url, int pageIndex)
{
var thisUrl = url + pageIndex + ".html";
var html = GetHtml(thisUrl);
//创建一个(可重用)解析器前端
var parser = new HtmlParser();
var document = parser.Parse(html);
var mengList = document.QuerySelectorAll("#list > div.main > div.l-item > ul > li");
//#list > div.main > div.pagelist > a.end
//获取最末页数据
if (!PageEnd.HasValue)
{
var pageEnd = document.QuerySelector("#list > div.main > div.pagelist > a.end")?.TextContent;
PageEnd = Convert.ToInt32(pageEnd);
}
var list = new List<Dream>();
for (var i = ; i < mengList.Length; i++)
{
var meng = new Dream();
meng.CateName = "其他";
//名称
meng.Name = mengList[i].QuerySelector("h3 > a").TextContent;
//简介
meng.Summary = mengList[i].QuerySelector("p").TextContent;
//连接
meng.Url = mengList[i].QuerySelector("h3 > a").GetAttribute("href");
meng.CreateTime = DateTime.Now;
_context.Dream.Add(meng);
_context.SaveChanges();
}
//翻页记录页码
pageIndex++;
if (pageIndex <= Convert.ToInt32(PageEnd))
{
Console.WriteLine(pageIndex + "/" + PageEnd);
//翻页完之前一直抓取
GetData(url, pageIndex);
}
}

定义接口,输出一下看看获取了多少页的数据

PageEnd是在控制器里面定义的

 public class DreamController : ControllerBase
{
static int? PageEnd = null;
//other code
 [HttpGet]
public async Task<IActionResult> GetMengXinfo()
{
GetData("http://www.xzw.com/jiemeng/lib/renwu/", );
return Ok(PageEnd);
}

调试走一波

可以看到这里数据其实已经拿到了,那我们就开始往数据库保存

由于是演示,我们找一个数据量较少的分类来获取 使用“其他”分类获取,调用接口,看到返回值是45

这个跟我们找到对应的数据是一样的

说明数据是ok的,我们看下数据库,dream表已经有数据了

到这里 分类数据就获取到了,其他几个分类 可以使用一个数组,循环数组拼连接获取,也可以放到后台任务慢慢执行,比如Hangfire

详细信息获取

详细信息的页面我们其实是有的,就是dream表里面的url字段,拼接上domain之后就成了详细页面的连接,我们又可以使用AngleSharp来获取数据拉。。

其实AngleSharp是对获取到的文档进行解析,里面构建了很多C#和js习惯的语法,比如

document.QuerySelector(选择器)//选择器查询单个符合条件的数据

document.QuerySelectorAll("#list > div.main > div.l-item > ul > li");获取复合条件的元素集合

获取详情页面内容,并给实体对象赋值,这里有很多可以试探的方法,大家可以尝试一下,我这个只是简单的为了完成我想要的功能。

  /// <summary>
/// 获取详情页的页面解析
/// </summary>
/// <param name="dreamId"></param>
/// <param name="url"></param>
public void GetDetailData(int dreamId, string url)
{
var html = GetHtml(url);
var parser = new HtmlParser();
var document = parser.Parse(html);
//#wraper > div.main-wrap > div.pleft.fl > div.viewbox.box > div.sbody
var sbody = document.QuerySelector("#wraper > div.main-wrap > div.pleft.fl > div.viewbox.box > div.sbody");
var dllist = sbody.QuerySelectorAll("dl");
var title = sbody.QuerySelector("h2").TextContent;//标题
if (dllist.Length > )
{
foreach (var detail in dllist)
{
//#wraper > div.main-wrap > div.pleft.fl > div.viewbox.box > div.sbody > dl:nth-child(4) > dt > strong
var info = new DreamInfo();
info.FkDreamId = dreamId;
info.DreamName = title;
info.Name = detail.QuerySelector("dt > strong").TextContent;
info.Content = detail.QuerySelector("dd").TextContent; ;
info.CreateTime = DateTime.Now;
_context.DreamInfo.Add(info);
_context.SaveChanges();
} }
}

定义接口

[Route("detail")]
[HttpGet]
public async Task<IActionResult> GetDreamInfo()
{
var domain = "http://www.xzw.com";
//查询出其他分类的梦数据来解析详细内容
var dreamList = _context.Dream.Where(l => l.CateName == "其他").ToList();
foreach (var dream in dreamList)
{
GetDetailData(dream.Id, domain + dream.Url);
}
return Ok(PageEnd);
}

执行接口https://localhost:44329/api/dream/detail

这里不展示调试信息了,怕被说水内容

然后看数据库dreaminfo也有了数据

找到对应页面

到这里,数据基本都可以获取到了,其他分类可以做计划任务来获取数据

总结

  对自己感兴趣的东西,可能下决心投入的时间会更长一点,共勉。

  排版较乱可能影响阅读,不过内容还是能看到的。。

  GitHub:https://github.com/ermpark/dream.git

C# NetCore使用AngleSharp爬取周公解梦数据的更多相关文章

  1. C# NetCore使用AngleSharp爬取周公解梦数据 起因和页面数据拆解

    起因 最近突然心血来潮想做个小程序,学习一下小程序开发流程,然后新手就想做个查询的就可以了,少点交互能力,这种思来想去还是周公解梦比较靠谱, 网上一搜,还真有小程序源码,但是这里面似乎数据都是取第三方 ...

  2. bert+seq2seq 周公解梦,看AI如何解析你的梦境?【转】

    介绍 在参与的项目和产品中,涉及到模型和算法的需求,主要以自然语言处理(NLP)和知识图谱(KG)为主.NLP涉及面太广,而聚焦在具体场景下,想要生产落地的还需要花很多功夫. 作为NLP的主要方向,情 ...

  3. 基于爬取百合网的数据,用matplotlib生成图表

    爬取百合网的数据链接:http://www.cnblogs.com/YuWeiXiF/p/8439552.html 总共爬了22779条数据.第一次接触matplotlib库,以下代码参考了matpl ...

  4. Scrapy实战篇(八)之Scrapy对接selenium爬取京东商城商品数据

    本篇目标:我们以爬取京东商城商品数据为例,展示Scrapy框架对接selenium爬取京东商城商品数据. 背景: 京东商城页面为js动态加载页面,直接使用request请求,无法得到我们想要的商品数据 ...

  5. 利用python爬取58同城简历数据

    利用python爬取58同城简历数据 利用python爬取58同城简历数据 最近接到一个工作,需要获取58同城上面的简历信息(http://gz.58.com/qzyewu/).最开始想到是用pyth ...

  6. 使用Selenium爬取网站表格类数据

    本文转载自一下网站:Python爬虫(5):Selenium 爬取东方财富网股票财务报表 https://www.makcyun.top/web_scraping_withpython5.html 需 ...

  7. jsoup爬取某网站安全数据

    jsoup爬取某网站安全数据 package com.vfsd.net; import java.io.IOException; import java.sql.SQLException; impor ...

  8. python爬取豆瓣电影信息数据

    题外话+ 大家好啊,最近自己在做一个属于自己的博客网站(准备辞职回家养老了,明年再战)在家里 琐事也很多, 加上自己 一回到家就懒了(主要是家里冷啊! 广东十几度,老家几度,躲在被窝瑟瑟发抖,) 由于 ...

  9. 几句简单的python代码完成周公解梦功能

    <周公解梦>是靠人的梦来卜吉凶的一本于民间流传的解梦书籍,共有七类梦境的解述.这是非常传统的中国文化体系的一部分,但是如何用代码来获取并搜索周公解梦的数据呢?一般情况下,要通过爬虫获取数据 ...

随机推荐

  1. [转载]Ocelot简易教程(六)之重写配置文件存储方式并优化响应数据

    作者:依乐祝 原文地址:https://www.cnblogs.com/yilezhu/p/9807125.html 很多人都说配置文件的配置很繁琐,如果存储在数据库就方便很多,可以通过自定义UI界面 ...

  2. 【52.49%】【codeforces 556A】Case of the Zeros and Ones

    time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard ou ...

  3. SpringMvc中两个Controller类之间传递参数的方法

    使用SpringMvc框架,在访问ControllerA的时候,将A里面的参数传递到ControllerB中.适用于同一框架下两个不同Controller或者由rpc(dubbo)连接的两个工程里的C ...

  4. 菜单之二:使用xml文件定义菜单 分类: H1_ANDROID 2013-11-03 09:39 1038人阅读 评论(0) 收藏

    参考<疯狂android讲义>2.10节 P174,参见归档project:XmlMenuDemo.zip 一般推荐使用XML文件定义菜单. 基本步骤如下: 1.定义布局文件 为简单显示原 ...

  5. dnf游戏外怪原理

    dnf游戏外怪原理 一.总结 一句话总结:用钩子,修改内存.找到存储数据的内存,修改内存的执行代码达到修改数据的目的,修改了数据之后再改回来. 1.如何找到存储数据的内存? 然后数据变化,用软件找变化 ...

  6. Windows Phone 8.1 控件

    如果你已经开始了 Windows Phone 8.1 的学习,就会发现许多在 8.0 下的控件在 8.1 中都发生了变化,以下就谈谈几个 8.1 下的新控件以及与 8.0 控件的改变. 1. Text ...

  7. AE中网络分析的实现 的各个类之间的关系

    原文AE中网络分析的实现 的各个类之间的关系 1.     创建网络数据集 在ArcCatalog中勾选网络分析模块,新建个人地理信息数据库—>新建要素数据集—>批量导入要素—>创建 ...

  8. AngularJs压缩时须要注意的事项

    因为AngularJS是通过控制器构造函数的參数名字来判断依赖服务名称的.所以假设你要压缩控制器的JS代码.它全部的參数也同一时候会被压缩,这时候依赖注入系统就不能正确的识别出服务了. 假如我们的Co ...

  9. [Node.js] Identify memory leaks with nodejs-dashboard

    In this lesson, I introduce a memory leak into our node.js application and show you how to identify ...

  10. Android BlueDroid(一):BlueDroid概述

    关键词:bluedroid bluez作者:xubin341719(欢迎转载,请注明作者,请尊重版权,谢谢!)欢迎指正错误.共同学习.共同进步!! 一.名词解释:(实用信息添加中--) BTI F: ...