[자바]Google Report API를 이용한 사이트 통계정보 가져오기, 성별, 페이지제목별, 연령구간대별,브라우저별,OS별…

FSP 0 22 01.08 12:50

 

[자바]Google Report API를 이용한 사이트 통계정보 가져오기, 성별, 페이지제목별, 연령구간대별,브라우저별,OS별,모바일디바이스 브랜드별로 페이지뷰, 접속사용자수, 접속세션수 

 

[1단계]

 

구글 통계 정보를 조회해서 API를 이용해 데이터를 자지고 오려면 

 

1. https://console.cloud.google.com/identity/serviceaccounts?folder=&organizationId=&project=top-creek-300922&supportedpurview=project

에서 사용자 추가, 아래 이메일이 그렇게 해서 만듦. 그리고 키파일 생성함

키파일은 자바 프로그램에서 사용하니 잘 보관해야 함

 

54be5713875141a7eb5af4712eb16aba_1610076
 

 

2. 위 사용자에 대해 구글 애널리틱스의 관리자에서 조회권한을 줘야 함

 

54be5713875141a7eb5af4712eb16aba_1610076
 

첫화면 좌하단 관리자 클릭

보기 à 보기 사용자관리 여기서 위에서 생성한 계정의 이메일을 통해 사용자 조회 권한을 부여함

 

54be5713875141a7eb5af4712eb16aba_1610077
 

 

[2단계, 자바코드 작성하기]

 

1. 마리아DB 테이블

 

CREATE TABLE T_GA_STATS(

start_ymd VARCHAR(8) ,

             end_ymd VARCHAR(8) ,

dimension VARCHAR(50),

             dim_val   VARCHAR(900),

page_views INT ,

             users INT ,

             sessions INT, 

reg_dt DATETIME DEFAULT CURRENT_TIMESTAMP,

mdfcn_dt DATETIME DEFAULT CURRENT_TIMESTAMP,

    PRIMARY KEY(start_ymd, end_ymd, dimension, dim_val)

)ENGINE = InnoDB  CHARACTER SET utf8;

 

 

2. ga.properties

 

#VIEW ID, 구글 애놀리틱스 화면에서 좌상 단 "전체웹사이트 데이터" 선택 후 팝업화면에서 오른쪽 전체웹사이트 데이터아래 숫자 입니다.

view.id=22931XXXX

 

#Key File Location, 파일명은 사용자 마다 다릅니다. 위 1에서 사용자 등록하고 키파일 만든 바로 그것 입니다.

key.file.location=c:\\/top-creek-3030922-ca1xbabc22484.json

 

#----------------------------------- Metric(측정항목) Start

#페이지뷰 Expression

metric1.expression=ga:pageviews

 

#페이지뷰 alias

metric1.alias=pageviews

 

#사용자수 Expression

metric2.expression=ga:users

 

#사용자수 alias

metric2.alias=users

 

#세션수 Expression

metric3.expression=ga:sessions

 

#세션수 alias

metric3.alias=sessions

#----------------------------------- Metric(측정항목) End

 

 

#----------------------------------- Dimension(측정기준) Start

#성별

dim1=ga:userGender

 

#페이지 제목별

dim2=ga:pageTitle

 

#연령 구간대별

dim3=ga:userAgeBracket

 

#브라우저별

dim4=ga:browser

 

#OS별

dim5=ga:operatingSystem

 

#모바일 디바이스 브랜드별

dim6=ga:mobileDeviceBranding

 

#기기별

dim7=ga:deviceCategory

#----------------------------------- Dimension(측정기준) End

 

3. mybatis-config.xml

 

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD config 3.0//EN" 

"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>

 

<!-- DB설정 파일 로딩 -->

<properties resource="db.properties" />

 

<typeAliases>

<typeAlias alias="GaStatsVO" type="jmx.vo.GaStatsVO" /> 

</typeAliases>

 

<!-- db1 : 마리아DB 연결 -->

<environments default="development">

<environment id="development">

<transactionManager type="JDBC" />

<dataSource type="POOLED">

<property name="driver" value="${db1.driver}" />

<property name="url" value="${db1.url}" />

<property name="username" value="${db1.id}" />

<property name="password" value="${db1.password}" />

<property name="poolPingQuery" value="select 1"/> <!-- 핑쿼리 추가 -->

<property name="poolPingEnabled" value="true"/> <!-- 핑쿼리 추가 -->

<property name="poolPingConnectionsNotUsedFor" value="7200000"/> <!-- 2시간마다 -->

<property name="poolMaximumActiveConnections" value="200"/> <!-- 주어진 시간에 존재할수 있는 활성화된 커넥션 수 -->

<property name="poolMaximumIdleConnections" value="200"/> <!-- 주어진 시간에 존재할 수 있는 유휴 커넥션의 수 -->

<property name="poolTimeToWait" value="20000"/> <!-- 풀이 로그 상태를 출력하고 비정상적으로 긴경우 커넥션을 다시얻을려고 시도하는 로우 레벨 셋팅 --> 

</dataSource>

</environment>

</environments>

 

<mappers>

<mapper resource="mapper/gastats.xml" />

</mappers>

 

</configuration>


4. 

GaStatsVO.java


package jmx.vo;

 

import lombok.Data;

 

/* ----------------------------------------------------------------------------

 *  File Name : GaStatsVO.java

 *  Desc : 구글 통계정보를 저장하기 위한 VO

 * ----------------------------------------------------------------------------

 */

@Data

public class GaStatsVO {

// 통계 시작년월일

private String start_ymd;

// 통계 종료년월일

private String end_ymd;

// 측정기준(성별, 브라우저별, OS별...... 접속현황, 이때 성별 이런것이 Dimension)

private String dimension;

// 측정기준값(male, female)

private String dim_val;

// 페이지뷰

private String page_views;

// 접속사용자수

private String users;

// 접속 세션수

private String sessions;

// 등록일시

private String reg_date;

// 수정일시

private String mdfcn_dt;

}

 

5. 매퍼 인터페이스(GaStatsMapper.java)

 

package jmx.db.mapper;

 

import jmx.vo.GaStatsVO;

 

/* ----------------------------------------------------------------------------

 *  File Name : GaStatsMapper.java

 *  Desc : 구글 통계정보 저장(T_GA_STATS)용 매퍼 인터페이스 

 * ----------------------------------------------------------------------------

 */

public interface GaStatsMapper {

// T_GA_STATS 입력(구글 통계정보)

public void insertGaStats(GaStatsVO gaStatsVO);

// T_GA_STATS 삭제(구글 통계정보)

public void deleteGaStats(GaStatsVO gaStatsVO);

}



6. DAO(GaStatsDAO.java)

 

package jmx.db.dao;

 

import org.apache.ibatis.session.SqlSession;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.log4j.LogManager;

import org.apache.log4j.Logger;

 

import jmx.db.mapper.GaStatsMapper;

import jmx.vo.GaStatsVO;

 

/* ----------------------------------------------------------------------------

 *  File Name : GaStatsDAO.java

 *  Desc : 구글 통계정보를 DB에 저장

 * ----------------------------------------------------------------------------

 */

public class GaStatsDAO {

 

final static Logger logger = LogManager.getLogger(GaStatsDAO.class);

private SqlSessionFactory sqlSessionFactory = null;

private SqlSession session = null;

 

public void getSession() {

sqlSessionFactory = DBConnectionFactory.getSqlSessionFactory();

session = sqlSessionFactory.openSession();

}

/**

* 구글 통계정보 저장

* @param gaStatsVO

* @throws Exception 

*/

public void insertGaStats(GaStatsVO gaStatsVO) throws Exception {

 

getSession();

GaStatsMapper mapper = session.getMapper(GaStatsMapper.class);

try {

mapper.insertGaStats(gaStatsVO);

catch(Exception e) {

session.rollback();

logger.info(">>>> insertGaStats Insert ERROR ::: " + e);

throw new Exception("insertGaStats Insert ERROR" + e.getMessage());

}

finally {

session.commit();

session.close();

session = null;

}

}

/**

* 구글 통계정보 삭제

* @param gaStatsVO

* @throws Exception 

*/

public void deleteGaStats(GaStatsVO gaStatsVO) throws Exception {

 

getSession();

GaStatsMapper mapper = session.getMapper(GaStatsMapper.class);

try {

mapper.deleteGaStats(gaStatsVO);

catch(Exception e) {

session.rollback();

logger.info(">>>> deleteGaStats Delete ERROR ::: " + e);

throw new Exception("deleteGaStats Delete ERROR" + e.getMessage());

}

finally {

session.commit();

session.close();

session = null;

}

}

 

}



7. resource 아래 mapper 아래 매퍼 XML(gastats.xml)


<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE mapper PUBLIC '-//mybatis.org//DTD Mapper 3.0//EN'

<mapper namespace='jmx.db.mapper.GaStatsMapper'>

<!-- 구글 통계정보 저장 -->
<insert id='insertGaStats' parameterType='GaStatsVO'>
INSERT INTO T_GA_STATS (
START_YMD
,END_YMD
,DIMENSION
,DIM_VAL
,PAGE_VIEWS
,USERS
,SESSIONS
)
VALUES(
#{start_ymd}
,#{end_ymd}
,REPLACE(#{dimension},'ga:', '')
,#{dim_val}
,CAST(#{page_views} AS UNSIGNED)
,CAST(#{users} AS UNSIGNED)
,CAST(#{sessions} AS UNSIGNED)
)
</insert>
<!-- 구글 통계정보 삭제 -->
<delete id='deleteGaStats' parameterType='GaStatsVO'>
DELETE FROM T_GA_STATS 
WHERE  START_YMD = #{start_ymd}
AND    END_YMD   = #{end_ymd}
</delete>
</mapper>


7. 구글 통계정보 읽기

package batch;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Properties;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.analyticsreporting.v4.AnalyticsReporting;
import com.google.api.services.analyticsreporting.v4.AnalyticsReportingScopes;
import com.google.api.services.analyticsreporting.v4.model.ColumnHeader;
import com.google.api.services.analyticsreporting.v4.model.DateRange;
import com.google.api.services.analyticsreporting.v4.model.DateRangeValues;
import com.google.api.services.analyticsreporting.v4.model.Dimension;
import com.google.api.services.analyticsreporting.v4.model.GetReportsRequest;
import com.google.api.services.analyticsreporting.v4.model.GetReportsResponse;
import com.google.api.services.analyticsreporting.v4.model.Metric;
import com.google.api.services.analyticsreporting.v4.model.MetricHeaderEntry;
import com.google.api.services.analyticsreporting.v4.model.Report;
import com.google.api.services.analyticsreporting.v4.model.ReportRequest;
import com.google.api.services.analyticsreporting.v4.model.ReportRow;

import jmx.db.dao.GaStatsDAO;
import jmx.vo.GaStatsVO;

/* ----------------------------------------------------------------------------
 *  File Name : GAStatistics.java
 *  Desc : 구글 통계정보 가지고 와서 DB 저장
 * ----------------------------------------------------------------------------
 */
public class GaStatistics {
// 화면 ID(22931XXXX로 고정)
private String viewId = null;
// 키파일 위치
private String keyFileLocation = null;
//----------------------------------- Metric(측정항목) Start
//측정항목1
private String metric1Expression = null;
private String metric1Alias = null;
//측정항목2
private String metric2Expression = null;
private String metric2Alias = null;
//측정항목3
private String metric3Expression = null;
private String metric3Alias = null;
//----------------------------------- Dimension Start
private String dim1 = null;
private String dim2 = null;
private String dim3 = null;
private String dim4 = null;
private String dim5 = null;
private String dim6 = null;
private String dim7 = null;

// GAStatistics 클래스가 new 될때 호출되는 초기화 블럭
{
// 구글 통뎨정보 가지고 오기 위한 설정 파일
loadProperties();
}

private String APPLICATION_NAME = "서구 Analytics Reporting";
private JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();

final static Logger logger = LogManager.getLogger(GaStatistics.class);
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("기간(일별)을 입력하세요. java batch.GaStatistics 2014-01-01 2020-12-31");
System.exit(1);
}

GaStatistics ga = new GaStatistics();
//기간을 확인
logger.info("::::: " + args[0] + " 부터 " + args[1] + " 까지 구글 통계정보를 가지고 옵니다");
try {
ga.getData(args[0], args[1]);
logger.info("::::: " + args[0] + " 부터 " + args[1] + " 까지 구글 통계정보를 가지고 옵니다");
}
catch(Exception e) {
e.printStackTrace();
}
}

/**
* Get Google Analytics Statistics Data 
* @throws Exception
*/
public void getData(String startDate, String endDate) throws Exception {
try {
AnalyticsReporting service = initializeAnalyticsReporting();

// 입력 기간 데이터 삭제
delete(startDate, endDate);
GetReportsResponse response1 = getReport1(service, startDate, endDate);
saveResponse(response1, startDate, endDate);
GetReportsResponse response2 = getReport2(service, startDate, endDate);
saveResponse(response2, startDate, endDate);
} catch (Exception e) {
logger.error(">>>>> 구글 애널리틱스 데이터 수신 오류! ::: " + e.getMessage());
throw new Exception(e);
}
}

/**
* Initializes an Analytics Reporting API V4 service object.
*
* @return An authorized Analytics Reporting API V4 service object.
* @throws IOException
* @throws GeneralSecurityException
*/
private AnalyticsReporting initializeAnalyticsReporting() throws GeneralSecurityException, IOException {

HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream(keyFileLocation))
.createScoped(AnalyticsReportingScopes.all());

// Construct the Analytics Reporting service object.
return new AnalyticsReporting.Builder(httpTransport, JSON_FACTORY, credential)
.setApplicationName(APPLICATION_NAME).build();
}

/**
* Queries the Analytics Reporting API V4.
* 주의 : Request의 MAX는 5개, 즉 통계정보를 받기 위한 요청은 최대5개
*      그래서 getReport1(5개), getReport2(2개) 만듦
*
* @param service An authorized Analytics Reporting API V4 service object.
* @return GetReportResponse The Analytics Reporting API V4 response.
* @throws IOException
*/
private GetReportsResponse getReport1(AnalyticsReporting service, String startDate, String endDate) throws IOException {
// Create the DateRange object.
DateRange dateRange = new DateRange();
dateRange.setStartDate(startDate);
dateRange.setEndDate(endDate);

// Create the Metrics object.
Metric metric1 = new Metric().setExpression(metric1Expression).setAlias(metric1Alias); // 페이지뷰
Metric metric2 = new Metric().setExpression(metric2Expression).setAlias(metric2Alias); // 사용자수
Metric metric3 = new Metric().setExpression(metric3Expression).setAlias(metric3Alias); // 세션수
Metric metrics[] = new Metric[3];
metrics[0] = metric1;
metrics[1] = metric2;
metrics[2] = metric3;
Dimension dimension1 = new Dimension().setName(dim1); // 성별
Dimension dimension2 = new Dimension().setName(dim2); // 페이지제목별
Dimension dimension3 = new Dimension().setName(dim3); // 연령 구간대별
Dimension dimension4 = new Dimension().setName(dim4); // 브라우저별
Dimension dimension5 = new Dimension().setName(dim5); // OS별
//Dimension dimension6 = new Dimension().setName(dim6); // 모바일디바이스 브랜드별
//Dimension dimension7 = new Dimension().setName(dim7); // 기기(Device)별

// Create the ReportRequest object.
ReportRequest request1 = new ReportRequest().setViewId(viewId).setDateRanges(Arrays.asList(dateRange))
.setMetrics(Arrays.asList(metrics)).setDimensions(Arrays.asList(dimension1));
ReportRequest request2 = new ReportRequest().setViewId(viewId).setDateRanges(Arrays.asList(dateRange))
.setMetrics(Arrays.asList(metrics)).setDimensions(Arrays.asList(dimension2));
ReportRequest request3 = new ReportRequest().setViewId(viewId).setDateRanges(Arrays.asList(dateRange))
.setMetrics(Arrays.asList(metrics)).setDimensions(Arrays.asList(dimension3));
ReportRequest request4 = new ReportRequest().setViewId(viewId).setDateRanges(Arrays.asList(dateRange))
.setMetrics(Arrays.asList(metrics)).setDimensions(Arrays.asList(dimension4));
ReportRequest request5 = new ReportRequest().setViewId(viewId).setDateRanges(Arrays.asList(dateRange))
.setMetrics(Arrays.asList(metrics)).setDimensions(Arrays.asList(dimension5));
//ReportRequest request6 = new ReportRequest().setViewId(viewId).setDateRanges(Arrays.asList(dateRange))
// .setMetrics(Arrays.asList(metrics)).setDimensions(Arrays.asList(dimension6));
//ReportRequest request7 = new ReportRequest().setViewId(viewId).setDateRanges(Arrays.asList(dateRange))
// .setMetrics(Arrays.asList(metrics)).setDimensions(Arrays.asList(dimension7));

ArrayList<ReportRequest> requests = new ArrayList<ReportRequest>();
requests.add(request1);
requests.add(request2);
requests.add(request3);
requests.add(request4);
requests.add(request5);
//requests.add(request6);
//requests.add(request7);

// Create the GetReportsRequest object.
GetReportsRequest getReport = new GetReportsRequest().setReportRequests(requests);

// Call the batchGet method.
GetReportsResponse response = service.reports().batchGet(getReport).execute();

// Return the response.
return response;
}
/**
* Queries the Analytics Reporting API V4.
* 주의 : Request의 MAX는 5개, 즉 통계정보를 받기 위한 요청은 최대5개
*      그래서 getReport1(5개), getReport2(2개) 만듦
*
* @param service An authorized Analytics Reporting API V4 service object.
* @return GetReportResponse The Analytics Reporting API V4 response.
* @throws IOException
*/
private GetReportsResponse getReport2(AnalyticsReporting service, String startDate, String endDate) throws IOException {
// Create the DateRange object.
DateRange dateRange = new DateRange();
dateRange.setStartDate(startDate);
dateRange.setEndDate(endDate);

// Create the Metrics object.
Metric metric1 = new Metric().setExpression(metric1Expression).setAlias(metric1Alias); // 페이지뷰
Metric metric2 = new Metric().setExpression(metric2Expression).setAlias(metric2Alias); // 사용자수
Metric metric3 = new Metric().setExpression(metric3Expression).setAlias(metric3Alias); // 세션수
Metric metrics[] = new Metric[3];
metrics[0] = metric1;
metrics[1] = metric2;
metrics[2] = metric3;
Dimension dimension6 = new Dimension().setName(dim6); // 모바일디바이스 브랜드별
Dimension dimension7 = new Dimension().setName(dim7); // 기기(Device)별

// Create the ReportRequest object.
ReportRequest request6 = new ReportRequest().setViewId(viewId).setDateRanges(Arrays.asList(dateRange))
.setMetrics(Arrays.asList(metrics)).setDimensions(Arrays.asList(dimension6));
ReportRequest request7 = new ReportRequest().setViewId(viewId).setDateRanges(Arrays.asList(dateRange))
.setMetrics(Arrays.asList(metrics)).setDimensions(Arrays.asList(dimension7));

ArrayList<ReportRequest> requests = new ArrayList<ReportRequest>();
requests.add(request6);
requests.add(request7);

// Create the GetReportsRequest object.
GetReportsRequest getReport = new GetReportsRequest().setReportRequests(requests);

// Call the batchGet method.
GetReportsResponse response = service.reports().batchGet(getReport).execute();

// Return the response.
return response;
}
// 기간별 삭제
private void delete(String startDate, String endDate) throws Exception {
GaStatsVO vo = new GaStatsVO();
vo.setStart_ymd(startDate.replace("-", ""));
vo.setEnd_ymd(endDate.replace("-", ""));
// DB에 Mybatis를 통해 값을 저장하기 위한 DAO
GaStatsDAO dao = new GaStatsDAO(); 
// 혹시 있담녀 그날분 삭제 
dao.deleteGaStats(vo);
}

/**
* Parses and prints the Analytics Reporting API V4 response.
*
* @param response An Analytics Reporting API V4 response.
* @throws Exception 
*/
private void saveResponse(GetReportsResponse response, String startDate, String endDate) throws Exception {

GaStatsVO vo = new GaStatsVO();
vo.setStart_ymd(startDate.replace("-", ""));
vo.setEnd_ymd(endDate.replace("-", ""));
// DB에 Mybatis를 통해 값을 저장하기 위한 DAO
GaStatsDAO dao = new GaStatsDAO(); 
for (Report report : response.getReports()) {
ColumnHeader header = report.getColumnHeader();
List<String> dimensionHeaders = header.getDimensions();
List<MetricHeaderEntry> metricHeaders = header.getMetricHeader().getMetricHeaderEntries();
List<ReportRow> rows = report.getData().getRows();

if (rows == null) {
logger.info("No data found for " + viewId);
return;
}

for (ReportRow row : rows) {
List<String> dimensions = row.getDimensions();
List<DateRangeValues> metrics = row.getMetrics();

for (int i = 0; i < dimensionHeaders.size() && i < dimensions.size(); i++) {
vo.setDimension(dimensionHeaders.get(i));
if (dimensions.get(i).contains("(상세보기)")) {
vo.setDim_val(dimensions.get(i).substring(0, dimensions.get(i).indexOf("(상세보기)")-1));
    }
else {
vo.setDim_val(dimensions.get(i));
}
if(dimensions.get(i).length() > 900) {
vo.setDim_val(dimensions.get(i).substring(0, 900));
}
}

for (int j = 0; j < metrics.size(); j++) {
DateRangeValues values = metrics.get(j);
for (int k = 0; k < values.getValues().size() && k < metricHeaders.size(); k++) {
if ("pageviews".equals(metricHeaders.get(k).getName())) {
vo.setPage_views(values.getValues().get(k));
}
else if ("users".equals(metricHeaders.get(k).getName())) {
vo.setUsers(values.getValues().get(k));
}
else if ("sessions".equals(metricHeaders.get(k).getName())) {
vo.setSessions(values.getValues().get(k));
}
}
}
try {
//VO에 있는 값을 저장
dao.insertGaStats(vo);
}
catch(Exception e) {
logger.error(">>>>> T_GA_STATS 저장 오류 ::: " + e);
e.printStackTrace();
throw new Exception("T_GA_STATS 저장 오류 ::: " + e);
}
}
}
}

/**
* 구글 통계정보를 가지고 오기 위한 설정파일 로딩
*/
    public void loadProperties() {
InputStream input = null;
try {
input = this.getClass().getClassLoader().getResourceAsStream("ga.properties");
Properties prop = new Properties();
// load a properties file
prop.load(input);
// get the property value
viewId = prop.getProperty("view.id");
keyFileLocation = prop.getProperty("key.file.location");
metric1Expression = prop.getProperty("metric1.expression");
metric1Alias = prop.getProperty("metric1.alias");
metric2Expression = prop.getProperty("metric2.expression");
metric2Alias = prop.getProperty("metric2.alias");
metric3Expression = prop.getProperty("metric3.expression");
metric3Alias = prop.getProperty("metric3.alias");
dim1 = prop.getProperty("dim1");
dim2 = prop.getProperty("dim2");
dim3 = prop.getProperty("dim3");
dim4 = prop.getProperty("dim4");
dim5 = prop.getProperty("dim5");
dim6 = prop.getProperty("dim6");
dim7 = prop.getProperty("dim7");
} catch (Exception ex) {
ex.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
input = null;
} catch (Exception e) {
}
}
}
}
}

 

Comments