通用采集小工具重构之路——字符处理规则重构
之前由于工作的原因,写过一个通用网站数据采集的小工具,通过配置XML来采集不同的网站内容。
这段时间工作闲暇之余,觉得有必要重构一下,顺便学习学习,特此记录。
字符处理规则重构
字符处理应该算是采集中得一个核心内容,如果在一大串HTML字符串中提取成我们需要的字段。先看看之前的处理方式:
View Code
string temp2; temp2 = GetStr(str, MyConfig.Url, Lev); //字符截取规则 temp2 = ReplaceStr(temp2, MyConfig.UrlGL, Lev); //字符过滤规则 temp2 = SetCodeing(temp2, MyConfig.UrlBM, Lev);//字符URL编码规则 temp2 = Myreplace(temp2,MyConfig.UrlGvContent,Lev);//字符替换规则
分析毛病:
1. 客户端调用次数太多,如果有四个规则则需要调用四个规则。
2. 扩展不灵活,如果以后遇到新的采集需求而现有的规则不满足要求,需要添加新的规则,则不符合“开闭原则”
下面让我们开始重构吧:
1. 提取公用的规则接口
文字处理规则接口
/// <summary> /// 文字处理规则接口 /// </summary> public interface ItextRule { /// <summary> /// 字符处理 /// </summary> /// <param name="sourceStr">待处理字符串</param> /// <param name="key">配置关键字</param> /// <param name="lev">当前层级</param> /// <returns></returns> string TextPro(string sourceStr,string key,int lev); }
2. 建立规则类的抽象类,写入一些公用的方法
字符处理规则基础类
/// <summary> /// 字符处理规则基础类 /// </summary> public abstract class TextRuleBase { private string myKey = string.Empty; public TextRuleBase(string _key) { myKey = _key; } /// <summary> /// 获取配置文件的值 /// </summary> /// <param name="key"></param> /// <param name="lev"></param> /// <returns></returns> protected string[] GetValue(string key,int lev) { string str = string.Empty; string temp = string.Empty; string tempKey = key + myKey + lev; bool Istrue = true; while(Istrue) //循环读配置,知道为空 { temp = SiteConfig.ConfigByKey(tempKey); if (temp == "") { Istrue = false; } else { str += temp + "|"; tempKey += lev; } } return str.Split(new char[]{'|'},StringSplitOptions.RemoveEmptyEntries); } /// <summary> /// 具体规则处理 强制子类实现 /// </summary> /// <param name="sourceStr"></param> /// <param name="Content"></param> /// <returns></returns> protected abstract string TextPro(string sourceStr, string[] Contents); }
3. 建立字符规则类,按照上面的逻辑分别建立4个字符规则类,继承接口和抽象类
字符截取规则 基本规则
/// <summary> /// 字符截取规则 基本规则 /// </summary> public class TextIntercept :TextRuleBase, ItextRule { public TextIntercept():base("") { } #region ItextRule 公开成员 /// <summary> /// 字符截取规则具体实现(多次) /// </summary> /// <param name="sourceStr"></param> /// <param name="key"></param> /// <param name="lev"></param> /// <returns></returns> public string TextPro(string sourceStr, string key, int lev) { return TextPro(sourceStr,GetValue(key,lev)); } #endregion #region 内部强制私有方法 /// <summary> /// 字符截取规则具体实现(多次) /// </summary> /// <param name="sourceStr"></param> /// <param name="Content"></param> /// <returns></returns> protected override string TextPro(string sourceStr, string[] Contents) { string relText = sourceStr; foreach (string value in Contents) { if (value != "") { relText = Function.GetStr(relText, value, MyConfig.Key); } } Console.WriteLine("字符截取规则结果:" + relText); Console.WriteLine(""); return relText; } #endregion }
这里就只建立一个示例,其他同。或详见CODE
4. 建立一个高层接口,供客户端直接调用,内部封装好各种规则(根据配置)
字符处理规则的高层接口
/// <summary> /// 字符处理规则的高层接口 /// </summary> public class TextRuleAll:ItextRule { private Dictionary<string, IList<ItextRule>> ruleList = new Dictionary<string, IList<ItextRule>>(); #region ItextRule 成员 public string TextPro(string sourceStr, string key, int lev) { string dicKey = key + lev; string returnStr = string.Empty; if (!ruleList.ContainsKey(dicKey)) { IList<ItextRule> list = new List<ItextRule>(); #region 根据配置构建关键字规则列表 foreach (string vale in MyConfig.AllTextRules()) { string[] temp = vale.Split('.'); string xmlKey = temp[temp.Length - 1]; if (xmlKey == "TextIntercept") //写死 字符截取规则为基本规则 xmlKey = ""; if (SiteConfig.ConfigByKey(key + xmlKey + lev) != "") //XML文件有此配置关键字 { list.Add((ItextRule)Assembly.Load("Demo1").CreateInstance(vale)); } } #endregion ruleList.Add(dicKey,list); } IList<ItextRule> mylist = ruleList[dicKey]; if (mylist != null && mylist.Count > 0) //循环执行各种规则处理 { returnStr = sourceStr; foreach (ItextRule irule in mylist) returnStr = irule.TextPro(returnStr, key, lev); } return returnStr; } #end
5. 配置文件
XML配置
<MyConfig> <!--字符处理扩展规则列表--> <!--TextIntercept为截取规则--> <!--StaticReplace为静态替换规则--> <AllTextRules>Collect.TextRule.TextIntercept,Collect.TextRule.StaticReplace,Collect.TextRule.TextUrlEncode,Collect.TextRule.TextFilter</AllTextRules> <!--TextIntercept截取规则配置--> <Name1>邮件地址是[内容]</Name1> <!--StaticReplacej静态替换配置--> <NameStaticReplace1>#,@</NameStaticReplace1> <NameStaticReplace11>fuwentao,fwt</NameStaticReplace11> <!--中文URL编码规则配置--> <NameTextUrlEncode1>city=[内容]</NameTextUrlEncode1> <!--过滤规则配置--> <NameTextFilter1>.com,[内容]http</NameTextFilter1> </MyConfig>
重构完了,让我们再看看客户端的调用:
string testStr = "我是fuwentao,我的邮件地址是fwt1314111#163.com,网址http://www.mywaysoft.net/city=上海"; TextRuleAll cmd = new TextRuleAll(); string rel= cmd.TextPro(testStr, "Name", 1); //结果
就一句cmd.TextPro搞定!是不是比之前简单多了。
并且,这样灵活性也很强,以后如果要增加新的处理规则,则只需要建立一个规则类,然后再配置文件中配置一下就OK啦。