Рабочий чекер попал ли ваш сайт под фильтр Гугл — бесплатно

от автора

Понадобилось мне проанализировать сайт на предмет попадания его под фильтр Гугла, причем с историческими данными.

Первым делом начал гуглить — чекер фильтров Гугла и вот это вот все. Естественно — в интернетах куча решений, но есть небольшое но… Они либо платные, либо условно‑бесплатные, либо вообще непонятно как работают.

Ну что делать — надо реализовать собственное решение, что я и сделал.

Палю годноту, так как использование этого решения никак не повлияет на мою деятельность, а кому то может и полезно будет.

Суть решения достаточно проста есть код (он будет ниже), написанный на Python. Он реализует интерактивный дашборд для визуализации данных, полученных из Google Search Console, с использованием библиотеки Dash (на базе Plotly) для построения графиков.

Фактически скрипт подключается по АПИ к Гугл Серч Консоль, забирает оттуда данные по показам, кликам и позициям, после чего выводит их на графике. В самом скрипте добавлены все апы Гугла за последние 2 года (информацию брал тут), ну и можно вручную добавить значимые события, которые вы внедряли на сайте (ниже покажу где это меняется в коде).

Немного теории — что это за скрипт и как он настраивается и работает

  1. Настройка параметров и констант в коде
    В разделе с параметрами задаются:

    • Список сайтов – определяются доменные или URL‑свойства, для которых будут запрашиваться данные.

    • Дата начала и окончания – задается временной интервал, за который нужно получать данные.

    • Списки обновлений (updates) и событий (events) – массивы с информацией о значимых изменениях (обновлениях алгоритмов и событиях на сайте). Для каждого обновления указаны его название, дата начала и окончания, а для событий – дата и название.

  2. Запрос данных из Google Search Console
    Функция fetch_gsc_data формирует запрос к API Google Search Console, используя сервисный аккаунт (авторизационные данные считываются из JSON‑файла — который вам также понадобится для работы скрипта). В запросе задается диапазон дат и необходимые измерения (в данном случае – «date»). Ответ API преобразуется в DataFrame, где хранится дата и основные метрики (клики, показы, позиция).

  3. Агрегация данных по сайтам
    Функция load_all_data итеративно вызывает fetch_gsc_data для каждого сайта из заданного списка и объединяет полученные данные в один общий DataFrame. Каждая выборка дополняется информацией о соответствующем сайте.

  4. Создание интерактивного дашборда с Dash

    • Интерфейс пользователя:
      В Layout приложения создаются элементы управления:

      • Чекбоксы для выбора сайтов, метрик, обновлений и событий.

      • Графический компонент, в котором отображаются данные.

    • Обновление графика:
      Callback-функция отслеживает изменения состояния элементов управления (выбор сайтов, метрик, обновлений и событий, а также изменения зума на графике). При каждом изменении происходит следующее:

      • Данные фильтруются по выбранным сайтам.

      • Если выбраны метрики, по каждому сайту строятся линии (с использованием Plotly Scatter), где каждая линия отражает динамику конкретной метрики.

      • Дополнительно, в графике добавляются:

        • Прямоугольники (vrect) – для обозначения периодов обновлений (например, обновлений поискового алгоритма), с отображением названия обновления.

        • Вертикальные линии (vline) и аннотации – для отображения событий, таких как изменения или важные действия на сайте.

      • Применяется диапазонный слайдер (range slider) для оси X, позволяющий пользователю интерактивно изменять временной интервал.

      • При изменении зума по оси X происходит динамический пересчет диапазона оси Y для более точного отображения изменений в данных.

      • Свойство uirevision='fixed' используется для того, чтобы сохранить настройки зума и панорамирования между обновлениями графика.

От теории к практике — как работать со скриптом

Итак, для начала вам потребуется:

1. Создать проект в Google Cloud Console

Переходим на https://console.cloud.google.com/

  • Создаем новый проект

  • Переходим в APIs & Services → Library

  • Находим и включаем API:

    • ✅ Google Search Console API

2. Создать Service Account (сервисный аккаунт)

  • Переходим в IAM & Admin → Service Accounts

  • Нажимаем Create Service Account и создаем его

  • Далее создаем и скачаем JSON-файл с ключом (credentials.json)

  • Сохраняем этот файл – он понадобится в корне проекта

В файле будет вот такие данные

{   "type": "service_account",   "project_id": "Имя вашего проекта",   "private_key_id": "Ваш Private Key ID",   "private_key": "Ваш Private Key",   "client_email": "project@project.iam.gserviceaccount.com",   "client_id": "Ваш номер клиента",   "auth_uri": "https://accounts.google.com/o/oauth2/auth",   "token_uri": "https://oauth2.googleapis.com/token",   "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",   "client_x509_cert_url": "Ваши данные",   "universe_domain": "googleapis.com" } 

Сразу оговорюсь — в вашем JSON-файле будут ваши данные, не такие как в примере.

Почту из строки client_email необходимо будет добавить в качестве админа в вашей Серч Консоли (для нужного сайта).

Далее в той же папке, где у вас лежит JSON-файл создаем файл с расширением .py, я делаю всегда так — main.py

В файле вот такой код

import os import json import pandas as pd import plotly.graph_objs as go import dash from dash import dcc, html from datetime import datetime from dash.dependencies import Input, Output  from google.oauth2 import service_account from googleapiclient.discovery import build  # Ваши константы SITES = [     "sc-domain:Ваш домен",     "sc-domain:Ваш домен", ]  # Даты, за которые берем данные START_DATE = "2024-01-01" END_DATE   = "2025-04-12"  # ============================================================ # Обновленный список Google Updates с дополнительными данными # ============================================================ GOOGLE_UPDATES = [     {"name": "March 2025 core update", "start": "2025-03-13", "end": "2025-03-26"},     {"name": "December 2024 spam update", "start": "2024-12-19", "end": "2024-12-26"},     {"name": "December 2024 core update", "start": "2024-12-12", "end": "2024-12-18"},     {"name": "November 2024 core update", "start": "2024-11-11", "end": "2024-12-04"},     {"name": "Ranking is experiencing an ongoing issue (Aug 2024)", "start": "2024-08-15", "end": "2024-08-19"},     {"name": "August 2024 core update", "start": "2024-08-15", "end": "2024-09-03"},     {"name": "June 2024 spam update", "start": "2024-06-20", "end": "2024-06-27"},     {"name": "March 2024 spam update", "start": "2024-03-05", "end": "2024-03-19"},     {"name": "March 2024 core update", "start": "2024-03-05", "end": "2024-04-19"},     {"name": "November 2023 reviews update", "start": "2023-11-08", "end": "2023-12-07"},     {"name": "November 2023 core update", "start": "2023-11-02", "end": "2023-11-27"},     {"name": "October 2023 core update", "start": "2023-10-05", "end": "2023-10-18"},     {"name": "Ranking is experiencing an ongoing issue (Oct 2023)", "start": "2023-10-05", "end": "2023-10-31"},     {"name": "October 2023 spam update", "start": "2023-10-04", "end": "2023-10-19"},     {"name": "September 2023 helpful content update", "start": "2023-09-14", "end": "2023-09-27"},     {"name": "August 2023 core update", "start": "2023-08-22", "end": "2023-09-07"},     {"name": "April 2023 reviews update", "start": "2023-04-12", "end": "2023-04-25"},     {"name": "March 2023 core update", "start": "2023-03-15", "end": "2023-03-28"},     {"name": "February 2023 product reviews update", "start": "2023-02-21", "end": "2023-03-07"}, ]  # События на сайте EVENTS = [     {"name": "Ваше событие",           "date": "2024-02-12"},     {"name": "Ваше событие",         "date": "2024-02-16"},     {"name": "Ваше событие",      "date": "2024-02-27"},     {"name": "Ваше событие",          "date": "2024-03-20"},     {"name": "Ваше событие",          "date": "2024-03-21"}, ]  def fetch_gsc_data(property_uri, start_date, end_date, creds):     service = build('searchconsole', 'v1', credentials=creds)     body = {         'startDate': start_date,         'endDate': end_date,         'dimensions': ['date'],         'rowLimit': 10000     }     response = service.searchanalytics().query(siteUrl=property_uri, body=body).execute()     rows = response.get('rows', [])     data = []     for r in rows:         d = r['keys'][0]         data.append({             'date': d,             'clicks': r.get('clicks', 0),             'impressions': r.get('impressions', 0),             'position': r.get('position', 0)         })     df = pd.DataFrame(data)     df['date'] = pd.to_datetime(df['date'])     return df  def load_all_data(     start_date=START_DATE,      end_date=END_DATE,      sites=SITES,      creds_file="Название вашего JSON-файла" ):     creds = service_account.Credentials.from_service_account_file(         creds_file,         scopes=["https://www.googleapis.com/auth/webmasters.readonly"]     )     all_df = []     for s in sites:         df_s = fetch_gsc_data(s, start_date, end_date, creds)         df_s['domain'] = s         all_df.append(df_s)     big_df = pd.concat(all_df, ignore_index=True)     return big_df  app = dash.Dash(__name__) GLOBAL_DF = None  # кешируем загруженные данные  app.layout = html.Div([     html.H1("GSC Дашборд - Клики, Показы, Позиция"),      html.Div([         html.Label("Выберите сайт(-ы):"),         dcc.Checklist(             id='site-selector',             options=[{'label': site, 'value': site} for site in SITES],             value=SITES,               inline=True         ),     ]),      html.Div([         html.Label("Метрики:"),         dcc.Checklist(             id='metric-selector',             options=[                 {'label': 'Клики', 'value': 'clicks'},                 {'label': 'Показы', 'value': 'impressions'},                 {'label': 'Позиция', 'value': 'position'},             ],             # Если тут пусто, у нас нет рядов данных => ось X может стать [0..1]             value=[],               inline=True         ),     ]),      html.Div([         html.Label("Показать Google Updates:"),         dcc.Checklist(             id='updates-toggle',             options=[{'label': u['name'], 'value': u['name']} for u in GOOGLE_UPDATES],             value=[],               inline=True         ),     ]),      html.Div([         html.Label("Показать события:"),         dcc.Checklist(             id='events-toggle',             options=[{'label': e['name'], 'value': e['name']} for e in EVENTS],             value=[],               inline=True         ),     ]),      dcc.Graph(id='gsc-graph') ])  @app.callback(     Output('gsc-graph', 'figure'),     [         Input('site-selector', 'value'),         Input('metric-selector', 'value'),         Input('updates-toggle', 'value'),         Input('events-toggle', 'value'),         Input('gsc-graph', 'relayoutData')     ] ) def update_graph(selected_sites, selected_metrics, selected_updates, selected_events, relayoutData):     global GLOBAL_DF     if GLOBAL_DF is None:         GLOBAL_DF = load_all_data()      print("=== CALLBACK ===")     print("Selected events: ", selected_events)  # Проверяем в консоли, что выбрано      fig = go.Figure()      # Фильтруем общий DF по выбранным доменам     filtered_df = GLOBAL_DF[GLOBAL_DF['domain'].isin(selected_sites)]      # Если выбраны метрики, строим линии     if selected_metrics:         for site in selected_sites:             df_site = filtered_df[filtered_df['domain'] == site].sort_values('date')             for metric in selected_metrics:                 fig.add_trace(go.Scatter(                     x=df_site['date'],                     y=df_site[metric],                     mode='lines',                     name=f"{site} - {metric}"                 ))      # Добавляем прямоугольники (vrect) для Google Updates     for upd in GOOGLE_UPDATES:         if upd['name'] in selected_updates:             fig.add_vrect(                 x0=upd['start'], x1=upd['end'],                 fillcolor='red', opacity=0.1, layer='below', line_width=0,                 annotation_text=upd['name'],                 annotation_position="top left"             )      # Добавляем события (вертикальные линии) для выбранных ev     for ev in EVENTS:         if ev['name'] in selected_events:             date_str = pd.to_datetime(ev['date']).strftime('%Y-%m-%d')             print(f"Adding event line: {ev['name']} at {date_str}")  # Диагностика             fig.add_vline(                 x=date_str,                 line_color='blue',                 opacity=1.0,                 line_width=2,                 layer='above'             )             fig.add_annotation(                 x=date_str,                 y=1,                 xref='x',                 yref='paper',                 text=ev['name'],                 showarrow=True,                 arrowhead=2,                 ax=0,                 ay=-40,                 font=dict(color='blue', size=12)             )      # Настройка осей     fig.update_layout(         title="GSC Трафик",         xaxis_title="Дата",         yaxis_title="Значение",         legend_title="Сайты и метрики",         xaxis=dict(             tickmode='linear',             tick0=pd.to_datetime(START_DATE),             dtick=86400000.0,  # один день (в мс)             tickformat="%d-%m-%Y",             rangeslider=dict(visible=True),         )     )      # Если метрик нет => вручную задаём X-ось (иначе range может оказаться [0..1])     if not selected_metrics:         print("No metrics selected -> Forcing x-range to START..END")         fig.update_xaxes(range=[START_DATE, END_DATE])      # Обработка зума (для Y-оси)     if relayoutData:         if "xaxis.range[0]" in relayoutData and "xaxis.range[1]" in relayoutData and selected_metrics:             x_start = pd.to_datetime(relayoutData["xaxis.range[0]"])             x_end = pd.to_datetime(relayoutData["xaxis.range[1]"])             mask = (filtered_df['date'] >= x_start) & (filtered_df['date'] <= x_end)             zoomed_df = filtered_df[mask]             if not zoomed_df.empty:                 y_min = zoomed_df[selected_metrics].min().min()                 y_max = zoomed_df[selected_metrics].max().max()                 y_padding = (y_max - y_min) * 0.05                 fig.update_yaxes(range=[y_min - y_padding, y_max + y_padding])      # Чтобы при переключении чекбоксов не сбрасывался зум или аннотации     fig.update_layout(uirevision='fixed')      return fig  if __name__ == '__main__':     app.run(debug=True) 

В данном коде необходимо изменить следующее:

Строка 14 — вписать ваши домены, которые нужно вывести на графике

Строка 19 — указываем период, за который нужны данные (если проектов много, рекомендую не брать слишком большой период — будет долго подгружать)

Строка — 25-46 — тут я вписал апы Гугла — вы можете добавить если что то не указано

Строка 48 — тут вписываете события, которые хотите видеть на графике (они будут показаны вертикальной линией, как на скрине выше)

Строка 84 — название вашего JSON — файла (который расположен в той же папке, что и сам скрипт)

Все — вы почти готовы начинать…

Пока писал статью, показалось что уж проще было заплатить какому-нибудь сервису

Запуск и работа с дашбордом

Перед тем как запускать скрипт — устанавливаем необходимые зависимости, для чего в терминале (я через VS Code ставлю) вводим эту команду:

pip install dash plotly pandas google-auth google-auth-oauthlib google-auth-httplib2 google-api-python-client

Ждем когда все установится и запускаем скрипт простой командой

python main.py

Когда скрипт запустится вы увидите в терминале, что дашборд доступен по локальному адресу, в моем случае это — http://127.0.0.1:8050

Думаю у вас будет так же.

По умолчанию чтобы увидеть график нужно будет установить чекбокс на показы, клики или позиции и выбрать какой ап гугла показать, далее можно масштабировать график, там в принципе все интуитивно понятно.

Самое главное, что несколько минут настройки и у вас свой мини-сервис по анализу — попали ли вы под очередной ап Гугла или нет.

Кстати, когда будет новый update нужно будет добавить его руками в коде, если хотите сравнить повлиял ли он на вас.

Можно конечно все это делать и по-другому, но я вот сдела такой мини дашбоард и работаю с ним. Пользуйтесь, если надо.


ссылка на оригинал статьи https://habr.com/ru/articles/900482/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *