# Ошибка 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-запросах: ```typescript // 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: ```typescript 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` с этой логикой? ```typescript // 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(); } } } ``` ```typescript 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.