1688: получить товар по URL
/1688/api/v1/item/by-url
Парсит страницу одного товара на 1688.com и возвращает структурированные данные.
Параметры запроса
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
url |
string | да | Полный URL страницы товара на 1688.com. Поддерживаются домены detail.1688.com, m.1688.com, offer.1688.com. |
Заголовки
| Заголовок | Обязательный | Описание |
|---|---|---|
X-API-Token |
да | Ваш API-токен. Альтернативно — query-параметр apiToken. |
Пример запроса
curl -X GET \
"https://bhapi.ru/1688/api/v1/item/by-url?url=https://detail.1688.com/offer/745678901234.html" \
-H "X-API-Token: ваш_токен_здесь"
Успешный ответ 200 OK
{
"code": 200,
"message": "OK",
"data": {
"item_id": "745678901234",
"url": "https://detail.1688.com/offer/745678901234.html",
"title": "2024新款春夏男士休闲运动鞋 透气网面跑步鞋",
"images": [
"https://cbu01.alicdn.com/img/ibank/O1CN01abcdef.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01ghijkl.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01mnopqr.jpg"
],
"desc_images": [
"https://cbu01.alicdn.com/img/ibank/O1CN01desc01.jpg",
"https://cbu01.alicdn.com/img/ibank/O1CN01desc02.jpg"
],
"detail_description": "Высококачественная спортивная обувь...",
"price_info": {
"currency": "CNY",
"price": 68.0,
"original_price": 128.0,
"tiers": [
{"from_qty": 1, "to_qty": 2, "price": 78.0},
{"from_qty": 3, "to_qty": 29, "price": 68.0},
{"from_qty": 30, "to_qty": null, "price": 58.0}
]
},
"inventory": 15000,
"rating": 4.8,
"review_count": 342,
"sold_count": 12500,
"attributes": {
"Материал подошвы": "EVA+резина",
"Материал верха": "Сетка+искусственная кожа",
"Стиль": "Спортивный",
"Сезон": "Весна/Лето"
},
"video_url": "https://cloud.video.taobao.com/play/u/xxx/e/6/t/1/xxx.mp4",
"video_poster": "https://cbu01.alicdn.com/img/poster.jpg",
"video_urls": [
"https://cloud.video.taobao.com/play/u/xxx/e/6/t/1/xxx.mp4"
],
"pack_info": [
{
"variant": "Чёрный",
"length_cm": 33.0,
"width_cm": 21.0,
"height_cm": 12.0,
"volume_cm3": 8316.0,
"weight_g": 680.0
}
],
"shop": {
"shop_id": "b2b-2210xxxxxx",
"shop_name": "莆田市鑫达鞋业有限公司",
"shop_url": "https://shop1234.1688.com"
},
"skus": [
{
"sku_id": "5021639372635",
"title": "Чёрный / 39",
"attributes": {"颜色": "黑色", "尺码": "39"},
"price": 68.0,
"inventory": 500
}
],
"raw": null
}
}
raw содержит дополнительные данные, которые не удалось нормализовать.
Оно может быть полезно для отладки или получения нестандартных данных.
1688: пакетный парсинг из файла
/1688/api/v1/item/by-file
Загрузите текстовый файл со списком URL (по одному в строке). Сервис последовательно обработает каждый URL и вернёт массив результатов.
Параметры
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
file |
file (multipart) | да | Текстовый файл UTF-8 со списком URL. По одному URL на строку. |
Ограничения
| Параметр | Значение |
|---|---|
| Максимальный размер файла | 1 МБ |
| Максимальное количество URL | 500 |
| Кодировка | UTF-8 |
Пример файла
https://detail.1688.com/offer/745678901234.html
https://detail.1688.com/offer/745678905678.html
https://detail.1688.com/offer/745678909012.html
Пример запроса
curl -X POST "https://bhapi.ru/1688/api/v1/item/by-file" \
-H "X-API-Token: ваш_токен_здесь" \
-F "file=@urls.txt"
Формат ответа
Массив объектов ItemDetailResponse. Ошибки для отдельных URL не прерывают весь запрос:
[
{
"code": 200,
"message": "OK",
"data": { "item_id": "745678901234", "title": "...", ... }
},
{
"code": 422,
"message": "URL не является ссылкой на товар 1688.com.",
"data": { "item_id": "unknown", "url": "https://example.com/wrong", ... }
}
]
Формат ответа
Для парсера 1688 все ответы API имеют единую обёртку ItemDetailResponse.
Поле code содержит бизнес-код результата, message — текстовое описание,
data — данные товара.
| Поле | Тип | Описание |
|---|---|---|
code | integer | Код результата. 200 — успех, остальные — ошибки. |
message | string | Человекочитаемое описание: "OK", сообщение об ошибке. |
data | ItemDetail | Объект с данными о товаре (см. Структура ItemDetail). |
Структура ItemDetail
Основной объект с данными товара парсера 1688, возвращаемый в поле data.
| Поле | Тип | Описание |
|---|---|---|
item_id | string | Идентификатор товара на 1688. |
url | string | Оригинальный URL товара. |
title | string | Название товара (на языке оригинала). |
images | string[] | Массив URL основных изображений товара. |
desc_images | string[] | URL изображений из описания товара (блок «подробности»). |
detail_description | string | null | Текстовое описание товара (характеристики, производство и т.п.). |
price_info | PriceInfo | null | Ценовая информация (см. Цены и SKU). |
inventory | integer | null | Общий остаток товара на складе. |
rating | float | null | Рейтинг товара (например, 4.8 из 5). |
review_count | integer | null | Количество отзывов о товаре. |
sold_count | integer | null | Количество продаж за период. |
attributes | object | Характеристики: материал, стиль, сезон и т.д. Ключ — название, значение — текст. |
video_url | string | null | URL первого видео товара. |
video_poster | string | null | Постер (превью) первого видео. |
video_urls | string[] | Все URL видео товара. |
pack_info | PackInfoItem[] | Информация об упаковке по вариантам (размеры, вес). |
shop | ShopInfo | null | Информация о магазине (см. Информация о магазине). |
skus | SkuItem[] | Список SKU / вариантов товара. |
raw | object | null | Дополнительные необработанные данные для отладки. |
Цены и SKU
PriceInfo
| Поле | Тип | Описание |
|---|---|---|
currency | string | Код валюты (CNY). |
price | float | Базовая цена товара. |
original_price | float | null | Старая цена (если есть скидка). |
tiers | PriceTier[] | Оптовые ценовые ступени. |
PriceTier — оптовые ступени
На 1688 цена зависит от количества. Чем больше заказ, тем ниже цена за единицу.
| Поле | Тип | Описание |
|---|---|---|
from_qty | integer | null | Минимальное количество (включительно). |
to_qty | integer | null | Максимальное количество (включительно). null — без верхней границы. |
price | float | Цена за единицу в этом диапазоне. |
"tiers": [
{"from_qty": 1, "to_qty": 2, "price": 78.0}, // 1-2 шт: 78 ¥
{"from_qty": 3, "to_qty": 29, "price": 68.0}, // 3-29 шт: 68 ¥
{"from_qty": 30, "to_qty": null, "price": 58.0} // от 30 шт: 58 ¥
]
SkuItem — варианты товара
| Поле | Тип | Описание |
|---|---|---|
sku_id | string | Идентификатор SKU. |
title | string | Название варианта (например, «Чёрный / 42»). |
attributes | object | Атрибуты: цвет, размер и т.д. |
price | float | null | Цена конкретного SKU (если отличается). |
inventory | integer | null | Остаток по этому варианту. |
PackInfoItem — упаковка
| Поле | Тип | Описание |
|---|---|---|
variant | string | Название варианта (цвет). |
length_cm | float | null | Длина упаковки, см. |
width_cm | float | null | Ширина, см. |
height_cm | float | null | Высота, см. |
volume_cm3 | float | null | Объём, см³. |
weight_g | float | null | Вес, г. |
Информация о магазине
| Поле | Тип | Описание |
|---|---|---|
shop_id | string | null | Идентификатор магазина на 1688. |
shop_name | string | null | Название магазина/компании. |
shop_url | string | null | URL магазина. |
Коды ошибок
При ошибке API возвращает JSON с кодом и описанием:
{
"code": 422,
"message": "URL не является ссылкой на товар 1688.com."
}
| Код | HTTP Status | Описание | Что делать |
|---|---|---|---|
400 |
Bad Request | Некорректный запрос. | Проверьте формат запроса и параметры. |
401 |
Unauthorized | Токен не передан или невалиден. | Убедитесь, что токен передан через X-API-Token или apiToken. |
403 |
Forbidden | Токен заблокирован или истёк. | Создайте новый токен в личном кабинете. |
413 |
Payload Too Large | Размер файла превышает 1 МБ. | Уменьшите файл или разбейте на несколько. |
417 |
Expectation Failed | Товар найден, но не удалось извлечь данные. | Возможно, страница товара изменена, снята с продажи или защищена. Попробуйте позже. |
422 |
Unprocessable Entity | URL не является ссылкой на товар 1688. | Проверьте, что URL ведёт на detail.1688.com, m.1688.com или offer.1688.com. |
429 |
Too Many Requests | Исчерпан дневной или общий лимит запросов. | Подождите до следующего дня или увеличьте лимит в настройках тарифа. |
439 |
Rate Limited | Слишком частые запросы (rate limit). | Добавьте задержку между запросами (1-2 секунды). |
499 |
Client Closed | Клиент закрыл соединение до завершения обработки. | Увеличьте таймаут на стороне клиента (рекомендуется 30+ секунд). |
500 |
Internal Server Error | Внутренняя ошибка сервиса. | Повторите запрос через несколько секунд. Если ошибка повторяется — свяжитесь с поддержкой. |
503 |
Service Unavailable | Сервис временно недоступен. | Попробуйте позже. Проводятся технические работы. |
Лимиты и квоты
У каждого API-токена есть два типа лимитов:
| Тип лимита | Описание | Сброс |
|---|---|---|
Дневной (limit_daily) |
Максимальное число запросов в сутки (UTC). | Каждый день в 00:00 UTC. |
Общий (limit_total) |
Максимальное общее число запросов за всё время жизни токена. | Не сбрасывается. При исчерпании — создайте новый токен. |
Рекомендации по оптимизации:
- Добавляйте паузу 1-2 секунды между запросами, чтобы не попасть под rate limit.
- Используйте пакетный эндпоинт
/by-fileвместо последовательных/by-url. - Кэшируйте результаты на своей стороне — данные товара обновляются не чаще раза в час.
Примеры: Python
Простой запрос одного товара
import requests
API_URL = "https://bhapi.ru/api/v1/item/by-url"
TOKEN = "ваш_токен_здесь"
response = requests.get(
API_URL,
params={"url": "https://detail.1688.com/offer/745678901234.html"},
headers={"X-API-Token": TOKEN},
timeout=30,
)
data = response.json()
if data["code"] == 200:
item = data["data"]
print(f"Товар: {item['title']}")
print(f"Цена: {item['price_info']['price']} {item['price_info']['currency']}")
print(f"Изображений: {len(item['images'])}")
print(f"SKU вариантов: {len(item['skus'])}")
print(f"Магазин: {item['shop']['shop_name']}")
else:
print(f"Ошибка {data['code']}: {data['message']}")
Пакетная обработка списка URL
import requests
import json
import time
API_URL = "https://bhapi.ru/api/v1/item/by-url"
TOKEN = "ваш_токен_здесь"
urls = [
"https://detail.1688.com/offer/745678901234.html",
"https://detail.1688.com/offer/745678905678.html",
"https://detail.1688.com/offer/745678909012.html",
]
results = []
for url in urls:
response = requests.get(
API_URL,
params={"url": url},
headers={"X-API-Token": TOKEN},
timeout=30,
)
data = response.json()
results.append(data)
if data["code"] == 200:
print(f"✓ {data['data']['title'][:50]}…")
else:
print(f"✗ Ошибка {data['code']}: {data['message']}")
time.sleep(1.5) # пауза, чтобы не превысить rate limit
# Сохраняем результаты
with open("results.json", "w", encoding="utf-8") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f"\nОбработано: {len(results)} товаров")
Загрузка файла с URL
import requests
API_URL = "https://bhapi.ru/api/v1/item/by-file"
TOKEN = "ваш_токен_здесь"
with open("urls.txt", "rb") as f:
response = requests.post(
API_URL,
headers={"X-API-Token": TOKEN},
files={"file": ("urls.txt", f, "text/plain")},
timeout=120, # файл может обрабатываться долго
)
results = response.json()
success = sum(1 for r in results if r["code"] == 200)
print(f"Успешно: {success}/{len(results)}")
for item in results:
if item["code"] == 200:
d = item["data"]
print(f" {d['item_id']}: {d['title'][:40]}… — {d['price_info']['price']} CNY")
else:
print(f" Ошибка {item['code']}: {item['message']}")
Извлечение оптовых цен
# Предположим, item — это data["data"] из успешного ответа
price_info = item["price_info"]
print(f"Базовая цена: {price_info['price']} {price_info['currency']}")
if price_info.get("original_price"):
discount = round((1 - price_info['price'] / price_info['original_price']) * 100)
print(f"Скидка: {discount}% (было {price_info['original_price']})")
print("\nОптовые ступени:")
for tier in price_info["tiers"]:
to = tier["to_qty"] or "∞"
print(f" {tier['from_qty']}–{to} шт: {tier['price']} ¥")
# Рассчитаем стоимость заказа из 50 единиц
order_qty = 50
applicable_price = price_info["price"]
for tier in price_info["tiers"]:
if tier["from_qty"] <= order_qty:
if tier["to_qty"] is None or tier["to_qty"] >= order_qty:
applicable_price = tier["price"]
total = applicable_price * order_qty
print(f"\nЗаказ {order_qty} шт: {applicable_price} × {order_qty} = {total} ¥")
Примеры: cURL
Получить данные товара
# Через заголовок (рекомендуется)
curl -X GET \
"https://bhapi.ru/api/v1/item/by-url?url=https://detail.1688.com/offer/745678901234.html" \
-H "X-API-Token: ваш_токен"
# Через query-параметр
curl -X GET \
"https://bhapi.ru/api/v1/item-by-url?url=https://detail.1688.com/offer/745678901234.html&apiToken=ваш_токен"
Загрузить файл с URL
curl -X POST "https://bhapi.ru/api/v1/item/by-file" \
-H "X-API-Token: ваш_токен" \
-F "file=@urls.txt"
Сохранить результат в файл
curl -s -X GET \
"https://bhapi.ru/api/v1/item/by-url?url=https://detail.1688.com/offer/745678901234.html" \
-H "X-API-Token: ваш_токен" | python3 -m json.tool > result.json
Примеры: JavaScript
Fetch API (браузер / Node.js 18+)
const API_URL = "https://bhapi.ru/api/v1/item/by-url";
const TOKEN = "ваш_токен_здесь";
async function getItem(productUrl) {
const params = new URLSearchParams({ url: productUrl });
const response = await fetch(`${API_URL}?${params}`, {
method: "GET",
headers: { "X-API-Token": TOKEN },
});
const data = await response.json();
if (data.code === 200) {
console.log("Товар:", data.data.title);
console.log("Цена:", data.data.price_info.price, data.data.price_info.currency);
console.log("SKU:", data.data.skus.length, "вариантов");
return data.data;
} else {
console.error(`Ошибка ${data.code}: ${data.message}`);
return null;
}
}
getItem("https://detail.1688.com/offer/745678901234.html");
Node.js с axios
const axios = require("axios");
const api = axios.create({
baseURL: "https://bhapi.ru",
headers: { "X-API-Token": "ваш_токен" },
timeout: 30000,
});
async function parseProduct(url) {
try {
const { data } = await api.get("/api/v1/item/by-url", {
params: { url },
});
if (data.code === 200) {
return data.data;
}
throw new Error(`API ошибка ${data.code}: ${data.message}`);
} catch (err) {
console.error("Ошибка:", err.message);
return null;
}
}
parseProduct("https://detail.1688.com/offer/745678901234.html")
.then(item => {
if (item) {
console.log(JSON.stringify(item, null, 2));
}
});
Примеры: PHP
PHP с cURL
<?php
$apiUrl = "https://bhapi.ru/api/v1/item/by-url";
$token = "ваш_токен_здесь";
$productUrl = "https://detail.1688.com/offer/745678901234.html";
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $apiUrl . "?" . http_build_query(["url" => $productUrl]),
CURLOPT_HTTPHEADER => ["X-API-Token: " . $token],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$data = json_decode($response, true);
if ($data["code"] === 200) {
$item = $data["data"];
echo "Товар: " . $item["title"] . "\n";
echo "Цена: " . $item["price_info"]["price"] . " " . $item["price_info"]["currency"] . "\n";
echo "Вариантов: " . count($item["skus"]) . "\n";
} else {
echo "Ошибка {$data['code']}: {$data['message']}\n";
}
Загрузка файла (PHP)
<?php
$apiUrl = "https://bhapi.ru/api/v1/item/by-file";
$token = "ваш_токен_здесь";
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $apiUrl,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["X-API-Token: " . $token],
CURLOPT_POSTFIELDS => ["file" => new CURLFile("urls.txt", "text/plain")],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
]);
$response = curl_exec($ch);
curl_close($ch);
$results = json_decode($response, true);
foreach ($results as $item) {
if ($item["code"] === 200) {
echo "✓ " . $item["data"]["title"] . "\n";
} else {
echo "✗ Ошибка {$item['code']}: {$item['message']}\n";
}
}
Пакетная обработка
Для парсинга большого количества товаров рекомендуем использовать эндпоинт /by-file
или скрипт с паузами между запросами. Ниже — пример скрипта с обработкой ошибок и повторными попытками.
import requests
import time
import json
API_URL = "https://bhapi.ru/api/v1/item/by-url"
TOKEN = "ваш_токен_здесь"
MAX_RETRIES = 3
DELAY = 2 # секунды между запросами
def fetch_item(url: str) -> dict | None:
"""Получает данные товара с повторными попытками."""
for attempt in range(1, MAX_RETRIES + 1):
try:
resp = requests.get(
API_URL,
params={"url": url},
headers={"X-API-Token": TOKEN},
timeout=30,
)
data = resp.json()
if data["code"] == 200:
return data["data"]
# Ошибки, при которых повтор не поможет
if data["code"] in (401, 403, 422):
print(f" Фатальная ошибка {data['code']}: {data['message']}")
return None
# Ошибки rate limit — ждём дольше
if data["code"] in (429, 439):
wait = DELAY * attempt * 5
print(f" Rate limit, ожидание {wait}с...")
time.sleep(wait)
continue
# Серверные ошибки — повторяем
print(f" Попытка {attempt}/{MAX_RETRIES}: ошибка {data['code']}")
except requests.RequestException as e:
print(f" Попытка {attempt}/{MAX_RETRIES}: {e}")
time.sleep(DELAY * attempt)
return None
# Основной цикл
urls = open("urls.txt").read().strip().splitlines()
results = []
for i, url in enumerate(urls, 1):
print(f"[{i}/{len(urls)}] {url[:60]}...")
item = fetch_item(url)
if item:
results.append(item)
print(f" ✓ {item['title'][:50]}")
else:
print(f" ✗ Не удалось получить данные")
time.sleep(DELAY)
with open("results.json", "w", encoding="utf-8") as f:
json.dump(results, f, ensure_ascii=False, indent=2)
print(f"\nГотово: {len(results)}/{len(urls)} товаров")
Формат ответа
Для парсера 1688 все ответы API имеют единую обёртку ItemDetailResponse.
Поле code содержит бизнес-код результата, message — текстовое описание,
data — данные товара.
| Поле | Тип | Описание |
|---|---|---|
code | integer | Код результата. 200 — успех, остальные — ошибки. |
message | string | Человекочитаемое описание: "OK", сообщение об ошибке. |
data | ItemDetail | Объект с данными о товаре (см. Структура ItemDetail). |