.NetCore实践爬虫系统(二)自定义规则
回顾
上篇文章NetCore实践爬虫系统(一)解析网页内容 我们讲了利用HtmlAgilityPack,输入XPath路径,识别网页节点,获取我们需要的内容。评论中也得到了大家的一些支持与建议。下面继续我们的爬虫系统实践之路。本篇文章不包含依赖注入/数据访问/UI界面等,只包含核心的爬虫相关知识,只能作为Demo使用,抛砖引玉,共同交流。
上篇文章NetCore实践爬虫系统(一)解析网页内容 我们讲了利用HtmlAgilityPack,输入XPath路径,识别网页节点,获取我们需要的内容。评论中也得到了大家的一些支持与建议。下面继续我们的爬虫系统实践之路。本篇文章不包含依赖注入/数据访问/UI界面等,只包含核心的爬虫相关知识,只能作为Demo使用,抛砖引玉,共同交流。
抽象规则
爬虫系统之所以重要,正是他能支持各种各样的数据。要支持识别数据,第一步就是要将规则剥离出来,支持用户自定义。
爬虫规则,实际上是跟商品有点类似,如动态属性,但也有它特殊的地方,如规则可以循环嵌套,递归,相互引用,链接可以无限下去抓取。更复杂的,就需要自然语言识别,语义分析等领域了。
我用PPT画了个演示图。用于演示支持分析文章,活动,天气等各种类型的规则。

爬虫系统之所以重要,正是他能支持各种各样的数据。要支持识别数据,第一步就是要将规则剥离出来,支持用户自定义。
爬虫规则,实际上是跟商品有点类似,如动态属性,但也有它特殊的地方,如规则可以循环嵌套,递归,相互引用,链接可以无限下去抓取。更复杂的,就需要自然语言识别,语义分析等领域了。
我用PPT画了个演示图。用于演示支持分析文章,活动,天气等各种类型的规则。
编码实现
先来定义个采集规则接口,根据规则获取单个或一批内容。
/// <summary>
/// 采集规则接口
/// </summary>
public interface IDataSplider
{
/// <summary>
/// 得到内容
/// </summary>
/// <param name="rule"></param>
/// <returns></returns>
List<SpliderContent> GetByRule(SpliderRule rule);
/// <summary>
/// 得到属性信息
/// </summary>
/// <param name="node"></param>
/// <param name="rule"></param>
/// <returns></returns>
List<Field> GetFields(HtmlNode node, SpliderRule rule);
}
必不可少的规则类,用来配置XPath根路径。
/// <summary>
/// 采集规则-能满足列表页/详情页。
/// </summary>
public class SpliderRule
{
public string Id { get; set; }
public string Url { get; set; }
/// <summary>
/// 网页块
/// </summary>
public string ContentXPath { get; set; }
/// <summary>
/// 支持列表式
/// </summary>
public string EachXPath { get; set; }
/// <summary>
///
/// </summary>
public List<RuleField> RuleFields { get; set; }
}
然后就是属性字段的自定义设置,这里根据内容特性,加入了正则支持。例如评论数是数字,可用正则筛选出数字。还有Attribute字段,用来获取node的Attribute信息。
/// <summary>
/// 自定义属性字段
/// </summary>
public class RuleField
{
public string Id { get; set; }
public string DisplayName { get; set; }
/// <summary>
/// 用于存储的别名
/// </summary>
public string FieldName { get; set; }
public string XPath { get; set; }
public string Attribute { get; set; }
/// <summary>
/// 针对获取的HTml正则过滤
/// </summary>
public string InnerHtmlRegex { get; set; }
/// <summary>
/// 针对获取的Text正则过滤
/// </summary>
public string InnerTextRegex { get; set; }
/// <summary>
/// 是否优先取InnerText
/// </summary>
public bool IsFirstInnerText { get; set; }
}
下面是根据文章爬虫规则的解析步骤,实现接口IDataSplider
/// <summary>
/// 支持列表和详情页
/// </summary>
public class ArticleSplider : IDataSplider
{
/// <summary>
/// 根据Rule
/// </summary>
/// <param name="rule"></param>
/// <returns></returns>
public List<SpliderContent> GetByRule(SpliderRule rule)
{
var url = rule.Url;
HtmlWeb web = new HtmlWeb();
//1.支持从web或本地path加载html
var htmlDoc = web.Load(url);
var contentnode = htmlDoc.DocumentNode.SelectSingleNode(rule.ContentXPath);
var list = new List<SpliderContent>();
//列表页
if (!string.IsNullOrWhiteSpace(rule.EachXPath))
{
var itemsNodes = contentnode.SelectNodes(rule.EachXPath);
foreach (var item in itemsNodes)
{
var fields = GetFields(item, rule);
list.Add(new SpliderContent()
{
Fields = fields,
SpliderRuleId = rule.Id
});
}
return list;
}
//详情页
var cfields = GetFields(contentnode, rule);
list.Add(new SpliderContent()
{
Fields = cfields,
SpliderRuleId = rule.Id
});
return list;
}
public List<Field> GetFields(HtmlNode item, SpliderRule rule)
{
var fields = new List<Field>();
foreach (var rulefield in rule.RuleFields)
{
var field = new Field() { DisplayName = rulefield.DisplayName, FieldName = "" };
var fieldnode = item.SelectSingleNode(rulefield.XPath);
if (fieldnode != null)
{
field.InnerHtml = fieldnode.InnerHtml;
field.InnerText = fieldnode.InnerText;
field.AfterRegexHtml = !string.IsNullOrWhiteSpace(rulefield.InnerHtmlRegex) ? Regex.Replace(fieldnode.InnerHtml, rulefield.InnerHtmlRegex, "") : fieldnode.InnerHtml;
field.AfterRegexText = !string.IsNullOrWhiteSpace(rulefield.InnerTextRegex) ? Regex.Replace(fieldnode.InnerText, rulefield.InnerTextRegex, "") : fieldnode.InnerText;
//field.AfterRegexHtml = Regex.Replace(fieldnode.InnerHtml, rulefield.InnerHtmlRegex, "");
//field.AfterRegexText = Regex.Replace(fieldnode.InnerText, rulefield.InnerTextRegex, "");
if (!string.IsNullOrWhiteSpace(rulefield.Attribute))
{
field.Value = fieldnode.Attributes[rulefield.Attribute].Value;
}
else
{
field.Value = rulefield.IsFirstInnerText ? field.AfterRegexText : field.AfterRegexHtml;
}
}
fields.Add(field);
}
return fields;
}
}
还是以博客园为例,配置内容和属性的自定义规则
/// <summary>
///
/// </summary>
public void RunArticleRule()
{
var postitembodyXPath = "div[@class='post_item_body']//";
var postitembodyFootXPath = postitembodyXPath+ "div[@class='post_item_foot']//";
var rule = new SpliderRule()
{
ContentXPath = "//div[@id='post_list']",
EachXPath = "div[@class='post_item']",
Url = "https://www.cnblogs.com",
RuleFields = new List<RuleField>() {
new RuleField(){ DisplayName="推荐", XPath="*//span[@class='diggnum']", IsFirstInnerText=true },
new RuleField(){ DisplayName="标题",XPath=postitembodyXPath+"a[@class='titlelnk']", IsFirstInnerText=true },
new RuleField(){ DisplayName="URL",XPath=postitembodyXPath+"a[@class='titlelnk']",Attribute="href", IsFirstInnerText=true },
new RuleField(){ DisplayName="简要",XPath=postitembodyXPath+"p[@class='post_item_summary']", IsFirstInnerText=true },
new RuleField(){ DisplayName="作者",XPath=postitembodyFootXPath+"a[@class='lightblue']", IsFirstInnerText=true },
new RuleField(){ DisplayName="作者URL",XPath=postitembodyFootXPath+"a[@class='lightblue']",Attribute="href", IsFirstInnerText=true },
new RuleField(){ DisplayName="讨论数", XPath="span[@class='article_comment']",IsFirstInnerText=true, InnerTextRegex=@"[^0-9]+" },
new RuleField(){ DisplayName="阅读数", XPath=postitembodyFootXPath+"span[@class='article_view']",IsFirstInnerText=true, InnerTextRegex=@"[^0-9]+" },
}
};
var splider = new ArticleSplider();
var list = splider.GetByRule(rule);
foreach (var item in list)
{
var msg = string.Empty;
item.Fields.ForEach(M =>
{
if (M.DisplayName != "简要" && !M.DisplayName.Contains("URL"))
{
msg += $"{M.DisplayName}:{M.Value}";
}
});
Console.WriteLine(msg);
}
}
先来定义个采集规则接口,根据规则获取单个或一批内容。
/// <summary>
/// 采集规则接口
/// </summary>
public interface IDataSplider
{
/// <summary>
/// 得到内容
/// </summary>
/// <param name="rule"></param>
/// <returns></returns>
List<SpliderContent> GetByRule(SpliderRule rule);
/// <summary>
/// 得到属性信息
/// </summary>
/// <param name="node"></param>
/// <param name="rule"></param>
/// <returns></returns>
List<Field> GetFields(HtmlNode node, SpliderRule rule);
}
必不可少的规则类,用来配置XPath根路径。
/// <summary>
/// 采集规则-能满足列表页/详情页。
/// </summary>
public class SpliderRule
{
public string Id { get; set; }
public string Url { get; set; }
/// <summary>
/// 网页块
/// </summary>
public string ContentXPath { get; set; }
/// <summary>
/// 支持列表式
/// </summary>
public string EachXPath { get; set; }
/// <summary>
///
/// </summary>
public List<RuleField> RuleFields { get; set; }
}
然后就是属性字段的自定义设置,这里根据内容特性,加入了正则支持。例如评论数是数字,可用正则筛选出数字。还有Attribute字段,用来获取node的Attribute信息。
/// <summary>
/// 自定义属性字段
/// </summary>
public class RuleField
{
public string Id { get; set; }
public string DisplayName { get; set; }
/// <summary>
/// 用于存储的别名
/// </summary>
public string FieldName { get; set; }
public string XPath { get; set; }
public string Attribute { get; set; }
/// <summary>
/// 针对获取的HTml正则过滤
/// </summary>
public string InnerHtmlRegex { get; set; }
/// <summary>
/// 针对获取的Text正则过滤
/// </summary>
public string InnerTextRegex { get; set; }
/// <summary>
/// 是否优先取InnerText
/// </summary>
public bool IsFirstInnerText { get; set; }
}
下面是根据文章爬虫规则的解析步骤,实现接口IDataSplider
/// <summary>
/// 支持列表和详情页
/// </summary>
public class ArticleSplider : IDataSplider
{
/// <summary>
/// 根据Rule
/// </summary>
/// <param name="rule"></param>
/// <returns></returns>
public List<SpliderContent> GetByRule(SpliderRule rule)
{
var url = rule.Url;
HtmlWeb web = new HtmlWeb();
//1.支持从web或本地path加载html
var htmlDoc = web.Load(url);
var contentnode = htmlDoc.DocumentNode.SelectSingleNode(rule.ContentXPath);
var list = new List<SpliderContent>();
//列表页
if (!string.IsNullOrWhiteSpace(rule.EachXPath))
{
var itemsNodes = contentnode.SelectNodes(rule.EachXPath);
foreach (var item in itemsNodes)
{
var fields = GetFields(item, rule);
list.Add(new SpliderContent()
{
Fields = fields,
SpliderRuleId = rule.Id
});
}
return list;
}
//详情页
var cfields = GetFields(contentnode, rule);
list.Add(new SpliderContent()
{
Fields = cfields,
SpliderRuleId = rule.Id
});
return list;
}
public List<Field> GetFields(HtmlNode item, SpliderRule rule)
{
var fields = new List<Field>();
foreach (var rulefield in rule.RuleFields)
{
var field = new Field() { DisplayName = rulefield.DisplayName, FieldName = "" };
var fieldnode = item.SelectSingleNode(rulefield.XPath);
if (fieldnode != null)
{
field.InnerHtml = fieldnode.InnerHtml;
field.InnerText = fieldnode.InnerText;
field.AfterRegexHtml = !string.IsNullOrWhiteSpace(rulefield.InnerHtmlRegex) ? Regex.Replace(fieldnode.InnerHtml, rulefield.InnerHtmlRegex, "") : fieldnode.InnerHtml;
field.AfterRegexText = !string.IsNullOrWhiteSpace(rulefield.InnerTextRegex) ? Regex.Replace(fieldnode.InnerText, rulefield.InnerTextRegex, "") : fieldnode.InnerText;
//field.AfterRegexHtml = Regex.Replace(fieldnode.InnerHtml, rulefield.InnerHtmlRegex, "");
//field.AfterRegexText = Regex.Replace(fieldnode.InnerText, rulefield.InnerTextRegex, "");
if (!string.IsNullOrWhiteSpace(rulefield.Attribute))
{
field.Value = fieldnode.Attributes[rulefield.Attribute].Value;
}
else
{
field.Value = rulefield.IsFirstInnerText ? field.AfterRegexText : field.AfterRegexHtml;
}
}
fields.Add(field);
}
return fields;
}
}
还是以博客园为例,配置内容和属性的自定义规则
/// <summary>
///
/// </summary>
public void RunArticleRule()
{
var postitembodyXPath = "div[@class='post_item_body']//";
var postitembodyFootXPath = postitembodyXPath+ "div[@class='post_item_foot']//";
var rule = new SpliderRule()
{
ContentXPath = "//div[@id='post_list']",
EachXPath = "div[@class='post_item']",
Url = "https://www.cnblogs.com",
RuleFields = new List<RuleField>() {
new RuleField(){ DisplayName="推荐", XPath="*//span[@class='diggnum']", IsFirstInnerText=true },
new RuleField(){ DisplayName="标题",XPath=postitembodyXPath+"a[@class='titlelnk']", IsFirstInnerText=true },
new RuleField(){ DisplayName="URL",XPath=postitembodyXPath+"a[@class='titlelnk']",Attribute="href", IsFirstInnerText=true },
new RuleField(){ DisplayName="简要",XPath=postitembodyXPath+"p[@class='post_item_summary']", IsFirstInnerText=true },
new RuleField(){ DisplayName="作者",XPath=postitembodyFootXPath+"a[@class='lightblue']", IsFirstInnerText=true },
new RuleField(){ DisplayName="作者URL",XPath=postitembodyFootXPath+"a[@class='lightblue']",Attribute="href", IsFirstInnerText=true },
new RuleField(){ DisplayName="讨论数", XPath="span[@class='article_comment']",IsFirstInnerText=true, InnerTextRegex=@"[^0-9]+" },
new RuleField(){ DisplayName="阅读数", XPath=postitembodyFootXPath+"span[@class='article_view']",IsFirstInnerText=true, InnerTextRegex=@"[^0-9]+" },
}
};
var splider = new ArticleSplider();
var list = splider.GetByRule(rule);
foreach (var item in list)
{
var msg = string.Empty;
item.Fields.ForEach(M =>
{
if (M.DisplayName != "简要" && !M.DisplayName.Contains("URL"))
{
msg += $"{M.DisplayName}:{M.Value}";
}
});
Console.WriteLine(msg);
}
}
运行效果
效果完美!

经过简单的重构,我们已经达到了上篇的效果。
效果完美!
经过简单的重构,我们已经达到了上篇的效果。
常用规则模型和自定义规则模型
写到这里,我想到了一般UML图工具或Axsure原型等,都会内置各种常用组件,那么文章爬虫模型也是我们内置的一种常用组件了。后续我们完全可以按照上面的套路支持其他模型。除了常用模型之外,在网页或客户端上,高级的爬虫工具会支持用户自定义配置,根据配置来获取内容。
上面的SpliderRule已经能支持大部分内容管理系统单页面抓取。但无法支持规则相互引用,然后根据抓取的内容引用配置规则继续抓取。(这里也许有什么专门的名词来描述:递归爬虫?)。
今天主要是在上篇文章的基础上重构而来,支持了规则配置。为了有点新意,就多提供两个配置例子吧。
写到这里,我想到了一般UML图工具或Axsure原型等,都会内置各种常用组件,那么文章爬虫模型也是我们内置的一种常用组件了。后续我们完全可以按照上面的套路支持其他模型。除了常用模型之外,在网页或客户端上,高级的爬虫工具会支持用户自定义配置,根据配置来获取内容。
上面的SpliderRule已经能支持大部分内容管理系统单页面抓取。但无法支持规则相互引用,然后根据抓取的内容引用配置规则继续抓取。(这里也许有什么专门的名词来描述:递归爬虫?)。
今天主要是在上篇文章的基础上重构而来,支持了规则配置。为了有点新意,就多提供两个配置例子吧。
例子1:文章详情
我们以上篇文章为例,获取文章详情。 主要结点是标题,内容。其他额外属性暂不处理。

我们以上篇文章为例,获取文章详情。 主要结点是标题,内容。其他额外属性暂不处理。
编码实现
/// <summary>
/// 详情
/// </summary>
public void RunArticleDetail() {
var rule = new SpliderRule()
{
ContentXPath = "//div[@id='post_detail']",
EachXPath = "",
Url = " https://www.cnblogs.com/fancunwei/p/9581168.html",
RuleFields = new List<RuleField>() {
new RuleField(){ DisplayName="标题",XPath="*//div[@class='post']//a[@id='cb_post_title_url']", IsFirstInnerText=true },
new RuleField(){ DisplayName="详情",XPath="*//div[@class='postBody']//div[@class='blogpost-body']",Attribute="", IsFirstInnerText=false }
}
};
var splider = new ArticleSplider();
var list = splider.GetByRule(rule);
foreach (var item in list)
{
var msg = string.Empty;
item.Fields.ForEach(M =>
{
Console.WriteLine($"{M.DisplayName}:{M.Value}");
});
Console.WriteLine(msg);
}
}
/// <summary>
/// 详情
/// </summary>
public void RunArticleDetail() {
var rule = new SpliderRule()
{
ContentXPath = "//div[@id='post_detail']",
EachXPath = "",
Url = " https://www.cnblogs.com/fancunwei/p/9581168.html",
RuleFields = new List<RuleField>() {
new RuleField(){ DisplayName="标题",XPath="*//div[@class='post']//a[@id='cb_post_title_url']", IsFirstInnerText=true },
new RuleField(){ DisplayName="详情",XPath="*//div[@class='postBody']//div[@class='blogpost-body']",Attribute="", IsFirstInnerText=false }
}
};
var splider = new ArticleSplider();
var list = splider.GetByRule(rule);
foreach (var item in list)
{
var msg = string.Empty;
item.Fields.ForEach(M =>
{
Console.WriteLine($"{M.DisplayName}:{M.Value}");
});
Console.WriteLine(msg);
}
}
运行效果
效果同样完美!

效果同样完美!
例子2:天气预报
天气预报的例子,我们就以上海8-15天预报为例。
天气预报的例子,我们就以上海8-15天预报为例。
分析结构
点击链接,我们发现 今天/7天/8-15天/40天分别是不同的路由页面,那就简单了,我们只考虑当前页面就行。还有个问题,那个晴天雨天的图片,是按样式显示的。我们虽然能抓到html,但样式还未考虑,,HtmlAgilityPack应该有个从WebBrowser获取网页的,似乎能支持样式。本篇文章先跳过这个问题,以后再细究。

点击链接,我们发现 今天/7天/8-15天/40天分别是不同的路由页面,那就简单了,我们只考虑当前页面就行。还有个问题,那个晴天雨天的图片,是按样式显示的。我们虽然能抓到html,但样式还未考虑,,HtmlAgilityPack应该有个从WebBrowser获取网页的,似乎能支持样式。本篇文章先跳过这个问题,以后再细究。
配置规则
根据网页结构,配置对应规则。
public void RunWeather() {
var rule = new SpliderRule()
{
ContentXPath = "//div[@id='15d']",
EachXPath = "*//li",
Url = "http://www.weather.com.cn/weather15d/101020100.shtml",
RuleFields = new List<RuleField>() {
new RuleField(){ DisplayName="日期",XPath="span[@class='time']", IsFirstInnerText=true },
new RuleField(){ DisplayName="天气",XPath="span[@class='wea']",Attribute="", IsFirstInnerText=false },
new RuleField(){ DisplayName="区间",XPath="span[@class='tem']",Attribute="", IsFirstInnerText=false },
new RuleField(){ DisplayName="风向",XPath="span[@class='wind']",Attribute="", IsFirstInnerText=false },
new RuleField(){ DisplayName="风力",XPath="span[@class='wind1']",Attribute="", IsFirstInnerText=false },
}
};
var splider = new ArticleSplider();
var list = splider.GetByRule(rule);
foreach (var item in list)
{
var msg = string.Empty;
item.Fields.ForEach(M =>
{
msg += $"{M.DisplayName}:{M.Value} ";
});
Console.WriteLine(msg);
}
}
根据网页结构,配置对应规则。
public void RunWeather() {
var rule = new SpliderRule()
{
ContentXPath = "//div[@id='15d']",
EachXPath = "*//li",
Url = "http://www.weather.com.cn/weather15d/101020100.shtml",
RuleFields = new List<RuleField>() {
new RuleField(){ DisplayName="日期",XPath="span[@class='time']", IsFirstInnerText=true },
new RuleField(){ DisplayName="天气",XPath="span[@class='wea']",Attribute="", IsFirstInnerText=false },
new RuleField(){ DisplayName="区间",XPath="span[@class='tem']",Attribute="", IsFirstInnerText=false },
new RuleField(){ DisplayName="风向",XPath="span[@class='wind']",Attribute="", IsFirstInnerText=false },
new RuleField(){ DisplayName="风力",XPath="span[@class='wind1']",Attribute="", IsFirstInnerText=false },
}
};
var splider = new ArticleSplider();
var list = splider.GetByRule(rule);
foreach (var item in list)
{
var msg = string.Empty;
item.Fields.ForEach(M =>
{
msg += $"{M.DisplayName}:{M.Value} ";
});
Console.WriteLine(msg);
}
}
运行效果
效果再次完美!

效果再次完美!
源码
上述代码已提交到GitHub
上述代码已提交到GitHub
总结探讨
综上所述,我们实现单页面的自定义规则,但也遗留了一个小问题。天气预报晴天阴天效果图,原文是用样式展示的。针对这种不规则问题,如果代码定制当然很容易,但如果做成通用,有什么好办法呢?请提出你的建议!心情好的,顺便点个推荐...
下篇文章,继续探讨多页面/递归爬虫自定义规则的实现。
.NetCore实践爬虫系统(二)自定义规则的更多相关文章
- .NetCore实践爬虫系统(一)解析网页内容
爬虫系统的意义 爬虫的意义在于采集大批量数据,然后基于此进行加工/分析,做更有意义的事情.谷歌,百度,今日头条,天眼查都离不开爬虫. 今日目标 今天我们来实践一个最简单的爬虫系统.根据Url来识别网页 ...
- 《CMake实践》笔记二:INSTALL/CMAKE_INSTALL_PREFIX
<CMake实践>笔记一:PROJECT/MESSAGE/ADD_EXECUTABLE <CMake实践>笔记二:INSTALL/CMAKE_INSTALL_PREFIX &l ...
- 《CMake实践》笔记二:INSTALL/CMAKE_INSTALL_PREFIX【转】
本文转载自:http://www.cnblogs.com/52php/p/5681751.html 四.更好一点的Hello World 没有最好,只有更好 从本小节开始,后面所有的构建我们都将采用 ...
- 基于golang分布式爬虫系统的架构体系v1.0
基于golang分布式爬虫系统的架构体系v1.0 一.什么是分布式系统 分布式系统是一个硬件或软件组件分布在不同的网络计算机上,彼此之间仅仅通过消息传递进行通信和协调的系统.简单来说就是一群独立计算机 ...
- 【转】RHadoop实践系列之二:RHadoop安装与使用
RHadoop实践系列之二:RHadoop安装与使用 RHadoop实践系列文章,包含了R语言与Hadoop结合进行海量数据分析.Hadoop主要用来存储海量数据,R语言完成MapReduce 算法, ...
- 机器学习算法与Python实践之(二)支持向量机(SVM)初级
机器学习算法与Python实践之(二)支持向量机(SVM)初级 机器学习算法与Python实践之(二)支持向量机(SVM)初级 zouxy09@qq.com http://blog.csdn.net/ ...
- scrapy分布式爬虫scrapy_redis二篇
=============================================================== Scrapy-Redis分布式爬虫框架 ================ ...
- PySpider 爬虫系统
PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI.采用Python语言编写,分布式架构,支持多种数据库后端,强大的WebUI支持脚本编辑器,任务监视器,项目管理器以及结果查看器 ...
- java编程排序之内置引用类型的排序规则实现,和自定义规则实现+冒泡排序运用
第一种排序:[冒泡排序]基本数据类型的排序. [1]最简易的冒泡排序.效率低.因为比较的次数和趟数最多. /** * 最原始的冒泡排序. * 效率低. * 因为趟数和次数最多.都是按最大化的循环次数进 ...
随机推荐
- MySQL crash-safe replication(3): MySQL的Crash Safe和Binlog的关系
2016-12-23 17:29 宋利兵 作者:宋利兵 来源:MySQL代码研究(mysqlcode) 0.导读 本文重点介绍了InnoDB的crash safe和binlog之间的关系,以及2阶段提 ...
- 转:C#常用的集合类型(ArrayList类、Stack类、Queue类、Hashtable类、Sort)
C#常用的集合类型(ArrayList类.Stack类.Queue类.Hashtable类.Sort) .ArrayList类 ArrayList类主要用于对一个数组中的元素进行各种处理.在Array ...
- UNIX高级环境编程(12)进程关联(Process Relationships)- 终端登录过程 ,进程组,Session
在前面的章节我们了解到,进程之间是有关联的: 每个进程都有一个父进程: 子进程退出时,父进程可以感知并且获取子进程的退出状态. 本章我们将了解: 进程组的更多细节: sessions的内容: logi ...
- gl 绘制多边形的函数解析 分类: OpenGL(转)
http://blog.csdn.net/zhongjling/article/details/7528091 1,所谓正反面 glFrontFace(GL_CCW); // 设置CCW方向为“正面 ...
- mariadb使用\s查看用户权限
今天出现一个问题就是:给zabbix用户赋予权限 语句如下: grant all on zabbix.* to 'zabbix'@'%' identified by 'zabbix' 按照这样的说法应 ...
- 有关java编辑器myeclipse编辑网站的一些设置(个人习惯)
一.界面显示设置 首先进入一个新的空间,里面的设置肯定都是默认的.点击上方导航栏的window-Perferences-Appearance可以去进行设置界面的显示,Theme中可以选择windows ...
- 服务器 一 MQTT服务器硬件
目的: 实现手机4G网络控制单片机,需要搭建服务器,手机或者各种控制端远程控制. 本教程 1 MQTT服务器硬件模块 2 MQTT服务器电脑搭建 2.1自己搭建 2.2租阿里云服务器 2 MQTT服 ...
- 分享一个excel根据文件超链接获取链接文档的最后更新时间
#获取制定单元格内超链接对应的链接地址Sub geturi() For Each cell In Range("E3:E43") If cell.Hyperlinks.Count ...
- tarjan 求割点
在无向连通图中,如果将其中一个点以及所连的所有边都删掉,图就不再连通的话,那么这个点就叫做割点 首先将所有的点分为:1.环中点 2.不成环的单点割点一般出现的情况是:如果(处在不同环中/一环一单点/均 ...
- 如何在Drupal7中用代码批量创建节点、评论和分类
最近,我忙于一个网站迁移工作.网站是使用某个老式CMS建立的,有一定数量的文章.不同的分类数据和用户评论.我的团队被雇来把这些数据从这个浪费人力物力的老式CMS上完整的迁移到功能更现代的开源Drupa ...