# google_positions.py — позиции сайта в Google: три источника

Скрипт проверяет, на каком месте ваш сайт стоит в Google по списку запросов, и ведёт историю в CSV. Лицензия MIT.

Статья с разбором: https://sk-seo.ru/blog/proverka-pozitsiy-google-python.html

| Источник | Что даёт | Что понадобится |
|---|---|---|
| `xmlriver` (по умолчанию) | снимок выдачи в любом городе для любого сайта; 25 ₽ за 1000 запросов на базовом тарифе | аккаунт XMLRiver |
| `gsc` | средняя позиция, показы и клики **вашего** сайта за период; бесплатно | доступ к сайту в Search Console и проект в Google Cloud |
| `browser` | снимок выдачи через настоящий браузер; бесплатно, для небольших объёмов | браузер CloakBrowser |

Достаточно настроить один источник. Остальные можно не трогать.

---

## Шаг 1. Python и файлы

1. Установите Python 3.9 или новее с [python.org](https://www.python.org/downloads/). Проверка: `python --version`.
2. Распакуйте архив `google-positions.zip` — в папке окажутся `google_positions.py`, `keywords.txt`, `env.example` и этот README. Если качали файлы по одному, положите их в одну папку.
3. Скопируйте `env.example` в файл с именем `.env` (с точкой в начале) в той же папке. Все ваши ключи и пути вписываются только туда; в сам скрипт ничего вписывать не нужно.
4. Откройте `keywords.txt` и замените примеры на свои запросы — по одному на строку.

## Шаг 2а. XMLRiver

1. Зарегистрируйтесь на [xmlriver.com](https://xmlriver.com/) и пополните баланс. Прогон 100 запросов на глубину ТОП-10 — это 100 обращений, около 2,5 ₽ по базовому тарифу.
2. В личном кабинете, в разделе «Настройки сбора», возьмите ID пользователя (`user`) и ключ (`key`). Подробнее — [документация по подключению](https://xmlriver.com/api/api-connect/).
3. Впишите их в `.env`:
   ```
   XMLRIVER_USER=12345
   XMLRIVER_KEY=ваш_ключ
   ```
4. Найдите код своего города в справочнике [geo.csv](https://xmlriver.com/files/geo.csv): первая колонка — ID для скрипта. Москва — `1011969`. Код домена Google — в [domains.xlsx](https://xmlriver.com/files/domains.xlsx) (google.ru — `143`), язык — в [langs.xlsx](https://xmlriver.com/files/langs.xlsx).
5. Сначала посчитайте, сколько обращений уйдёт, потом запускайте:
   ```bash
   python google_positions.py -k keywords.txt -s example.ru --pages 3 --dry-run
   python google_positions.py -k keywords.txt -s example.ru --loc 1011969 --lang ru --gdomain 143 --pages 3
   ```

## Шаг 2б. Google Search Console

Работает только для сайтов, к которым у вас есть доступ в Search Console.

1. Установите библиотеки: `pip install google-auth requests`.
2. Откройте [Google Cloud Console](https://console.cloud.google.com/) и создайте проект (или выберите существующий).
3. В разделе «APIs & Services» → «Library» найдите **Google Search Console API** и нажмите «Enable».
4. В разделе «IAM & Admin» → «Service Accounts» создайте сервисный аккаунт. Роли в проекте ему не нужны.
5. Откройте созданный аккаунт → вкладка «Keys» → «Add key» → «Create new key» → формат JSON. Сохраните файл рядом со скриптом, например как `gsc-key.json`. Это секрет: не выкладывайте его в открытый доступ и не коммитьте в git.
6. Скопируйте e-mail сервисного аккаунта (вида `имя@проект.iam.gserviceaccount.com`).
7. В [Search Console](https://search.google.com/search-console) откройте свой ресурс → «Настройки» → «Пользователи и разрешения» → «Добавить пользователя», вставьте этот e-mail, уровень доступа — «Ограниченный доступ».
8. Впишите в `.env` ресурс точно так, как он записан в Search Console, и путь к ключу:
   ```
   GSC_PROPERTY=sc-domain:example.ru
   GSC_CREDENTIALS=gsc-key.json
   ```
   Для ресурса с префиксом адреса: `GSC_PROPERTY=https://example.ru/` — со слешем в конце.
9. Запуск (`--gsc-country` — код страны ISO-3 строчными, `--gsc-days` — длина периода):
   ```bash
   python google_positions.py -k keywords.txt -s example.ru --source gsc --gsc-country rus --gsc-days 28
   ```

Если у вас уже есть OAuth-токен пользователя в формате `authorized_user` (JSON с полем `refresh_token`), его можно указать в `GSC_CREDENTIALS` вместо ключа сервисного аккаунта.

Запрос, по которому сайт за период не показывался, выводится прочерком: Search Console о нём не знает.

## Шаг 2в. Браузер

1. Установите CloakBrowser — Chromium с изменённым отпечатком, Python-обёртка под MIT:
   ```bash
   pip install cloakbrowser
   cloakbrowser install        # скачает браузер, около 200 МБ
   ```
2. Возьмите каноническое имя города из того же [geo.csv](https://xmlriver.com/files/geo.csv) — третья колонка, например `Moscow,Moscow,Russia`.
3. Запуск:
   ```bash
   python google_positions.py -k keywords.txt -s example.ru --source browser --city "Moscow,Moscow,Russia" --lang ru --gl ru --pages 2
   ```
4. Если Google показал капчу, скрипт остановится и пометит оставшиеся запросы `skipped_after_captcha`. Запустите с `--headed`, решите капчу в открывшемся окне и повторите: cookies сохраняются в папке `--profile`.

Держите паузы (`--delay`, по умолчанию 8 секунд) и не гоняйте сотни запросов подряд. robots.txt Google закрывает раздел `/search` для роботов; для регулярного и объёмного мониторинга берите XMLRiver или Search Console.

---

## Первый прогон

Добавьте в `keywords.txt` один брендовый запрос, по которому ваш сайт точно первый, и прогоните его. Если сайт не найден — ошибка в домене (`-s`) или регионе, а не в позициях. Ровный «сайта нет в выдаче» по всем запросам чаще означает неверную настройку, чем реальную картину.

## Регулярные прогоны

Результаты дописываются в `positions_history.csv`, колонка `delta` показывает изменение против прошлого прогона того же источника, региона и устройства.

- Windows: «Планировщик заданий» → создать задачу → действие «Запуск программы»: `python`, аргументы `google_positions.py -k keywords.txt -s example.ru --loc 1011969 --pages 3`, рабочая папка — папка скрипта.
- Linux/macOS, раз в день в 7:00 (`crontab -e`):
  ```
  0 7 * * * cd /путь/к/папке && python3 google_positions.py -k keywords.txt -s example.ru --loc 1011969 --pages 3
  ```

## Все параметры

| Флаг | Что задаёт | По умолчанию |
|---|---|---|
| `-k`, `--keywords` | файл запросов | обязателен |
| `-s`, `--site` | домен сайта | обязателен |
| `--source` | `xmlriver`, `gsc`, `browser` | `xmlriver` |
| `--device` | `desktop`, `tablet`, `mobile` | desktop для выдачи, все устройства для gsc |
| `--pages` | глубина в страницах по 10 результатов (ТОП-30 — `3`) | `1` |
| `--all-pages` | листать все страницы, даже если сайт уже найден | выкл. |
| `--no-subdomains` | не засчитывать поддомены сайта | выкл. |
| `-o`, `--out` | CSV-история | `positions_history.csv` |
| `--env` | другой файл настроек вместо `.env` | `.env` |
| `--dry-run` | только посчитать обращения (и стоимость для xmlriver) | выкл. |
| `--loc`, `--country`, `--lang`, `--gdomain` | регион, страна, язык и домен Google для xmlriver | не заданы |
| `--price` | цена за 1000 запросов для расчёта, ₽ | `25` |
| `--gsc-property`, `--gsc-credentials` | то же, что в `.env`; флаг важнее | из `.env` |
| `--gsc-days`, `--gsc-country` | период и страна для gsc | `28`, все страны |
| `--city`, `--gl`, `--google-host` | город, страна интерфейса и домен Google для browser | —, —, `google.ru` |
| `--delay`, `--profile`, `--headed` | пауза, папка профиля, видимое окно для browser | `8`, `google_profile`, выкл. |

## Колонки CSV

`checked_at`, `source`, `keyword`, `position` (пусто — сайта нет в пределах глубины или в Search Console), `delta` (`+3`, `-2`, `0`, `new`, `entered`, `dropped`), `url`, `page`, `other_site_urls` (другие страницы сайта на тех же страницах выдачи; в режиме browser — хосты), `top3_domains`, `impressions` и `clicks` (только gsc), `device`, `loc`, `status`.

Разделитель — точка с запятой, кодировка UTF-8 с BOM: файл открывается в Excel без настройки.

## Если что-то не так

| Сообщение | Что делать |
|---|---|
| `Нет XMLRIVER_USER / XMLRIVER_KEY` | файл `.env` не найден или пуст; он должен лежать в текущей папке или рядом со скриптом |
| `api_error …` в колонке `status` | ошибка на стороне XMLRiver: чаще всего неверный ключ или закончился баланс; текст ошибки — в той же колонке |
| `Search Console: HTTP 403` | e-mail сервисного аккаунта не добавлен в пользователи ресурса или `GSC_PROPERTY` записан не так, как в Search Console |
| `Для --source gsc: pip install google-auth requests` | не установлены библиотеки |
| `captcha` в `status` | Google заподозрил автоматизацию: увеличьте `--delay`, повторите позже или запустите с `--headed` |
| все запросы «>30» | сначала проверьте брендовый запрос — см. «Первый прогон» |
