Asp.net Google Analytics Browsers stats

Нужна была толковая аналитика по браузерам, analytics такой инфы не дает, пришлось набросать свое.

Стандартный asp.net сайт.

Для работы необходимо подключить: Google.GData.Analytics, Google.GData.Client, Google.GData.Extensions.

http://code.google.com/intl/ru-RU/apis/gdata/articles/dotnet_client_lib.html

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="browserstats._Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>browserstats</title>
    <style type="text/css">
        html,body {padding:0;margin:0;overflow:hidden;}
        form {padding:0;margin:0;}
        #browsers-filter-holder {position:absolute;top:1em;left:1em;background-color:#eee;padding:1em;}
        #browsers-filter-holder a {diplay:block;text-decoration:none;border-bottom:1px dashed #0072bc;color:#0072bc;}
        #browsers-filter-holder {background:#FFFFFF;background: -moz-linear-gradient(top,#FFFFFF,#EEEEEE);background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#EEEEEE));filter: progid:DXImageTransform.Microsoft.gradient(enabled='true',startColorstr=#FFFFFF,endColorstr=#EEEEEE,GradientType=0);-moz-border-radius:10px;-webkit-border-radius:10px;border-radius:10px;-moz-box-shadow: 0px 0px 5px #000000;-webkit-box-shadow: 0px 0px 5px #000000;box-shadow: 0px 0px 5px #000000;}
        #browsers-filter-holder {filter:progid:DXImageTransform.Microsoft.Alpha(opacity=50);-moz-opacity: 0.5;-khtml-opacity: 0.5;opacity: 0.5;}
        #browsers-filter-holder:hover {filter:progid:DXImageTransform.Microsoft.Alpha(opacity=100);-moz-opacity: 1;-khtml-opacity: 1;opacity: 1;}
    </style>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
        function toggle_filter() {
            var cnt = document.getElementById('browsers-filter-content');
            if (!cnt) return false;

            cnt.style.display = (cnt.style.display == 'none') ? 'block' : 'none';

            return false;
        }
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <div id="browsers-filter-holder">
            <a href="javascript:void(0)" onclick="toggle_filter()">Filter results</a>
            <div id="browsers-filter-content" style="display:none;">
                <asp:CheckBoxList ID="cblBrowsers" runat="server"></asp:CheckBoxList>
                <asp:Button ID="btnSubmit" runat="server" onclick="btnSubmit_Click" Text="Submit" />
            </div>
        </div>
        <div id="chart"></div>

        <script type="text/javascript">
            google.load("visualization", "1", {packages:["corechart"]});
            google.setOnLoadCallback(drawChart);
            function drawChart() {
                var data = new google.visualization.DataTable();

                <asp:Literal ID="ltJsData" runat="server" />

                var windowWidth = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth;
                var windowHeight = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight;

                var chart = new google.visualization.LineChart(document.getElementById('chart'));
                chart.draw(data, {
                            width: windowWidth,
                            height: windowHeight,
                            title: 'rabota.ua browsers',
                            hAxis: {title: 'Month'},
                            vAxis: {title: '%', minValue: 0, maxValue: 50},
                            lineWidth: 2,
                            pointSize: 7,

                            });
            }
        </script>

    </form>
</body>
</html>

Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Google.GData.Analytics;
using Google.GData.Client;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Data;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace browserstats
{
    public partial class _Default : System.Web.UI.Page
    {
        public static string LOGIN = "[email protected]";
        public static string PASSWORD = "PASSWORD";
        public static string SITE_ID = "ga:2266524";
        public static int MIN_PERCENTS = 0;
        public static string CACHE_KEY = "rabota_ua_browser_stats";
        public static string DATATABLE_OBJ_PATH = HttpContext.Current.Server.MapPath("~/DataTable.obj");

        protected DataTable Get_DataTable(bool flushCache)
        {
            DataTable dt;
            if (flushCache || DateTime.Now.Month != (new FileInfo(DATATABLE_OBJ_PATH)).LastWriteTime.Month)
            {
                dt = Read_Data_From_Analytics();
                Stream stream = File.Open(DATATABLE_OBJ_PATH, FileMode.Create);
                BinaryFormatter bFormatter = new BinaryFormatter();
                bFormatter.Serialize(stream, dt);
                stream.Close();
            }
            else
            {
                Stream stream = File.Open(DATATABLE_OBJ_PATH, FileMode.Open);
                BinaryFormatter bFormatter = new BinaryFormatter();
                dt = (DataTable)bFormatter.Deserialize(stream);
                stream.Close();
            }
            return dt;
        }

        protected DataTable Read_Data_From_Analytics()
        {
            AnalyticsService service = new AnalyticsService("rabota_ua_browser_stats");
            service.setUserCredentials(LOGIN, PASSWORD);

            string start_date = new DateTime(DateTime.Now.AddYears(-1).Year, DateTime.Now.Month, 1).ToString("yyyy-MM-dd");
            string end_date = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).ToString("yyyy-MM-dd");
            List<DataFeed> feeds = new List<DataFeed>();
            string queryUri = "https://www.google.com/analytics/feeds/data" +
                                "?start-date=" + start_date +
                                "&end-date=" + end_date +
                                "&dimensions=ga:month,ga:browser,ga:browserVersion" +
                                "&metrics=ga:pageviews" +
                                "&sort=ga:month" +
                                "&max-results=10000" +
                                "&filters=ga:browserVersion!%3D(not%20set);ga:browserVersion!~%5E0;ga:browser%3D%3DFirefox,ga:browser%3D%3DOpera,ga:browser%3D%3DChrome,ga:browser%3D%3DInternet%20Explorer" +
                                "&ids=" + SITE_ID;

            while (queryUri != null)
            {
                DataFeed dataFeed = service.Query(new DataQuery(queryUri));
                feeds.Add(dataFeed);
                queryUri = dataFeed.NextChunk;
            }

            List<slice> slices = new List<slice>();
            foreach (DataFeed dataFeed in feeds)
            {
                foreach (AtomEntry item in dataFeed.Entries)
                {
                    string month = ((DataEntry)item).Dimensions[0].Value;
                    string browser = ((DataEntry)item).Dimensions[1].Value;
                    string browserVersion = ((DataEntry)item).Dimensions[2].Value;
                    string pageViews = ((DataEntry)item).Metrics[0].Value;

                    browserVersion = Regex.Replace(browserVersion, @"(\d+).*", "$1", RegexOptions.IgnoreCase);

                    int bv = int.Parse(browserVersion);

                    if (bv == 0 || bv > 20) continue;

                    double pv = double.Parse(pageViews);

                    slices.Add(new slice(month, browser, bv, pv));
                }
            }
            feeds = default(List<DataFeed>);

            //group results by month, browser and browserVersion and sum pageViews
            var q = from x in slices
                    group x by new { x.month, x.browser, x.browserVersion } into g
                    select new slice(g.Key.month, g.Key.browser, g.Key.browserVersion, g.Sum(s => s.pageViews));

            //group results by month and sum pageViews
            var pageViewsByMonth = from x in slices
                                    group x by x.month into g
                                    select new { month = g.Key, pageViews = g.Sum(s => s.pageViews) };

            //group results by browser and sum pageViews
            var pageViewsByBrowser = from x in slices
                                        group x by new { x.month, x.browser } into g
                                        select new { month = g.Key.month, browser = g.Key.browser, pageViews = g.Sum(s => s.pageViews) };

            //group results by browser and version and sum pageViews
            var pageViewsByBrowserVersion = from x in slices
                                            group x by new { x.month, x.browser, x.browserVersion } into g
                                            select new { month = g.Key.month, browser = string.Format("{0} {1}", g.Key.browser, g.Key.browserVersion), pageViews = g.Sum(s => s.pageViews) };

            //join grouped results for browsers and their versions
            var totalStatsByBrowsers = pageViewsByBrowser.Union(pageViewsByBrowserVersion).OrderBy(x => x.month).ThenByDescending(x => x.pageViews);

            //convert pageviews to percents
            var totalStatsByBrowsersPercentage = from x in totalStatsByBrowsers
                                                    where Math.Round(x.pageViews / ((pageViewsByMonth.First(m => m.month == x.month)).pageViews / 100)) > MIN_PERCENTS
                                                    select new { month = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(int.Parse(x.month)), browser = x.browser, percent = Math.Round(x.pageViews / ((pageViewsByMonth.First(m => m.month == x.month)).pageViews / 100)) };

            //grouped month names
            var tm = from x in totalStatsByBrowsersPercentage
                        group x by x.month into g
                        select g.Key;

            //grouped browser names
            var tb = from x in totalStatsByBrowsersPercentage
                        group x by x.browser into g
                        orderby g.Key
                        select g.Key;

            DataTable dt = new DataTable();
            dt.Columns.Add(new DataColumn("Month", typeof(string)));
            foreach (var b in tb)
            {
                dt.Columns.Add(new DataColumn(b, typeof(double)));
            }

            foreach (string m in tm)
            {
                DataRow dr = dt.NewRow();
                dr["Month"] = m;

                foreach (string b in tb)
                {
                    var o = totalStatsByBrowsersPercentage.FirstOrDefault(x => x.month == m && x.browser == b);
                    string p = (o == null) ? "0" : o.percent.ToString();

                    dr[b] = p;
                }

                dt.Rows.Add(dr);
            }

            return dt;
        }

        protected List<string> Build_Browsers_Filter(DataTable dt)
        {
            List<string> browsers = Build_Browsers_List(dt);
            List<string> browsersFilter = new List<string>();
            if (IsPostBack)
            {
                browsersFilter = (from x in cblBrowsers.Items.Cast<ListItem>()
                                    where x.Selected
                                    select x.Value).ToList<string>();
            }
            else {
                //browsersFilter = browsers;
                browsersFilter.Add("Internet Explorer");
                browsersFilter.Add("Internet Explorer 6");
                browsersFilter.Add("Internet Explorer 7");
                browsersFilter.Add("Internet Explorer 8");
                browsersFilter.Add("Firefox");
                browsersFilter.Add("Opera");
                browsersFilter.Add("Chrome");
            }

            return browsersFilter;
        }

        protected List<string> Build_Browsers_List(DataTable dt)
        {
            return (from x in dt.Columns.Cast<DataColumn>()
                    where x.ColumnName != "Month"
                    select x.ColumnName).ToList<string>();
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            DataTable dt;
            if (HttpContext.Current.Cache[CACHE_KEY] == null)
            {
                dt = Get_DataTable(false); //TODO: add ability to flush cache
                HttpContext.Current.Cache[CACHE_KEY] = dt;
            }
            else
            {
                dt = (DataTable)HttpContext.Current.Cache[CACHE_KEY];
            }

            List<string> browsers = Build_Browsers_List(dt);
            List<string> browsersFilter = Build_Browsers_Filter(dt);

            StringBuilder sb = new StringBuilder();

            sb.AppendLine("data.addColumn('string', 'Month');");
            foreach (string b in browsersFilter)
            {
                sb.AppendLine(string.Format("data.addColumn('number', '{0}');", b));
            }

            sb.AppendLine();
            sb.AppendLine("data.addRows(12);");
            sb.AppendLine();

            for(int r = 0; r < dt.Rows.Count; r++)
            {
                sb.AppendLine(string.Format("data.setValue({0}, 0, '{1}');", r, dt.Rows[r]["Month"]));
                for(int i = 0; i < browsersFilter.Count; i++)
                {
                    sb.AppendLine(string.Format("data.setValue({0}, {1}, {2});", r, (i + 1), dt.Rows[r][browsersFilter[i]]));
                }
                sb.AppendLine();
            }

            ltJsData.Text = sb.ToString();

            cblBrowsers.DataSource = browsers;
            cblBrowsers.DataBind();
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {

        }
    }

    public class slice
    {
        public slice(string Month, string Browser, int BrowserVersion, double PageViews)
        {
            month = Month;
            browser = Browser;
            browserVersion = BrowserVersion;
            pageViews = PageViews;
        }
        public string month;
        public string browser;
        public int browserVersion;
        public double pageViews;
    }
}

Собственно вот как это все выглядит:

video