ga4-data-api-usage
Some checks failed
Deploy to core / deploy (push) Failing after 2m16s

This commit is contained in:
Untone 2024-01-28 16:26:40 +03:00
parent bba87bbf1d
commit ebdfdb2613
2 changed files with 33 additions and 52 deletions

View File

@ -41,7 +41,7 @@ poetry run main.py
### viewed.py ### viewed.py
Задайте переменные окружения `GOOGLE_ANALYTICS_TOKEN` и `GOOGLE_GA_VIEW_ID` для сбора данных из [Google Analytics](https://developers.google.com/analytics?hl=ru). Задайте переменные окружения `GOOGLE_KEYFILE_PATH` и `GOOGLE_PROPERTY_ID` для получения данных из [Google Analytics](https://developers.google.com/analytics?hl=ru).
### search.py ### search.py

View File

@ -1,15 +1,14 @@
import asyncio import asyncio
import json import json
import logging import logging
import math
import os import os
import time import time
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from typing import Dict from typing import Dict
# ga # ga
from apiclient.discovery import build from google.analytics.data_v1beta import BetaAnalyticsDataClient
from google.oauth2.service_account import Credentials from google.analytics.data_v1beta.types import DateRange, Dimension, Metric, RunReportRequest
from orm.author import Author from orm.author import Author
from orm.shout import Shout, ShoutAuthor, ShoutTopic from orm.shout import Shout, ShoutAuthor, ShoutTopic
@ -23,19 +22,10 @@ logger = logging.getLogger('\t[services.viewed]\t')
logger.setLevel(logging.DEBUG) logger.setLevel(logging.DEBUG)
GOOGLE_KEYFILE_PATH = os.environ.get('GOOGLE_KEYFILE_PATH', '/dump/google-service.json') GOOGLE_KEYFILE_PATH = os.environ.get('GOOGLE_KEYFILE_PATH', '/dump/google-service.json')
# GOOGLE_ANALYTICS_API = 'https://analyticsreporting.googleapis.com/v4' GOOGLE_PROPERTY_ID = os.environ.get('GOOGLE_PROPERTY_ID', '')
GOOGLE_ANALYTICS_SCOPES = ['https://www.googleapis.com/auth/analytics.readonly']
VIEWS_FILEPATH = '/dump/views.json' VIEWS_FILEPATH = '/dump/views.json'
# Функция для создания объекта службы Analytics Reporting API V4
def get_service():
credentials = Credentials.from_service_account_file(GOOGLE_KEYFILE_PATH, scopes=GOOGLE_ANALYTICS_SCOPES)
service = build(serviceName='analyticsreporting', version='v4', credentials=credentials)
return service
class ViewedStorage: class ViewedStorage:
lock = asyncio.Lock() lock = asyncio.Lock()
views_by_shout = {} views_by_shout = {}
@ -43,7 +33,7 @@ class ViewedStorage:
shouts_by_author = {} shouts_by_author = {}
views = None views = None
period = 60 * 60 # каждый час period = 60 * 60 # каждый час
analytics_client = None analytics_client: BetaAnalyticsDataClient | None = None
auth_result = None auth_result = None
disabled = False disabled = False
updated = int(time.time()) updated = int(time.time())
@ -53,9 +43,13 @@ class ViewedStorage:
"""Подключение к клиенту Google Analytics с использованием аутентификации""" """Подключение к клиенту Google Analytics с использованием аутентификации"""
self = ViewedStorage self = ViewedStorage
async with self.lock: async with self.lock:
if os.path.exists(GOOGLE_KEYFILE_PATH): creds = open(GOOGLE_KEYFILE_PATH).read()
self.analytics_client = get_service() os.environ.setdefault('GOOGLE_APPLICATION_CREDENTIALS', creds)
logger.info(f' * Постоянная авторизация в Google Analytics {self.analytics_client}') if creds and GOOGLE_PROPERTY_ID:
# Using a default constructor instructs the client to use the credentials
# specified in GOOGLE_APPLICATION_CREDENTIALS environment variable.
self.analytics_client = BetaAnalyticsDataClient()
logger.info(f' * Постоянная авторизация в Google Analytics: {self.analytics_client}')
# Загрузка предварительно подсчитанных просмотров из файла JSON # Загрузка предварительно подсчитанных просмотров из файла JSON
self.load_precounted_views() self.load_precounted_views()
@ -74,7 +68,7 @@ class ViewedStorage:
"""Загрузка предварительно подсчитанных просмотров из файла JSON""" """Загрузка предварительно подсчитанных просмотров из файла JSON"""
self = ViewedStorage self = ViewedStorage
try: try:
with open('/dump/views.json', 'r') as file: with open(VIEWS_FILEPATH, 'r') as file:
precounted_views = json.load(file) precounted_views = json.load(file)
self.views_by_shout.update(precounted_views) self.views_by_shout.update(precounted_views)
logger.info(f' * {len(precounted_views)} публикаций с просмотрами успешно загружены.') logger.info(f' * {len(precounted_views)} публикаций с просмотрами успешно загружены.')
@ -91,35 +85,22 @@ class ViewedStorage:
start = time.time() start = time.time()
async with self.lock: async with self.lock:
if self.analytics_client: if self.analytics_client:
hours_ago = math.floor((int(time.time()) - self.updated) / 3600) or 1 request = RunReportRequest(
data = ( property=f'properties/{GOOGLE_PROPERTY_ID}',
self.analytics_client.data() dimensions=[Dimension(name='pagePath')],
.batchRunReports( metrics=[Metric(name='pageviews')],
{ date_ranges=[DateRange(start_date=self.start_date, end_date='today')],
'requests': [
{
'dateRanges': [{'startDate': f'{hours_ago}hoursAgo', 'endDate': 'today'}],
'metrics': [{'expression': 'ga:pageviews'}],
'dimensions': [{'name': 'ga:pagePath'}],
}
]
}
) )
.execute() response = self.analytics_client.run_report(request)
) if response and isinstance(response.rows, list):
if isinstance(data, dict):
slugs = set() slugs = set()
reports = data.get('reports', []) for row in response.rows:
if reports and isinstance(reports, list): print(row.dimension_values[0].value, row.metric_values[0].value)
rows = list(reports[0].get('data', {}).get('rows', []))
for row in rows:
# Извлечение путей страниц из ответа Google Analytics # Извлечение путей страниц из ответа Google Analytics
if isinstance(row, dict): if isinstance(row.dimension_values, list):
dimensions = row.get('dimensions', []) page_path = row.dimension_values[0].value
if isinstance(dimensions, list) and dimensions:
page_path = dimensions[0]
slug = page_path.split('discours.io/')[-1] slug = page_path.split('discours.io/')[-1]
views_count = int(row['metrics'][0]['values'][0]) views_count = int(row.metric_values[0].value)
# Обновление данных в хранилище # Обновление данных в хранилище
self.views_by_shout[slug] = self.views_by_shout.get(slug, 0) self.views_by_shout[slug] = self.views_by_shout.get(slug, 0)