This commit is contained in:
parent
bba87bbf1d
commit
ebdfdb2613
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user