Настройка автоматической проверки индексации новых страниц
Новая страница опубликована — это не значит, что Google её нашёл. Бот может обойти её через 3 часа, а может через 3 недели: зависит от crawl budget сайта, структуры sitemap, частоты обновлений. Ручная проверка через «site:» или GSC вручную не масштабируется: при публикации 50+ страниц в месяц нужна автоматизация.
Задача системы: при появлении новой страницы — отправить её на индексацию, дождаться подтверждения, зафиксировать в логе, уведомить при проблемах.
Уровень 1: Sitemap + Ping
Минимальный вариант — автоматическое обновление sitemap.xml и пинг поисковиков при добавлении новой страницы.
Ping-endpoint Google:
https://www.google.com/ping?sitemap=https://example.com/sitemap.xml
Вызывается GET-запросом. Можно встроить в деплой или хук публикации CMS:
import requests
def notify_google_sitemap(sitemap_url: str) -> bool:
ping_url = f"https://www.google.com/ping?sitemap={sitemap_url}"
resp = requests.get(ping_url, timeout=10)
return resp.status_code == 200
Для WordPress — плагины Yoast/RankMath делают это автоматически. На кастомных CMS — хук в событие post_published.
Sitemap с lastmod:
<url>
<loc>https://example.com/new-page/</loc>
<lastmod>2024-11-15T10:30:00+03:00</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
lastmod должен обновляться при каждом изменении страницы — иначе Google игнорирует его как статичный.
Уровень 2: Google Indexing API
Официальный способ форсировать проверку индексации. Изначально только для страниц с разметкой JobPosting/BroadcastEvent, но на практике работает для любых URL и значительно ускоряет индексацию.
Настройка сервисного аккаунта:
- Google Cloud Console → IAM → Service Accounts → Create
- Создать ключ JSON
- В Google Search Console добавить сервисный аккаунт как Owner (не Viewer — иначе API вернёт 403)
Код уведомления:
from google.oauth2 import service_account
from googleapiclient.discovery import build
SCOPES = ['https://www.googleapis.com/auth/indexing']
KEY_FILE = 'service-account-key.json'
credentials = service_account.Credentials.from_service_account_file(
KEY_FILE, scopes=SCOPES
)
service = build('indexing', 'v3', credentials=credentials)
def request_indexing(url: str, update_type: str = 'URL_UPDATED') -> dict:
"""update_type: URL_UPDATED | URL_DELETED"""
response = service.urlNotifications().publish(
body={
'url': url,
'type': update_type
}
).execute()
return response
# Результат содержит urlNotificationMetadata
# {'url': 'https://...', 'latestUpdate': {...}, 'latestRemove': {...}}
Batch-запросы (до 100 URL за раз):
def batch_request_indexing(urls: list[str]) -> list:
batch = service.new_batch_http_request()
results = []
def callback(request_id, response, exception):
if exception:
results.append({'url': request_id, 'error': str(exception)})
else:
results.append(response)
for url in urls[:100]: # Лимит API
batch.add(
service.urlNotifications().publish(
body={'url': url, 'type': 'URL_UPDATED'}
),
request_id=url,
callback=callback
)
batch.execute()
return results
Квота: 200 запросов/день для обычных сайтов. При необходимости — запрос на расширение квоты в Google Search Console.
Уровень 3: Проверка статуса индексации
Отправить запрос — это половина задачи. Нужно знать, проиндексирована ли страница.
GSC URL Inspection API:
def check_indexing_status(site_url: str, page_url: str) -> dict:
"""
site_url: 'https://example.com' — как зарегистрирован в GSC
page_url: полный URL страницы
"""
service = build('searchconsole', 'v1', credentials=credentials)
result = service.urlInspection().index().inspect(
body={
'inspectionUrl': page_url,
'siteUrl': site_url
}
).execute()
inspection = result.get('inspectionResult', {})
index_status = inspection.get('indexStatusResult', {})
return {
'verdict': index_status.get('verdict'), # PASS | FAIL | NEUTRAL
'coverage_state': index_status.get('coverageState'), # Submitted and indexed, Crawled - currently not indexed, etc.
'last_crawl_time': index_status.get('lastCrawlTime'),
'robots_txt_state': index_status.get('robotsTxtState'),
'indexing_state': index_status.get('indexingState'),
}
Возможные значения coverageState:
-
Submitted and indexed— страница в индексе -
Crawled - currently not indexed— бот обходил, но не добавил -
Discovered - currently not indexed— найдена, но не обработана -
Excluded by 'noindex' tag— проблема на стороне сайта
Автоматизация: полный цикл
Схема процесса:
Публикация страницы
↓
Webhook/cron триггер
↓
Добавление URL в очередь (Redis / БД)
↓
Worker: Indexing API → publish URL_UPDATED
↓
Cron через 48h: GSC Inspection API → check status
↓
Если не проиндексирована → повторная отправка + алерт
↓
Лог результатов
Пример таблицы мониторинга (PostgreSQL):
CREATE TABLE indexing_queue (
id SERIAL PRIMARY KEY,
url TEXT NOT NULL UNIQUE,
submitted_at TIMESTAMPTZ,
last_checked_at TIMESTAMPTZ,
status VARCHAR(64), -- pending | submitted | indexed | failed | excluded
coverage_state TEXT,
attempts INT DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Страницы требующие повторной проверки
SELECT url, status, attempts, last_checked_at
FROM indexing_queue
WHERE status NOT IN ('indexed', 'excluded')
AND attempts < 5
AND (last_checked_at IS NULL OR last_checked_at < NOW() - INTERVAL '48 hours')
ORDER BY created_at DESC;
Уведомления в Telegram при проблемах:
import httpx
async def send_telegram_alert(message: str, bot_token: str, chat_id: str):
url = f"https://api.telegram.org/bot{bot_token}/sendMessage"
await httpx.AsyncClient().post(url, json={
'chat_id': chat_id,
'text': message,
'parse_mode': 'HTML'
})
# Использование
pages_not_indexed = get_pages_not_indexed_after_7_days()
if pages_not_indexed:
msg = f"⚠️ {len(pages_not_indexed)} страниц не проиндексированы за 7 дней:\n"
msg += "\n".join(p.url for p in pages_not_indexed[:10])
await send_telegram_alert(msg, BOT_TOKEN, CHAT_ID)
Интеграция с CMS
На WordPress — custom plugin с хуком publish_post:
add_action('publish_post', function(int $post_id) {
$url = get_permalink($post_id);
// Вызов indexing API через wp_remote_post или очередь
wp_schedule_single_event(time() + 60, 'submit_url_to_indexing_api', [$url]);
});
На Laravel — через Events/Listeners:
// После создания модели Page
class PageCreated
{
public function __construct(public readonly Page $page) {}
}
class SubmitPageToGoogleIndexing implements ShouldQueue
{
public function handle(PageCreated $event): void
{
$url = route('page.show', $event->page->slug);
GoogleIndexingService::submit($url);
}
}
Сроки
Базовая настройка (sitemap ping + Indexing API при публикации) — 1–2 рабочих дня. Полноценная система с мониторингом статуса, очередью повторных проверок и алертами — 3–5 дней.







