记录一次C#爬虫记录,获取必应图片
记录一次C#爬虫记录,获取必应图片
起因
事情是这样的,我创建了一个仓库,里面有2018年到目前为止每日的必应壁纸,在八月份的时候我看到微软有接口文档,于是写了一个服务,每天早上八点钟会获取必应壁纸(目前已经可以作为api来使用了,暂时不对外开放)
然后推送到微信上面。这个项目的地址是 https://gitee.com/Pridejoy/Bing,有兴趣的可以去看看。但是吧,这个仓库有两个问题
- 2018年以前的壁纸没有的
- 2018年后的壁纸没有版权说明
为了更新这个仓库,我偶然见发现一个网站里面有必应壁纸,而且免费开放,我就绝对去爬这个网站
经过
说干就干,我学的是C#,听闻python的爬虫很厉害,但是0基础入门就不怎么回来,下定决心就干,我发现了一个neget包爬虫挺简单的。我分析了需要爬虫的网站。然后就开始下代码
步骤
不如授人以鱼不如授人以渔
使用的具体详情 https://www.cnblogs.com/xuliangxing/p/8004403.html
安装包
HtmlAgilityPack
如何加载Html
主要常见的有三种方式;从文件加载、从字符串加载、从网页链接加载。
// 从物理路径的文件加载
var doc = new HtmlDocument();
doc.Load(filePath);//文件路径
// 从Stream当中加载
var doc = new HtmlDocument();
doc.LoadHtml(html);
// 从网页的Url链接加载
var url = "http://www.cnblogs.com/xuliangxing/";
var web = new HtmlWeb();
var doc = web.Load(url);
以Stream对象为主的重载方法:
(1)public void Load(Stream stream) ///从指定的Stream对象中加载html;
(2)public void Load(Stream stream, bool detectEncodingFromByteOrderMarks) ///指定是否从顺序字节流中解析编码格式
(3)public void Load(Stream stream, Encoding encoding) ///指定编码格式
(4)public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks)
(5)public void Load(Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize) ///缓冲区大小
以指定的物理路径为主的重载方法:
(1)public void Load(string path)
(2)public void Load(string path, bool detectEncodingFromByteOrderMarks) ///指定是否从顺序字节流中解析编码格式
(3)public void Load(string path, Encoding encoding) ///指定编码格式
(4)public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks)
(5)public void Load(string path, Encoding encoding, bool detectEncodingFromByteOrderMarks, int buffersize)
如何精准定位到我们需要的数据
这个时候我们需要用到HtmlNodeCollection和HtmlNode这两个类,我们把Html每个标签看作一个Node,所有我们想到定位到某个标签的内容,就需要知道这个标签的相关属性。顺便说一下,HtmlNode类实现了IXPathNavigable接口,这说明了它可以通过xpath来定位数据了,如果你对解析XML格式数据的XmlDocument类了解的话,特别是使用过了SelectNodes()和SelectSingleNode()方法的人来说,对使用HtmlNode类将会很熟悉。其实Html Agility Pack内部是把html解析成xml文档格式了的,所以支持xml中的一些常用查询方式。下面通过简单示例对HtmlNode的一些主要的常用成员作简要的说明。
1.通过ID属性(或者其他属性)来选择对应的节点
通用格式:@id=‘xxxx’(id可以是其他属性等等),比如我们要定位到本文博客主页的标题和副标题内容。
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(url)//博客主页URL
//下面的意思是:通过属性id的值,来定位header下的blogTitle节点信息
HtmlNode titleNode = doc.DocumentNode.SelectSingleNode("//div[@id='header']/div[@id='blogTitle']");
我们还可以不通过属性id去定位,还有通过索引去定位,如下所示,这个效果和上面是等同的:
//下面的意思是:通过索引定位,div[2]是表示根节点的第二个
HtmlNode titleNode = doc.DocumentNode.SelectSingleNode("//div[2]/div[1]");
备注:注意路径里"//"表示从根节点开始查找,两个斜杠‘//’表示查找所有childnodes;一个斜杠'/'表示只查找第一层的childnodes(即不查找grandchild);点斜杠"./"表示从当前结点而不是根结点开始查找
2.如何获取节点文本内容
IDNode.OuterHtml ///返回结果是:<h1><a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">法号阿兴</a></h1>
IDNode.InnerHtml ///返回结果是:<a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">法号阿兴</a>
IDNode.InnerText ///返回结果是:法号阿兴
3.如何获取节点属性值
假如我们上面Html数据当中,博主博客地址,在标签<div id="header">
里的<a>
标签里,这个时候就需要使用HtmlNode下的Attribute属性了。
string url = doc.DocumentNode.SelectSingleNode("//div[@id='header']/div[@id='blogTitle']/a").Attributes["href"].Value;
4.如何获取某个标签的所有节点
我们如果获取前面Html数据的li所有分类,这个时候需要使用方法SelectNodes了
HtmlNodeCollection uiListNodes = doc.DocumentNode.SelectNodes("//ui[@id='navList']/li")
5.如何去掉外层的html tag只留下文本内容
回到我们刚刚上面讲到的地方,用remove方法。假设要删除上文结点<a id="Header1_HeaderTitle" class="headermaintitle" href="http://www.cnblogs.com/xuliangxing/">
法号阿兴</a>
,你想留下博客名称而不要的话,那你需要先得到这个Html结点,通过remove方法删除掉多余的HTML Tag假设该节点叫Node:
Node.ParentNode.RemoveChild(Node,true);
结果
结构当然是ok的了,经过一个小时的爬虫整理上传。
已经上传
2016年壁纸(366张)
2017年必应壁纸(365)
2018年必应壁纸(365张)
2019年必应壁纸(365张)
2020年必应壁纸(366张)
每一张都是精彩绝伦
等到后面会把api开放出来,可以通过情求获取壁纸,包括不同的分辨率
先说明下,
具体的源码 https://wwa.lanzoui.com/iXeZTv7pevi