Как стать автором
Обновить

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

Уровень сложностиПростой
Время на прочтение9 мин
Количество просмотров1.6K

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

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

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

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

Суть решения достаточно проста есть код (он будет ниже), написанный на 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 нужно будет добавить его руками в коде, если хотите сравнить повлиял ли он на вас.

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

Теги:
Хабы:
Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку
+5
Комментарии3

Публикации

Работа

Data Scientist
46 вакансий

Ближайшие события