13 KiB
Ошибка 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 проверяет:
- Cookies (сессия)
- Заголовки, имитирующие браузер
- 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();
}
Важные моменты
-
Обязательные заголовки:
x-device-id— из cookiemg_udix-client-name: magnitx-device-platform: Webreferer: https://magnit.ru/cookie— все cookies из сессии
-
Cookies, которые нужно передавать:
shopCode=992301mg_udi(device-id)oxxfgh,uwyii,uwyiert(сессионные)
-
Рекомендация: использовать 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.