打印

Google投放广告的js的分析

大家平时见到google的广告太多了,但有没有兴趣知道一下它的运行过程呢?

下面我们一起来看看这个广告代码的执行过程,以及其中的一些精彩内容。
阿权(hqlulu)平时也会投放google的广告,不过帐户还是$0.00,呵呵。
今天特意想研究一下它的运行过程,来给大家分享一下。

我们先看看下面的代码,是通过google的设置得到的:
复制内容到剪贴板
代码:
<script type="text/javascript"><!--
google_ad_client = "pub-2063594891864588";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "text_image";
google_ad_channel = "";
google_color_border = "E6E6E6";
google_color_bg = "E6E6E6";
google_color_link = "000000";
google_color_text = "333333";
google_color_url = "666666";
//--></script>
<script type="text/javascript"
  src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
明显,先设置一些参数,再调用该js文件,完成广告的投放。
下面把show_ads.js下载回来,我们分析一下:

首先就让我惊讶的是,文件里面首先就是一个这样的结构:
复制内容到剪贴板
代码:
(function(){……})()
我特意发贴问了一下,谢谢mozart0给了他的看法,再次总结一下:
首先,从最后一个括号看出来,这个是调用一个对象,而这个对象就是 function(){……} 建立后返回的
mozart0说:“直观的好处是把几条需要顺序执行的语句组织成一个单元,使逻辑清晰,又不用为它取名字,可能出于节约的考虑:该匿名函数像一个临时变量,执行后可以被立即销毁,当然连同其中的局部变量”
总体而言,就是建立了一个对象,并且执行它,同时,销毁了一切,一定程度实现了对对象的保护和保密

(A)() 执行效果:先定义A对象,然后执行A对象,执行完毕,A对象就被销毁了

这个是一个不错的方法,值得大家学习借鉴。

好了,我们看看“……”里面的代码,看完一遍就知道它是做了什么。
我整理了一下,按层次结构排列好(这个过程花费的时间也不少呢),没有修改里面的代码,只是加了注释和层次关系的整理。

大体执行过程为:

01 定义字符串操作函数,往URL后添加各种参数 c(b,a) 等
02 定义收集用户端信息的函数 function D(b,a)
03 定义输出广告代码的函数function G(b,a,d)
04 定义对象重置的函数function F(b)
05 定义添加各种参数到URL的函数function A()
06 定义屏幕信息检测函数function x(b,a)
07 定义页面初始化函数function E()
08 运行初始化函数
09 处理应该带上的参数
10 收集客户端信息
11 按指定的方式输出广告代码
12 对象重置

可能因为技术上的问题,这段js代码里面的函数名称都是很奇怪的,为了增加用户查看的难度吧?
在这里仅列举几个函数,其余见后面附上的完整代码

1 往URL上添加参数
复制内容到剪贴板
代码:
//如果值存在,则在广告链接后面加上参数
function c(b,a){
    if(a){
        window.google_ad_url+="&"+b+"="+a
    }
}
2 取得客户端信息
复制内容到剪贴板
代码:
//取得浏览器的参数 [执行步骤:03]
//这个是属于用户调查啦,也没收集多少隐私吧,呵呵
function D(b,a){
    var d=b.screen,g=navigator.javaEnabled(),e=-a.getTimezoneOffset();
    //用户浏览器属性
    if(d){
        c("u_h",d.height);
        c("u_w",d.width);
        c("u_ah",d.availHeight);
        c("u_aw",d.availWidth);
        c("u_cd",d.colorDepth)
    }
    //用户时区
    c("u_tz",e);
    //用户历史记录长度
    c("u_his",history.length);
    //用户浏览器对java的设置
    c("u_java",g);
    //用户plugins长度
    if(navigator.plugins){
        c("u_nplug",navigator.plugins.length)
    }
    //用户mimeTypes长度
    if(navigator.mimeTypes){
        c("u_nmime",navigator.mimeTypes.length)
    }
}
3 输出广告代码
复制内容到剪贴板
代码:
//输出广告代码到页面中 [执行步骤:04]
function G(b,a,d){
    d=d.substring(0,1000);
    //用正则表达式去掉末尾的 %+单个字符
    d=d.replace(/%\w?$/,"");
    //按不同的广告类型,输出广告代码
    //m函数是给数值两边加上引号
    if(b.google_ad_output=="js"&&(b.google_ad_request_done||b.google_radlink_request_done)){
        //把广告代码的地址输出,加载该文件
        a.write('<script language="JavaScript1.1" src='+m(d)+"><\/script>")
    }else if(b.google_ad_output=="html"){
        if(b.name!="google_ads_frame"){
                a.write('<iframe name="google_ads_frame" width='+m(b.google_ad_width)+" height="+m(b.google_ad_height)+" frameborder="+m(b.google_ad_frameborder)+" src="+m(d)+' marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" scrolling="no">');
                a.write("</iframe>")
        }
    }else if(b.google_ad_output=="textlink"){
        a.write('<script language="JavaScript1.1" src='+m(d)+"><\/script>")
    }
}
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com
整个js文件整理之后的代码为:
复制内容到剪贴板
代码:
(function(){
    // parse by hqlulu
    // www.aslibra.com
    // 2007-3-10
    //返回把参数用引号括起来的值
    function m(b){
        return b!=null?'"'+b+'"':'""'
    }
    //把参数转换字符
    function B(b){
        if(typeof encodeURIComponent=="function"){
            return encodeURIComponent(b)
        }else{
            return escape(b)
        }
    }
    //如果值存在,则在广告链接后面加上参数
    function c(b,a){
        if(a){
            window.google_ad_url+="&"+b+"="+a
        }
    }
    //把值转换字符并加到链接后面
    function f(b,a){
        if(a){
            c(b,B(a))
        }
    }
    //如果中间的参数是对象的话,则取时间与对象长度余数的值?
    function l(b,a,d){
        if(a&&typeof a=="object"){
            a=a[d%a.length]
        }
        c("color_"+b,a)
    }
    ///////////////  以上是定义在网址后加上参数的函数  ///////////////////
    //取得浏览器的参数 [执行步骤:03]
    //这个是属于用户调查啦,也没收集多少隐私吧,呵呵
    function D(b,a){
        var d=b.screen,g=navigator.javaEnabled(),e=-a.getTimezoneOffset();
        //用户浏览器属性
        if(d){
            c("u_h",d.height);
            c("u_w",d.width);
            c("u_ah",d.availHeight);
            c("u_aw",d.availWidth);
            c("u_cd",d.colorDepth)
        }
        //用户时区
        c("u_tz",e);
        //用户历史记录长度
        c("u_his",history.length);
        //用户浏览器对java的设置
        c("u_java",g);
        //用户plugins长度
        if(navigator.plugins){
            c("u_nplug",navigator.plugins.length)
        }
        //用户mimeTypes长度
        if(navigator.mimeTypes){
            c("u_nmime",navigator.mimeTypes.length)
        }
    }
    //检查参数是否以 ca- 开始,否则添加 ca-
    function y(b){
        b=b.toLowerCase();
        if(b.substring(0,3)!="ca-"){
            b="ca-"+b
        }
        return b
    }
    //输出广告代码到页面中 [执行步骤:04]
    function G(b,a,d){
        d=d.substring(0,1000);
        //用正则表达式去掉末尾的 %+单个字符
        d=d.replace(/%\w?$/,"");
        //按不同的广告类型,输出广告代码
        //m函数是给数值两边加上引号
        if(b.google_ad_output=="js"&&(b.google_ad_request_done||b.google_radlink_request_done)){
            //把广告代码的地址输出,加载该文件
            a.write('<script language="JavaScript1.1" src='+m(d)+"><\/script>")
        }else if(b.google_ad_output=="html"){
            if(b.name!="google_ads_frame"){
                    a.write('<iframe name="google_ads_frame" width='+m(b.google_ad_width)+" height="+m(b.google_ad_height)+" frameborder="+m(b.google_ad_frameborder)+" src="+m(d)+' marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" scrolling="no">');
                    a.write("</iframe>")
            }
        }else if(b.google_ad_output=="textlink"){
            a.write('<script language="JavaScript1.1" src='+m(d)+"><\/script>")
        }
    }
    //把对象的各个参数都置为null  [执行步骤:05] 结束
    //因为页面里面有多个广告代码的话,就混乱了,所以执行这个,以便下一个广告
    //同时,也防止页面里面直接用js查看设置的对象的值
    function F(b){
        var a=null;
        b.google_ad_frameborder=a;
        b.google_ad_format=a;
        b.google_page_url=a;
        b.google_language=a;
        b.google_gl=a;
        b.google_country=a;
        b.google_region=a;
        b.google_city=a;
        b.google_hints=a;
        b.google_safe=a;
        b.google_encoding=a;
        b.google_ad_output=a;
        b.google_max_num_ads=a;
        b.google_ad_channel=a;
        b.google_contents=a;
        b.google_alternate_ad_url=a;
        b.google_alternate_color=a;
        b.google_color_bg=a;
        b.google_color_text=a;
        b.google_color_link=a;
        b.google_color_url=a;
        b.google_color_border=a;
        b.google_color_line=a;
        b.google_adtest=a;
        b.google_kw_type=a;
        b.google_kw=a;
        b.google_num_radlinks=a;
        b.google_max_radlink_len=a;
        b.google_rl_filtering=a;
        b.google_rl_mode=a;
        b.google_rt=a;
        b.google_ad_type=a;
        b.google_image_size=a;
        b.google_feedback=a;
        b.google_skip=a;
        b.google_page_location=a;
        b.google_referrer_url=a;
        b.google_ad_region=a;
        b.google_ad_section=a;
        b.google_bid=a;
        b.google_cpa_choice=a;
        b.google_cust_age=a;
        b.google_cust_gender=a;
        b.google_cust_interests=a;
        b.google_cust_id=a;
        b.google_cust_job=a;
        b.google_cust_u_url=a;
        b.google_cust_ch=a;
        b.google_ed=a;
        b.google_targeting=a;
        b.google_ad_host=a
    }
    //处理应该带上的参数以便显示广告 [执行步骤:02]
    function A(){
        //这里有几种加上参数的形式
        //c 直接加上
        //f 转义后加上
        //l 加上对象中的参数?
        var b=null,a=window,d=document,g=new Date,e=g.getTime(),j=a.google_ad_format;
        if(a.google_cpa_choice){
            a.google_ad_url="http://pagead2.googlesyndication.com/cpa/ads?";
            a.google_ad_url+="client="+escape(y(a.google_ad_client));
            a.google_ad_region="_google_cpa_region_";
            c("cpa_choice",a.google_cpa_choice);
            if(typeof d.characterSet!="undefined"){
                f("oe",d.characterSet)
            }else if(typeof d.charset!="undefined"){
                f("oe",d.charset)
            }
        }else{
            a.google_ad_url="http://pagead2.googlesyndication.com/pagead/ads?";
            a.google_ad_url+="client="+escape(y(a.google_ad_client))
        }
        c("host",a.google_ad_host);
        var k=a.google_num_slots_by_client,w=a.google_num_slots_by_channel,i=a.google_prev_ad_formats_by_region;a.onerror=a.google_org_error_handler;
        if(a.google_ad_region==b&&a.google_ad_section!=b){
            a.google_ad_region=a.google_ad_section
        }
        var h=a.google_ad_region==b?"":a.google_ad_region,q=false;
        if(j){
            q=j.indexOf("_0ads")>0
        }
        if(q){
            if(a.google_num_0ad_slots){
                a.google_num_0ad_slots=a.google_num_0ad_slots+1
            }else{
                a.google_num_0ad_slots=1
            }
            if(a.google_num_0ad_slots>3){
                return
            }
        }else if(!a.google_cpa_choice){
            if(a.google_num_ad_slots){
                a.google_num_ad_slots=a.google_num_ad_slots+1
            }else{
                a.google_num_ad_slots=1
            }
            if(a.google_num_slots_to_rotate){
                i[h]=b;
                if(a.google_num_slot_to_show==b){
                    a.google_num_slot_to_show=e%a.google_num_slots_to_rotate+1
                }if(a.google_num_slot_to_show!=a.google_num_ad_slots){
                    return
                }
            }else if(a.google_num_ad_slots>3&&h==""){
                return
            }
        }
        c("dt",g.getTime());
        c("hl",a.google_language);
        if(a.google_country){
            c("gl",a.google_country)
        }else{
            c("gl",a.google_gl)
        }
        c("gr",a.google_region);
        f("gcs",a.google_city);
        f("hints",a.google_hints);
        c("adsafe",a.google_safe);
        c("oe",a.google_encoding);
        c("lmt",a.google_last_modified_time);
        f("alternate_ad_url",a.google_alternate_ad_url);
        c("alt_color",a.google_alternate_color);
        c("skip",a.google_skip);
        c("targeting",a.google_targeting);
        var n=a.google_ad_client;
        if(!k[n]){
            k[n]=1;k.length+=1
        }else{
            k[n]+=1
        }
        if(i[h]){
            f("prev_fmts",i[h].toLowerCase());
            if(k.length>1){
                c("slot",k[n])
            }
        }
        if(j){
            f("format",j.toLowerCase());
            if(i[h]){
                i[h]=i[h]+","+j
            }else{
                i[h]=j
            }
        }
        c("num_ads",a.google_max_num_ads);
        c("output",a.google_ad_output);
        c("adtest",a.google_adtest);
        if(a.google_ad_channel){
            var r=a.google_ad_channel;
            f("channel",r);
            var s="",t=r.split("+");
            for(var o=0;o<t.length;o++){
                var p=t[o];
                if(!w[p]){
                    w[p]=1
                }else{
                    s+=p+"+"
                }
            }
            f("pv_ch",s)
        }
        //l 参数名称,对象,时间
        //开始处理js文件前面的颜色和大小等信息
        f("url",a.google_page_url);
        l("bg",a.google_color_bg,e);
        l("text",a.google_color_text,e);
        l("link",a.google_color_link,e);
        l("url",a.google_color_url,e);
        l("border",a.google_color_border,e);
        l("line",a.google_color_line,e);
        c("kw_type",a.google_kw_type);
        f("kw",a.google_kw);
        f("contents",a.google_contents);
        c("num_radlinks",a.google_num_radlinks);
        c("max_radlink_len",a.google_max_radlink_len);
        c("rl_filtering",a.google_rl_filtering);
        c("rl_mode",a.google_rl_mode);
        c("rt",a.google_rt);
        c("ad_type",a.google_ad_type);
        c("image_size",a.google_image_size);
        c("region",a.google_ad_region);
        c("feedback_link",a.google_feedback);
        f("ref",a.google_referrer_url);
        f("loc",a.google_page_location);
        c("bid",a.google_bid);
        c("cust_age",a.google_cust_age);
        c("cust_gender",a.google_cust_gender);
        c("cust_interests",a.google_cust_interests);
        c("cust_id",a.google_cust_id);
        c("cust_job",a.google_cust_job);
        c("cust_u_url",a.google_cust_u_url);
        c("cust_ch",a.google_cust_ch);
        c("ed",a.google_ed);
        if(z(a,d)&&d.body){
            var u=d.body.scrollHeight,v=d.body.clientHeight;
            if(v&&u){
                f("cc",Math.round(v*100/u))
            }
        }
        //调用显示广告的代码
        D(a,g);
        G(a,d,a.google_ad_url);
        F(a)
    }
    //错误处理 window.onerror 则调用这个
    function C(b,a,d){
        A();
        return true
    }
    //判断本页面是否处于框架内,不是则返回真
    //(疑问:如果网页A包含网页A呢,导致死循环包含,加上脚本可以避免死循环呢?会不会出错?)
    function z(b,a){
        return b.top.location==a.location
    }
    //b: window对象  a: document对象
    //检测屏幕信息
    function x(b,a){
        var d=a.documentElement;
        if(z(b,a))
            return false;
        //不处于框架中
        if(b.google_ad_width&&b.google_ad_height){
            var g=1,e=1;
            //检测可显示区域
            //参数意义可以参考:
            // JS测试屏幕信息 http://www.aslibra.com/down/test_info.html
            if(b.innerHeight){
                g=b.innerWidth;e=b.innerHeight
            }else if(d&&d.clientHeight){
                g=d.clientWidth;e=d.clientHeight
            }else if(a.body){
                g=a.body.clientWidth;
                e=a.body.clientHeight
            }
            if(e>2*b.google_ad_height||g>2*b.google_ad_width){
                return false
            }
        }
        return true
    }
    //页面初始化处理 [执行步骤:01]
    //建立对象,记录文件属性以及来源等信息
    function E(){
        //定义错误处理
        var b=window,a=document,d=a.location,g=a.referrer,e=null;b.google_org_error_handler=b.onerror;b.onerror=C;
        //初始化window对象下的变量
        if(b.google_ad_frameborder==e){
            b.google_ad_frameborder=0
        }
        if(b.google_ad_output==e){
            b.google_ad_output="html"
        }
        if(b.google_ad_format==e&&b.google_ad_output=="html"){
            b.google_ad_format=b.google_ad_width+"x"+b.google_ad_height
        }
        if(b.google_page_url==e){
            b.google_page_url=g;
            if(!x(b,a)){
                b.google_page_url=d;
                b.google_last_modified_time=Date.parse(a.lastModified)/1000;
                b.google_referrer_url=g
            }
        }else{
            b.google_page_location=g;
            if(!x(b,a)){
                b.google_page_location=d
            }
        }
        if(b.google_num_slots_by_channel==e){
            b.google_num_slots_by_channel=[]
        }
        if(b.google_num_slots_by_client==e){
            b.google_num_slots_by_client=[]
        }
        if(b.google_prev_ad_formats_by_region==e){
            b.google_prev_ad_formats_by_region=[]
        }
    }
    //先检查处理页面参数
    E();
    //处理应该带上的参数
    A();
})()
有注释不对的地方还希望大家指正,谢谢!
附件: 您所在的用户组无法下载或查看附件,您需要注册/登录后才能查看!
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com