Files
supermarket/cursor_forbidden_api.md

13 KiB
Raw Blame History

Ошибка Forbidden в API Магнит

Exported on 12/14/2025 at 03:06:00 GMT+5 from Cursor (2.2.20)


User

@.cursor/plans/supermarket_scraper_system_1af4ed29.plan.md

Вопрос сейчас только про api магнит

https://magnit.ru/webgate/v2/goods/1000257489/stores/992301?storetype=6&catalogtype=1 ответ Forbidden Transaction ID: 2b7f613f-b7fe-4f95-9dd4-b30c1f5cb4a5

Хотя в браузере работает у них на сайте https://magnit.ru/product/1000257489-chay_chernyy_greenfield_english_edition_100pak?shopCode=992301&shopType=6

вот заголовки в браузере URL запроса: https://magnit.ru/webgate/v2/goods/1000257489/stores/992301?storetype=6&catalogtype=1 Метод запроса: GET Код статуса: 200 OK Удаленный адрес: 178.248.238.72:443 Правило для URL перехода: origin content-encoding: gzip content-type: application/json date: Sat, 13 Dec 2025 21:41:24 GMT document-policy: js-profiling referrer-policy: origin server: QRATOR strict-transport-security: max-age=31536000; includeSubDomains vary: Accept-Encoding,Accept-Encoding x-content-type-options: nosniff x-frame-options: SAMEORIGIN x-trace-id: 544850473b9c35d2d1c00538cc1d16c6 x-xss-protection: 1 :authority: magnit.ru :method: GET :path: /webgate/v2/goods/1000257489/stores/992301?storetype=6&catalogtype=1 :scheme: https accept: / accept-encoding: gzip, deflate, br, zstd accept-language: ru,en-US;q=0.9,en;q=0.8 baggage: sentry-environment=production,sentry-public_key=7992e659d14bf5d8da08d2e6a0706d0a,sentry-trace_id=596895b1cc7b4c05935d288b1cc91e8a,sentry-sampled=false,sentry-sample_rand=0.6716192411675364,sentry-sample_rate=0.05 content-type: application/json cookie: nmg_dt=; shopCode=992301; x_shop_type=ME; mg_udi=9D4909B8-9F79-5B1D-8457-EA519EC9AA3F; oxxfgh=ef3934b0-03b7-44fc-b6d8-9b0dd7412ea3%230%237884000000%235000%231800000%2312840; uwyii=b172df84-99bb-4b86-51b5-909db1474363; nmg_sp=Y; mg_uac=1; mg_adlt=Y; uwyiert=65182acc-a917-c963-d7fe-a14c0cab4e8d dnt: 1 priority: u=1, i referer: https://magnit.ru/ sec-ch-ua: "Not?A_Brand";v="99", "Chromium";v="130" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "Windows" sec-fetch-dest: empty sec-fetch-mode: cors sec-fetch-site: same-origin sec-gpc: 1 sentry-trace: 596895b1cc7b4c05935d288b1cc91e8a-b581de5bc3a814d5-0 user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 x-app-version: 2025.12.12-16.56 x-client-name: magnit x-device-id: 9D4909B8-9F79-5B1D-8457-EA519EC9AA3F x-device-platform: Web x-device-tag: disabled x-new-magnit: true x-platform-version: Windows Chrome 130


Cursor

API Магнита возвращает 403, потому что требуется авторизация и корректные заголовки. Анализирую требования и способы их соблюдения:

API Магнита возвращает 403, потому что требуется авторизация и корректные заголовки. По заголовкам из браузера видно, что нужны:

Проблема

API проверяет:

  1. Cookies (сессия)
  2. Заголовки, имитирующие браузер
  3. Referer и origin

Решение

Вариант 1: Использовать Playwright для получения cookies и заголовков

Сначала зайти на сайт через Playwright, получить cookies, затем использовать их в HTTP-запросах:

// src/scrapers/api/magnit/MagnitApiScraper.ts
import { chromium, Browser, Page } from 'playwright';
import axios, { AxiosInstance } from 'axios';

export class MagnitApiScraper {
  private browser: Browser | null = null;
  private page: Page | null = null;
  private httpClient: AxiosInstance;
  private cookies: string = '';
  private deviceId: string = '';

  constructor() {
    this.httpClient = axios.create({
      baseURL: 'https://magnit.ru',
      headers: {
        'accept': '*/*',
        'accept-language': 'ru,en-US;q=0.9,en;q=0.8',
        'content-type': 'application/json',
        'referer': 'https://magnit.ru/',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
        'x-app-version': '2025.12.12-16.56',
        'x-client-name': 'magnit',
        'x-device-platform': 'Web',
        'x-device-tag': 'disabled',
        'x-new-magnit': 'true',
        'x-platform-version': 'Windows Chrome 130',
      }
    });
  }

  async initialize() {
    // Запускаем браузер и получаем cookies
    this.browser = await chromium.launch({ headless: true });
    this.page = await this.browser.newPage();
    
    // Переходим на главную страницу
    await this.page.goto('https://magnit.ru/', { waitUntil: 'networkidle' });
    
    // Получаем cookies
    const cookies = await this.page.context().cookies();
    this.cookies = cookies.map(c => `${c.name}=${c.value}`).join('; ');
    
    // Извлекаем device-id из cookies
    const mgUdiCookie = cookies.find(c => c.name === 'mg_udi');
    if (mgUdiCookie) {
      this.deviceId = mgUdiCookie.value;
    } else {
      // Генерируем новый device-id если нет
      this.deviceId = this.generateDeviceId();
    }
    
    // Обновляем заголовки с device-id
    this.httpClient.defaults.headers['x-device-id'] = this.deviceId;
    this.httpClient.defaults.headers['cookie'] = this.cookies;
  }

  async getProductStores(productId: string, storeCode: string = '992301') {
    if (!this.page) {
      await this.initialize();
    }

    try {
      const response = await this.httpClient.get(
        `/webgate/v2/goods/${productId}/stores/${storeCode}`,
        {
          params: {
            storetype: '6',
            catalogtype: '1'
          }
        }
      );
      
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response?.status === 403) {
        // Если 403, обновляем сессию
        await this.initialize();
        return this.getProductStores(productId, storeCode);
      }
      throw error;
    }
  }

  private generateDeviceId(): string {
    // Генерация UUID формата: 9D4909B8-9F79-5B1D-8457-EA519EC9AA3F
    return 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'.replace(/[x]/g, () => {
      return (Math.random() * 16 | 0).toString(16).toUpperCase();
    });
  }

  async close() {
    if (this.browser) {
      await this.browser.close();
    }
  }
}

Вариант 2: Использовать Playwright напрямую для API-запросов

Делать запросы через контекст браузера Playwright:

async getProductStoresViaBrowser(productId: string, storeCode: string = '992301') {
  if (!this.page) {
    await this.initialize();
  }

  // Используем request API Playwright, который автоматически использует cookies браузера
  const response = await this.page!.request.get(
    `https://magnit.ru/webgate/v2/goods/${productId}/stores/${storeCode}?storetype=6&catalogtype=1`,
    {
      headers: {
        'accept': '*/*',
        'referer': 'https://magnit.ru/',
        'x-app-version': '2025.12.12-16.56',
        'x-client-name': 'magnit',
        'x-device-platform': 'Web',
        'x-new-magnit': 'true',
      }
    }
  );

  if (!response.ok()) {
    throw new Error(`API request failed: ${response.status()}`);
  }

  return await response.json();
}

Важные моменты

  1. Обязательные заголовки:

    • x-device-id — из cookie mg_udi
    • x-client-name: magnit
    • x-device-platform: Web
    • referer: https://magnit.ru/
    • cookie — все cookies из сессии
  2. Cookies, которые нужно передавать:

    • shopCode=992301
    • mg_udi (device-id)
    • oxxfgh, uwyii, uwyiert (сессионные)
  3. Рекомендация: использовать Playwright для инициализации сессии и получения cookies, затем делать запросы через page.request или передавать cookies в axios.

Нужна полная реализация MagnitApiScraper с этой логикой?

// src/scrapers/api/magnit/MagnitApiScraper.ts
import { chromium, Browser, Page } from 'playwright';
import axios, { AxiosInstance } from 'axios';

export class MagnitApiScraper {
  private browser: Browser | null = null;
  private page: Page | null = null;
  private httpClient: AxiosInstance;
  private cookies: string = '';
  private deviceId: string = '';

  constructor() {
    this.httpClient = axios.create({
      baseURL: 'https://magnit.ru',
      headers: {
        'accept': '*/*',
        'accept-language': 'ru,en-US;q=0.9,en;q=0.8',
        'content-type': 'application/json',
        'referer': 'https://magnit.ru/',
        'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36',
        'x-app-version': '2025.12.12-16.56',
        'x-client-name': 'magnit',
        'x-device-platform': 'Web',
        'x-device-tag': 'disabled',
        'x-new-magnit': 'true',
        'x-platform-version': 'Windows Chrome 130',
      }
    });
  }

  async initialize() {
    // Запускаем браузер и получаем cookies
    this.browser = await chromium.launch({ headless: true });
    this.page = await this.browser.newPage();
    
    // Переходим на главную страницу
    await this.page.goto('https://magnit.ru/', { waitUntil: 'networkidle' });
    
    // Получаем cookies
    const cookies = await this.page.context().cookies();
    this.cookies = cookies.map(c => `${c.name}=${c.value}`).join('; ');
    
    // Извлекаем device-id из cookies
    const mgUdiCookie = cookies.find(c => c.name === 'mg_udi');
    if (mgUdiCookie) {
      this.deviceId = mgUdiCookie.value;
    } else {
      // Генерируем новый device-id если нет
      this.deviceId = this.generateDeviceId();
    }
    
    // Обновляем заголовки с device-id
    this.httpClient.defaults.headers['x-device-id'] = this.deviceId;
    this.httpClient.defaults.headers['cookie'] = this.cookies;
  }

  async getProductStores(productId: string, storeCode: string = '992301') {
    if (!this.page) {
      await this.initialize();
    }

    try {
      const response = await this.httpClient.get(
        `/webgate/v2/goods/${productId}/stores/${storeCode}`,
        {
          params: {
            storetype: '6',
            catalogtype: '1'
          }
        }
      );
      
      return response.data;
    } catch (error) {
      if (axios.isAxiosError(error) && error.response?.status === 403) {
        // Если 403, обновляем сессию
        await this.initialize();
        return this.getProductStores(productId, storeCode);
      }
      throw error;
    }
  }

  private generateDeviceId(): string {
    // Генерация UUID формата: 9D4909B8-9F79-5B1D-8457-EA519EC9AA3F
    return 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'.replace(/[x]/g, () => {
      return (Math.random() * 16 | 0).toString(16).toUpperCase();
    });
  }

  async close() {
    if (this.browser) {
      await this.browser.close();
    }
  }
}
async getProductStoresViaBrowser(productId: string, storeCode: string = '992301') {
  if (!this.page) {
    await this.initialize();
  }

  // Используем request API Playwright, который автоматически использует cookies браузера
  const response = await this.page!.request.get(
    `https://magnit.ru/webgate/v2/goods/${productId}/stores/${storeCode}?storetype=6&catalogtype=1`,
    {
      headers: {
        'accept': '*/*',
        'referer': 'https://magnit.ru/',
        'x-app-version': '2025.12.12-16.56',
        'x-client-name': 'magnit',
        'x-device-platform': 'Web',
        'x-new-magnit': 'true',
      }
    }
  );

  if (!response.ok()) {
    throw new Error(`API request failed: ${response.status()}`);
  }

  return await response.json();
}

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

Проверяю, есть ли уже код для работы с API Магнита. Если нет, предложу решение для обхода 403 Forbidden.