queryString--网络爬虫
原文链接:https://www.cnblogs.com/yizhiamumu/p/9046017.html /n querystring字面上的意思就是查询字符串,一般是对http请求所带的数据进行解析。querystring模块只提供4个方法:
- querystring.parse
- querystring.stringify
- querystring.escape
- querystring.unescape
这4个方法是相对应的。
首先,使用querystring模块之前,需要require进来:
const querystring = require("querystring");
其次,就可以使用模块下的方法了:
1 querystring.parse(str,separator,eq,options)
parse这个方法是将一个字符串反序列化为一个对象。
参数:
- str指需要反序列化的字符串;
- separator(可省)指用于分割str这个字符串的字符或字符串,默认值为"&";
- eq(可省)指用于划分键和值的字符或字符串,默认值为"=";
- options(可省)该参数是一个对象,里面可设置maxKeys和decodeURIComponent这两个属性:
- maxKeys:传入一个number类型,指定解析键值对的最大值,默认值为1000,如果设置为0时,则取消解析的数量限制;
- decodeURIComponent:传入一个function,用于对含有%的字符串进行解码,默认值为querystring.unescape。在官方API的例子中,使用gbkDecodeURIComponent这个方法会报错,显示gbkDecodeURIComponent is no defined,这是因为在使用这个gbkDecodeURIComponent这个方法之前需要先进行定义。在API中也写了Assuming gbkDecodeURIComponent function already exists...这句话的意思是”假设这个gbkDecodeURIComponent方法已经存在”。
例子1,querystring.parse
1 querystring.parse("name=whitemu&sex=man&sex=women"); 2 /* 3 return: 4 { name: 'whitemu', sex: [ 'man', 'women' ] } 5 */ 6 querystring.parse("name=whitemu#sex=man#sex=women","#",null,{maxKeys:2}); 7 /* 8 return: 9 { name: 'whitemu', sex: 'man' } 10 */
2 querystring.stringify(obj,separator,eq,options)
stringify这个方法是将一个对象序列化成一个字符串,与querystring.parse相对。
参数:
- obj指需要序列化的对象
- separator(可省)用于连接键值对的字符或字符串,默认值为"&";
- eq(可省)用于连接键和值的字符或字符串,默认值为"=";
- options(可省)传入一个对象,该对象可设置encodeURIComponent这个属性:
encodeURIComponent:值的类型为function,可以将一个不安全的url字符串转换成百分比的形式,默认值为querystring.escape()。
例子2,querystring.stringify
querystring.stringify({name: 'whitemu', sex: [ 'man', 'women' ] }); /* return: 'name=whitemu&sex=man&sex=women' */ querystring.stringify({name: 'whitemu', sex: [ 'man', 'women' ] },"*","$"); /* return: 'name$whitemu*sex$man*sex$women' */
3 querystring.escape(str)
escape可使传入的字符串进行编码
例子3,querystring.escape
querystring.escape("name=慕白"); /* return: 'name%3D%E6%85%95%E7%99%BD' */
4 querystring.unescape(str)
unescape方法可将含有%的字符串进行解码
例子4,querystring.unescape
querystring.unescape('name%3D%E6%85%95%E7%99%BD'); /* return: 'name=慕白' */
小结:
querystring这个模块相对的还是比较简单,仅有4个方法。
- querystring.stringify序列化;
- querystring.parse反序列化;
- querystring.escape编码;
- querystring.unescape解码;
进阶版
可以写一个函数,专门用于做转换
private object ConvertParameter(string name, object defaultValue, bool isRequired)
我们甚至还可以把它抽象出来一个方法。
提取抽象方法
用Attribute和反射的思想,首先给变量设置HttpQueryString的属性,绑定上相应的QueryString,然后由Page基类来读取相应的QueryString信息。
属性这么写(HttpQueryStringAttribute.cs):
[AttributeUsage(AttributeTargets.Field)]
</span><span style="color: #0000ff;">public</span> sealed <span style="color: #0000ff;">class</span><span style="color: #000000;"> HttpQueryStringAttribute : Attribute {
</span><span style="color: #0000ff;">private</span><span style="color: #000000;"> string _name;
</span><span style="color: #0000ff;">private</span><span style="color: #000000;"> object _defaultValue;
</span><span style="color: #0000ff;">private</span><span style="color: #000000;"> bool _isRequired;
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> HttpQueryStringAttribute(string name) {
_name </span>=<span style="color: #000000;"> name;
_defaultValue </span>= <span style="color: #0000ff;">null</span><span style="color: #000000;">;
_isRequired </span>= <span style="color: #0000ff;">true</span><span style="color: #000000;">;
}
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> HttpQueryStringAttribute(string name, object defaultValue) {
_name </span>=<span style="color: #000000;"> name;
_defaultValue </span>=<span style="color: #000000;"> defaultValue;
_isRequired </span>= <span style="color: #0000ff;">false</span><span style="color: #000000;">;
}
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> string Name {
get { </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> _name; }
}
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> object DefaultValue {
get { </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> _defaultValue; }
}
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> bool IsRequired
{
get { </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> _isRequired; }
}
} </span></pre>
页面基类是这样的(PageBase.cs):
public class PageBase : Page { protected override void OnLoad(System.EventArgs e) { ParameterInitialize(); base.OnLoad(e); }</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> ParameterInitialize() { Type type </span>= <span style="color: #0000ff;">this</span><span style="color: #000000;">.GetType(); FieldInfo[] fields </span>=<span style="color: #000000;"> type.GetFields(); foreach (FieldInfo field in fields) { HttpQueryStringAttribute attribute </span>=<span style="color: #000000;"> (HttpQueryStringAttribute)Attribute.GetCustomAttribute(field, typeof(HttpQueryStringAttribute)); </span><span style="color: #0000ff;">if</span> (attribute != <span style="color: #0000ff;">null</span><span style="color: #000000;">) { SetField(field, attribute); } } } </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> SetField(FieldInfo field, HttpQueryStringAttribute attribute) { </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (attribute.IsRequired) { </span><span style="color: #0000ff;">if</span> (Request.QueryString[attribute.Name] != <span style="color: #0000ff;">null</span><span style="color: #000000;">) { SetFieldValue(field, </span><span style="color: #0000ff;">this</span><span style="color: #000000;">, attribute.Name, field.FieldType); } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> Exception(string.Format("Query string /"{0}/" is required", attribute.Name), <span style="color: #0000ff;">new</span><span style="color: #000000;"> NullReferenceException()); } } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { </span><span style="color: #0000ff;">if</span> (attribute.DefaultValue == <span style="color: #0000ff;">null</span> || field.FieldType ==<span style="color: #000000;"> attribute.DefaultValue.GetType()) { </span><span style="color: #0000ff;">if</span> (Request.QueryString[attribute.Name] == <span style="color: #0000ff;">null</span> || Request.QueryString[attribute.Name] ==<span style="color: #000000;"> string.Empty) { field.SetValue(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">, attribute.DefaultValue); } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { SetFieldValue(field, </span><span style="color: #0000ff;">this</span><span style="color: #000000;">, attribute.Name, field.FieldType); } } </span><span style="color: #0000ff;">else</span><span style="color: #000000;"> { </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> Exception(string.Format("Invalid default value of query string /"{0}/"({1})", attribute.Name, field.Name), <span style="color: #0000ff;">new</span><span style="color: #000000;"> NullReferenceException()); } } } </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> SetFieldValue(FieldInfo field, object obj, string name, Type conversionType) { </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> { field.SetValue(obj, Convert.ChangeType(Request.QueryString[name], conversionType)); } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception ex) { </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> Exception(string.Format("The given value of query string /"{0}/" can not be convert to {1}"<span style="color: #000000;">, name, conversionType), ex); } } } </span></pre>
在页面里,这样写就OK了(Default.aspx.cs):
public partial class _Default : PageBase { [HttpQueryString("Name", "Anonymous")] public string name;[HttpQueryString(</span>"UserId"<span style="color: #000000;">)] </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> userId; </span><span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> Page_Load(object sender, EventArgs e) { Response.Write(string.Format(</span>"Name is {0}<br/>"<span style="color: #000000;">, name)); Response.Write(string.Format(</span>"UserId is {0}<br/>"<span style="color: #000000;">, userId)); }
}
讨论
根据定义的变量的数据类型自动转换对应的QueryString,可以省去以后在页面里处理Query String的代码。
反过来想,QueryString 的处理没必要上升到反射的高度,复杂的实现也许会丧失一定的灵活性。比如我某个值忽然要改为从 Form 里面得到呢?从 Session 得到呢?这时候就可以比较出哪种做法更适合敏捷的适应需求。
页面里的 QueryString 的处理,之所以大家都很痛恨手工写编码,无非是因为这么几点:
- 需要判断是否 == null 才敢用 .ToString(), 很不爽。稍微不注意,就会抛出异常导致页面错误。
- 整形,double 等值类型从 QueryString 里面获取的时候,不知道是否为合法的数值,因此 Parse 的时候总是要写重复的处理异常的代码。