语言百度统计的JS脚本原理分析

【转】五、谈扩展方法的知道

先是,百度统计会要求我们于苟统计的页面中置放一截js语句,类似如下:

缘何而就此扩展方法

在说啊是扩大方法之前我们事先来说说胡要因此扩展方法。

第一我们定义一个 Person 类:

public class Person
{
    /// <summary>
    /// 出生日期
    /// </summary>
    public DateTime BirthTime { get; set; }
    /// <summary>
    /// 死亡日期
    /// </summary>
    public DateTime? DeathTime { get; set; }
    //、、、、、、
}

进入者近乎来自第三正的dll引用,且现在咱们需要加上一个术 GetAge 获取年龄。你或许会见想到自己必一个子类继承:

public class MyPerson : Person
{
    public int GetAge()
    {
        if (DeathTime.HasValue)
            return (DeathTime.Value - BirthTime).Days / 365;
        else
            return (DateTime.Now - BirthTime).Days / 365;
    }
}

没错,这样可以实现我们的急需。不过实现增产的方式就是错过继承真的是极方便的也(暂且不说)? 如果上面定义之密封类呢? public sealed class
Person ,这个时刻是无能够延续的,我们不得不另想办法。

擅自刻画个静态类:

public static class ExtensionClass
{
    public static int GetAge(Person person)
    {
        if (person.DeathTime.HasValue)
            return (person.DeathTime.Value - person.BirthTime).Days / 365;
        else
            return (DateTime.Now - person.BirthTime).Days / 365;
    }

接下来调用  age =
ExtensionClass.GetAge(p); ,是的看似对。可是就同我们说的扩大方法发生什么关联为?下面就见证奇迹的上了。

语言 1

外的其余地方都非变换,唯一变化之是在参数前面加里this关键字。对,是的,仅仅如此它便成为了咱今天一经提的恢宏方法。

调用如:  var age =
p.GetAge(); 相比上面的 age =
ExtensionClass.GetAge(p); 更简单明了。

此地我们说之凡在用扩大密封类的艺术时,我们可以及扩张方法。还有一样栽状况就算是,在急需扩大接口的时节下咱们尤其要。比如,需要扩大IList的排序。我们还是写单扩大方法,要么是持续实现接口(会强制要求兑现接口下的有着办法)。我想你心里就有矣答案选择啊种办法。

<script type=”text/javascript”>
var _bdhmProtocol = ((“https:” == document.location.protocol) ? ”
https://” : ” http://”);
document.write(unescape(“%3Cscript src=’” + _bdhmProtocol +
“hm.baidu.com/h.js%3F3266e9d3684eaa1337dc7c4b4b64b0ae’
type=’text/javascript’%3E%3C/script%3E”));
</script>

扩张方法到底是什么

咱们视上面用的恢宏方法,有无产生觉得非常神奇。仅仅多上加了一个this关键字就一直可以算作扩展方法以了。那扩展方法到底是呀东东,看了面代码好像和静态方法有说不清道不明的关联。下面我们累分析:

分别定义一个静态方法和一个扩张方法

 public static class ExtensionClass
 {
     public static int GetAge2(Person person)
     {
         if (person.DeathTime.HasValue)
             return (person.DeathTime.Value - person.BirthTime).Days / 365;
         else
             return (DateTime.Now - person.BirthTime).Days / 365;
     }

     public static int GetAge(this Person person)
     {
         if (person.DeathTime.HasValue)
             return (person.DeathTime.Value - person.BirthTime).Days / 365;
         else
             return (DateTime.Now - person.BirthTime).Days / 365;
     }

独家调用:

var p = new Person() { BirthTime = DateTime.Parse("1990-07-19") };
var age = p.GetAge();
age = ExtensionClass.GetAge2(p);

编译后的IL代码:

语言 2

咱俩视反编译成IL之后发现双方并随便例外。所以,我晓得成(扩展方法本质上就是静态方法,之所以出现恢弘方法是C#为另外一种样式展现静态方法而已。只有产生哪美用底会连续上课)。且 语言 3编译后语言 4平带动达了静态类名。

 

恢宏方法可以开些什么

  • 管早已有些静态方法转成扩展方法:如:

    public static bool IsNullOrEmpty(this string str)
    {

    return string.IsNullOrEmpty(str);
    

    }

调用: 

string str = null;
var isNull = str.IsNullOrEmpty();

 感觉相比期静态方法调用要优雅,更接近我们的自然语言。

  •  可以编制很多底增援类似,如(以string为条例):

语言 5语言 6

/// <summary>
        /// 转DateTime 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static DateTime? MyToDateTime(this string str)
        {
            if (string.IsNullOrEmpty(str))
                return null;
            else
                return DateTime.Parse(str);
        }

        /// <summary>
        /// 转double
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static double MyToDouble(this string str)
        {
            if (string.IsNullOrEmpty(str))
                return -1;
            else
                return double.Parse(str);
        }

        /// <summary>
        /// 转int
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static int MyToInt(this string str)
        {
            if (string.IsNullOrEmpty(str))
                return -1;
            else
                return int.Parse(str);
        }

        /// <summary>
        /// 指示指定的字符串是 null 还是 System.String.Empty 字符串。
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsNullOrEmpty(this string str)
        {
            return string.IsNullOrEmpty(str);
        }

        /// <summary>
        /// 如果字符串为null,则返回空字符串。(否则返回原字符串)
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string GetValueOrEmpty(this string str)
        {
            if (str.IsNullOrEmpty())
                return string.Empty;
            return str;
        }

View Code

方装有的且单是扩张方法的叠加用处,扩展方法确实的威力是也Linq服务的(主要反映为IEnumerable和IQueryable),实现链式编程。下面我们团结来促成所谓的链式编程:

初始化 Person 集合。

List<Person> persons = new List<Person>() 
{
     new Person(){ BirthTime=DateTime.Parse("1990-01-19")},
     new Person(){ BirthTime=DateTime.Parse("1993-04-17")},
     new Person(){ BirthTime=DateTime.Parse("1992-07-19"), DeathTime=DateTime.Parse("2010-08-18")},
     new Person(){ BirthTime=DateTime.Parse("1990-03-14")},
     new Person(){ BirthTime=DateTime.Parse("1991-08-15")},
     new Person(){ BirthTime=DateTime.Parse("1993-07-29")},
     new Person(){ BirthTime=DateTime.Parse("1991-06-19")}
};

需:1.询问活人。2.以出生日期排序

public static class ExtensionClass
    {
        /// <summary>
        /// 按条件查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IList<T> MyWhere<T>(this IList<T> list, Func<T, bool> func)
        {
            List<T> newList = new List<T>();
            foreach (var item in list)
            {
                if (func(item))
                    newList.Add(item);
            }
            return newList;
        }

        /// <summary>
        /// 升序排序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IList<T> MyOrderBy<T>(this IList<T> list, Func<T, DateTime> func)
        {
            if (list.Count() <= 1)
                return list;

            for (int i = 0; i < list.Count(); i++)
            {
                for (int j = i + 1; j < list.Count(); j++)
                {
                    var item1 = list[j - 1];
                    var item2 = list[j];
                    if ((func(item1) - func(item2)).Ticks > 0)
                    {
                        list[j - 1] = item2;
                        list[j] = item1;
                    }
                }
            }
            return list;
        }
        /// <summary>
        /// 降序排序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IList<T> MyOrderByDescending<T>(this IList<T> list, Func<T, DateTime> func)
        {
            if (list.Count() <= 1)
                return list;

            for (int i = 0; i < list.Count(); i++)
            {
                for (int j = 1; j < list.Count() - i; j++)
                {
                    var item1 = list[j - 1];
                    var item2 = list[j];
                    if ((func(item1) - func(item2)).Ticks < 0)
                    {
                        list[j - 1] = item2;
                        list[j] = item1;
                    }
                }
            }
            return list;
        }
    }

调用:(这里仅仅为演示,所以不用谈论实现是否成立、算法是否快捷。)

var newPersons = persons.MyWhere(t => t.DeathTime == null).MyOrderByDescending(t => t.BirthTime);
foreach (var item in newPersons)
{
    Console.WriteLine(item.BirthTime);
}

纵使是这么简单的落实了所谓的函数式编程。结果图如下:

语言 7

这么平等词代码搞定所有逻辑,像自然语言般的流畅。其实.net为IEnumerable实现了这样的扩充,如:

语言 8

执行组织和点一样模子一样。

 

实际扩展方法为可算作静态方法来使:

 var p1 = ExtensionClass.MyWhere(persons, t => t.DeathTime == null);
 var p2 = ExtensionClass.MyOrderByDescending(p1, t => t.BirthTime);
 var p3 = ExtensionClass.MyOrderBy(p2, t => t.BirthTime);

(不信教?继续羁押,有图有真相)

 

C#代码:

 语言 9

反编译C#的代码:(你是不是见到了,编译后一直就是下的恢弘方法的形式。)

语言 10

反编译的IL代码:

语言 11

则编译后的代码是相同的,但是做为程序员的我们再爱好哪种艺术为?语言 12

 

总结:

咱于针对扩大方法的怎么使疑惑或者忘记了平整之上,我们不用去追寻资料说:

  1. 率先只参数是设扩大或者只要操作的种,这叫做”被扩大的路”
  2. 以指定扩展方法,要以让扩大的类型名称前附加this修饰符
  3. 设拿方作为一个扩展方法来走访,要为此using指令导入扩展项目的命名空间,或者使扩展类型和调用代码在和一个命名空间中.

我们一味需要记住,当你免晓得怎么编写或使用扩展方法时,你先将她算静态方法编写或用。如果中,一般都得变更成为扩展方法的样式。

 

成套代码:

语言 13语言 14

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Data.Entity.Utilities;
using System.Diagnostics.CodeAnalysis;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using System.IO;

namespace test
{


    class Program
    {
        static void Main(string[] args)
        {
            /*             
             * 1.工具类
             * 2.链式编程
             */
            string str = null;
            var isNull = str.IsNullOrEmpty();

            var p = new Person() { BirthTime = DateTime.Parse("1990-07-19") };
            var age = p.GetAge();
            age = ExtensionClass.GetAge2(p);

            List<Person> persons = new List<Person>() 
            {
                 new Person(){ BirthTime=DateTime.Parse("1990-01-19")},
                 new Person(){ BirthTime=DateTime.Parse("1993-04-17")},
                 new Person(){ BirthTime=DateTime.Parse("1992-07-19"), DeathTime=DateTime.Parse("2010-08-18")},
                 new Person(){ BirthTime=DateTime.Parse("1990-03-14")},
                 new Person(){ BirthTime=DateTime.Parse("1991-08-15")},
                 new Person(){ BirthTime=DateTime.Parse("1993-07-29")},
                 new Person(){ BirthTime=DateTime.Parse("1991-06-19")}
            };

            var newPersons = persons.MyWhere(t => t.DeathTime == null).MyOrderByDescending(t => t.BirthTime);


            var p1 = ExtensionClass.MyWhere(persons, t => t.DeathTime == null);
            var p2 = ExtensionClass.MyOrderByDescending(p1, t => t.BirthTime);
            var p3 = ExtensionClass.MyOrderBy(p2, t => t.BirthTime);

            foreach (var item in newPersons)
            {
                Console.WriteLine(item.BirthTime);
            }
            Console.ReadKey();
        }
    }

    public sealed class Person
    {
        /// <summary>
        /// 出生日期
        /// </summary>
        public DateTime BirthTime { get; set; }
        /// <summary>
        /// 死亡日期
        /// </summary>
        public DateTime? DeathTime { get; set; }
    }

    //public class MyPerson : Person
    //{
    //    public int GetAge()
    //    {
    //        if (DeathTime.HasValue)
    //            return (DeathTime.Value - BirthTime).Days / 365;
    //        else
    //            return (DateTime.Now - BirthTime).Days / 365;
    //    }
    //}
    public static class ExtensionClass
    {
        /// <summary>
        /// 按条件查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IList<T> MyWhere<T>(this IList<T> list, Func<T, bool> func)
        {
            List<T> newList = new List<T>();
            foreach (var item in list)
            {
                if (func(item))
                    newList.Add(item);
            }
            return newList;
        }

        /// <summary>
        /// 升序排序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IList<T> MyOrderBy<T>(this IList<T> list, Func<T, DateTime> func)
        {
            if (list.Count() <= 1)
                return list;

            for (int i = 0; i < list.Count(); i++)
            {
                for (int j = i + 1; j < list.Count(); j++)
                {
                    var item1 = list[j - 1];
                    var item2 = list[j];
                    if ((func(item1) - func(item2)).Ticks > 0)
                    {
                        list[j - 1] = item2;
                        list[j] = item1;
                    }
                }
            }
            return list;
        }
        /// <summary>
        /// 降序排序
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static IList<T> MyOrderByDescending<T>(this IList<T> list, Func<T, DateTime> func)
        {
            if (list.Count() <= 1)
                return list;

            for (int i = 0; i < list.Count(); i++)
            {
                for (int j = 1; j < list.Count() - i; j++)
                {
                    var item1 = list[j - 1];
                    var item2 = list[j];
                    if ((func(item1) - func(item2)).Ticks < 0)
                    {
                        list[j - 1] = item2;
                        list[j] = item1;
                    }
                }
            }
            return list;
        }

        public static int GetAge2(Person person)
        {
            if (person.DeathTime.HasValue)
                return (person.DeathTime.Value - person.BirthTime).Days / 365;
            else
                return (DateTime.Now - person.BirthTime).Days / 365;
        }

        public static int GetAge(this Person person)
        {
            if (person.DeathTime.HasValue)
                return (person.DeathTime.Value - person.BirthTime).Days / 365;
            else
                return (DateTime.Now - person.BirthTime).Days / 365;
        }

        public static bool IsNullOrEmpty(this string str)
        {
            return string.IsNullOrEmpty(str);
        }
    } 
}

View Code

 

本文为联合到《C#基础知识巩固系列》

及时段js,实质上是向阳页面被引入hm.baidu.com/h.js的即时段代码,该代码的内容会基于后面的参数有所不同,h.js?后面的参数就是若当百度统计里之id。

获取该h.js代码的还要,百度统计会朝而的浏览器写副一个名字也“HMACCOUNT”的cookie,该cookie的晚点时呢2038年,所以若您无清空浏览器cookie,基本就不要过期。

h.js被下载后,便执行该脚本获取有浏览器相关消息及做客来源,获取的信包括屏幕尺寸、颜色深、flash版本、用户语言等。

起js代码中得博得,所有参数包括这些:”cc,cf,ci,ck,cl,cm,cp,cw,ds,ep,et,fl,ja,ln,lo,lt,nv,rnd,sb,se,si,st,su,sw,sse,v”。这些参数的意义大致如下:

cc: 不知道,一般为1
cf:url参数hmsr的值
ci:url参数hmci的值
ck:是否支持cookie 1:0
cl:颜色深浅 如 “32-bit”
cm:url参数hmmd的值
cp:url参数hmpl的值
cw:url参数hmkw的值
ds:屏幕尺寸,如 ’1024×768′
ep:初始值为’0′,时间变量,反映页面停留时间,格式大概是:现在时光-载入时间+“,”+另一个深粗的年月价值
et:初始值为’0′,如果ep时间变量不是0的言语,它见面成任何
fl:flash版本
ja:java支持 1:0
ln:语言 zh-cn
lo: 不知道,一般为0
lt:日期 time.time(),如“1327847756”, 在首涂鸦呼吁没有
nv: 不知道,一般为1或者0
rnd:十各项随机数字
sb:如果是360se浏览器该值等于‘17’
se: 和搜索引擎相关
si:统计代码id
st:
su:上一页document.referrer
sw: 不明了,估计跟找引擎有关,一般为空
sse:不掌握,估计跟查找引擎有关,一般为空
v:统计代码的版本 ,目前该值为“1.0.17”

当这些参数还装了了(有些参数并从未赋值),筛选产生已经赋值了之参数,并当hm.baidu.com/hm.gif的参数拼凑来一个url,如:http://hm.baidu.com/hm.gif?cc=1&ck=1&cl=32-bit&ds=1366×768&ep=0&et=0&fl=11.0&ja=1&ln=zh-cn
  。然后要该图。

百度统计服务端,通过接至之请,并从者图形的网址附带的参数获取有关消息,记录访客访问记录;当页面被用户关闭的时,同样会接触一浅呼吁hm.gif的过程,但这进程不是具浏览器与享有关闭动作都支持。

 

连下通过序模拟这等同进程:

第一,使用Wireshark(一慢性网络抓包工具)对浏览器实际的长河进展捕获。首先是利用ie打开一个生出超链接链接到有百度统计的网站,加载了后关闭浏览器。最后当Wireshark上博如此的纱数据包。

http://hm.baidu.com/h.js?3266e9d3684e7a1307dc7c4b4a64b0ae
http://hm.baidu.com/hm.gif?cc=1&ck=1&cl=32-bit&ds=1366×768&ep=0&et=0&fl=11.0&ja=1&ln=zh-cn&lo=0&lt;=1328171561&nv=1&rnd=2889921&si=3266e9d3684e7a1307dc7c4b4a64b0ae&st=3&su=http%3A%2F%2Fwww.zhanghangbo.com%2F&v=1.0.17
http://hm.baidu.com/hm.gif?cc=1&ck=1&cl=32-bit&ds=1366×768&ep=7289%2C115&et=3&fl=11.0&ja=1&ln=zh-cn&lo=0&lt;=1328171561&nv=1&rnd=1444115283&si=3266e9d3684e7a1307dc7c4b4a64b0ae&st=3&su=http%3A%2F%2Fwww.zhanghangbo.com%2F&v=1.0.17
http://hm.baidu.com/hm.gif?cc=1&ck=1&cl=32-bit&ds=1366×768&ep=212486%2C4614&et=3&fl=11.0&ja=1&ln=zh-cn&lo=0&lt;=1328171541&nv=1&rnd=1067394506&si=0f9e2caa14d6d0a51371b168d182314a&st=1&v=1.0.17

好窥见,浏览器总共向劳动器端发送了4浅呼吁:

  1. 请一段落js脚本。
  2. 加载了时出发一不良呼吁,并传递参数
  3. 退出页面下,发出同样次等呼吁,并传递参数,与方对比,发现ep参数有转移。

       
百度统计是冲cookie的,当求js脚本的时,会以您电脑里保存一个永久cookie,该cookie作为你的用户标识。同时发现,但离时参数ep从最开头之0变为了“7289%2C115”,转义后是“7289,115”这是片独毫秒单位,即7.2秒和0.1秒的意思。同时前片不成呼吁hm.gif的时段lt参数(时间,javascript:(new
Date).getTime())是无换的。rnd随机数每次都更换。

下面我们便来学一不行呼吁,本次用的python语言。

import urllib2
import urllib
import random
import math
import urlparse
import time
import cookielib

########################################################################
class Baidu:
“”””””
Referer=’http://www.lixin.me’
TargetPage=’/www.lixin.me’
BaiduID=”
Hjs=”http://hm.baidu.com/h.js?”
Hgif=”http://hm.baidu.com/hm.gif?”
UserAgent=’Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1;
Trident/5.0)’ #IE9
MyData={‘cc’:’1′,’ck’:’1′,’cl’:’32-bit’,’ds’:’1024×768′,’et’:’0′,’ep’:’0′,’fl’:’11.0′,’ja’:’1′,’ln’:’zh-cn’,’lo’:’0′,’nv’:’1′,’st’:’3′,’v’:’1.0.17′}
#———————————————————————-

def __init__(self,baiduID,targetPage=None,refererPage=None):
“””Constructor”””
self.TargetPage=targetPage or self.TargetPage
self.Referer=refererPage or self.Referer
self.BaiduID=baiduID
self.MyData[‘si’]=self.BaiduID
self.MyData[‘su’]=urllib.quote(self.Referer)
pass
def run(self,timeout=5):
cj=cookielib.CookieJar()
opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
opener.addheaders=[(“Referer”,self.TargetPage),(“User-Agent”,self.UserAgent)]
try:
response=opener.open(self.Hjs+self.BaiduID).info()
self.MyData[‘rnd’]=int(random.random()*2147483647 )
self.MyData[‘lt’]=int(time.time())
fullurl=self.Hgif+urllib.urlencode(self.MyData)
response2=opener.open(fullurl,timeout=timeout).info()
self.MyData[‘rnd’]=int(random.random()*2147483647 )
self.MyData[‘et’]=’3′
self.MyData[‘ep’]=’2000,100′
response3=opener.open(self.Hgif+urllib.urlencode(self.MyData),timeout=timeout).info()
pass
except urllib2.HTTPError ,ex:
print ex.code
pass
except urllib2.URLError,ex:
print ex.reason
pass
pass

if __name__ ==”__main__”:
a=Baidu(‘百度统计id’,’http://www.lixin.me/blog/test4','www.lixin.com.cn’)
a.run()

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图