В данной статье напишем парсер торговой площадки Wildberries на python, который основан на взаимодействии с API данного сайта.
Введение
В наше время большой популярностью пользуется торговая площадка Wildberries. Так как на Вайлдберриз можно найти большое количество скидок и распродаж, урвать товар по привлекательно низкой цене, а в случае чего, даже вернуть товар без вреда своему кошельку, главное не злоупотреблять этим =)
Многие подписчики нашей группы в ВКонтакте просили реализовать скрипт сбора данных для данного маркетплейса, а точнее написать парсер wildberries.
Написанный нами парсер, будет основан на работе и взаимодействии с API сайта Wildberries, что увеличивает скорость сбора интересующих вас данных. Можно собрать до 10 тысяч наименований товаров с одной группы.
Код проекта на Github
Анонс парсера Wildberries через telegram бот
Дополнительно мы реализовали парсер Wildberries через telegram бота, написанного на aiogram 3.ХХ и запустили в тестовом режиме на сервере, пока абсолютно без ограничений, для отладки и устранения багов, оттачивания юзабилити бота.
На данный момент функционал бота:
- Парсер WB по ссылке на категорию;
- Парсер WB по поисковому запросу;
- Парсер WB по ссылке на бренд.
В дальнейших планах:
- Парсер товаров продавца на WB
- Парсер отзывов на товар по артикулу WB
Следить за разработкой и задавать вопросы можете в телеграм канале Тимур и его блог.
Пример того, что мы получим
Для примера прикреплю скриншот файла excel, который был сформирован после выполнения нашего парсера (см. Рисунок 1.) Собранные нами данные: наименование, id, скидка, цена, цена со скидкой, бренд, количество отзывов, рейтинг товара, ссылка. Сбор производится по API Wildberries, поэтому сбор проходит очень быстро. Ограничение в 10 тысяч позиций (или 100 страниц выдачи) В будущем мы будем собирать более подробное описание товара и даже вытаскивать из API остатки товара со складов Вайлдбериз.
Последовательность написания скрипта парсера
Краткое содержание всех функций парсера Вилдберрис:
- Получение списка всех каталогов wildberries. Функция get_catalogs_wb
- Поиск пользовательской категории в списке каталогов. Функция search_category_in_catalog
- Извлечение данных из json файла с информацией о товарах. Функция get_data_from_json
- Постраничный сбор данных. Функция get_content
- Сохранение данных в эксель файл при помощи библиотеки pandas. Функция save_excel
- Основная функция выполняющая все выше перечисленные. Функция parser
Получаем список каталогов для парсера (get_catalogs_wb)
Все возможные каталоги площадки WildBerries мы получим через API. Для этого откроем «консоль разработчика (devtool)», выберем «сеть (network)» (пункт 1, рисунок 2), включим фильтр «XHR» (пункт 2, рисунок 2), очистим все что там загрузилось (пункт 3, рисунок 2). Далее нажмем на поиск (пункт 4, рисунок 2) и справа в нашем списке подгруженных файлов появится main-menu-ru-ru.json
Выберем на main-menu-ru-ru.json (пункт 1, рисунок 3) Посмотрим его содержимое, для этого нажмем «ответ (response)» (пункт 2, рисунок 3) и убедимся что это то, что мы искали, каталог (пункт 3, рисунок 3)!
Далее к полученной ссылке применим библиотеку requests (не забудем ее заранее установить pip install requests и импортировать). И ответ сохраним в виде json. Для наглядности рекомендую сохранить результат в .json файл, чтобы было легче понять, что откуда берется.
url = 'https://www.wildberries.ru/webapi/menu/main-menu-ru-ru.json'
headers = {'Accept': "*/*", 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
response = requests.get(url, headers=headers)
data = response.json()
with open('wb_catalogs_data.json', 'w', encoding='UTF-8') as file:
json.dump(data, file, indent=2, ensure_ascii=False)
print(f'Данные сохранены в wb_catalogs_data.json')
На Рисунке 4 Показана часть файла полученного json файла с сервера wildberries. Из него нас интересует поля url (ссылка на каталог), shard (название каталога), query (подразделы)
Создадим список data_list и заполним его всеми возможными подкаталогами. А именно из childs будем брать url, shard, query. Функция get_catalogs_wb будет возвращать этот список. Ниже код этой функции.
def get_catalogs_wb():
url = 'https://www.wildberries.ru/webapi/menu/main-menu-ru-ru.json'
headers = {'Accept': "*/*", 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
response = requests.get(url, headers=headers)
data = response.json()
data_list = []
for d in data:
try:
for child in d['childs']:
try:
category_name = child['name']
category_url = child['url']
shard = child['shard']
query = child['query']
data_list.append({
'category_name': category_name,
'category_url': category_url,
'shard': shard,
'query': query})
except:
continue
try:
for sub_child in child['childs']:
category_name = sub_child['name']
category_url = sub_child['url']
shard = sub_child['shard']
query = sub_child['query']
data_list.append({
'category_name': category_name,
'category_url': category_url,
'shard': shard,
'query': query})
except:
continue
except:
continue
return data_list
Проверяем ссылку от пользователя на наличие в каталоге (search_category_in_catalog)
Фукция на входе получает url каталога от пользователя и список всех возможных каталогов (data_list) от предыдущей функции.
def search_category_in_catalog(url, catalog_list):
try:
for catalog in catalog_list:
if catalog['category_url'] == url.split('https://www.wildberries.ru')[-1]:
print(f'найдено совпадение: {catalog["category_name"]}')
name_category = catalog['category_name']
shard = catalog['shard']
query = catalog['query']
return name_category, shard, query
else:
# print('нет совпадения')
pass
except:
print('Данный раздел не найден!')
Если каталог пользователя найден, возвращает название категории (name_category), ссылку на нее (shard) и подразделы данного каталога (query), иначе вывод сообщения «категория не найдена»
Извлекаем из json данные (get_data_from_json)
Извлекаем данные с полученного json файла (пример карточки 1 товара на Рисунок 5). Например я взял: наименование, id, скидку (sale), цену (priceU), цену со скидкой (salePriceU), бренд (brand), отзывы (feedbacks), рейтинг (rating) и ссылку товара
Функция возвращает нам список data_list в который мы записали все вышеперечисленные поля каждого товара. Код функции целиком:
def get_data_from_json(json_file):
data_list = []
for data in json_file['data']['products']:
try:
price = int(data["priceU"] / 100)
except:
price = 0
data_list.append({
'Наименование': data['name'],
'id': data['id'],
'Скидка': data['sale'],
'Цена': price,
'Цена со скидкой': int(data["salePriceU"] / 100),
'Бренд': data['brand'],
'id бренда': int(data['brandId']),
'feedbacks': data['feedbacks'],
'rating': data['rating'],
'Ссылка': f'https://www.wildberries.ru/catalog/{data["id"]}/detail.aspx?targetUrl=BP'
})
return data_list
Сбор контента со всех страниц выдачи (get_content)
Сразу скажу, wildberries выдает только первые 100 страниц выдачи, или 10 000 позиций, для решения данной проблемы я решил добавить фильтр по ценовому диапазону, который будет сокращать количество выдачи.
На входе функция будет получать shard (название каталога), query (подразделы) и для снижения количества выдачи ценовой диапазон от low_price до top_price.
Создаем цикл из 100 страниц и идем по нему до тех пор пока, количество выдачи не будет равно 0 или не закончатся страницы (100 штук)
def get_content(shard, query, low_price=None, top_price=None):
headers = {'Accept': "*/*", 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
data_list = []
for page in range(1, 101):
print(f'Сбор позиций со страницы {page} из 100')
url = f'https://catalog.wb.ru/catalog/{shard}/catalog?appType=1&curr=rub&dest=-1075831,-77677,-398551,12358499' \
f'&locale=ru&page={page}&priceU={low_price * 100};{top_price * 100}' \
f'®ions=64,83,4,38,80,33,70,82,86,30,69,1,48,22,66,31,40&sort=popular&spp=0&{query}'
r = requests.get(url, headers=headers)
data = r.json()
print(f'Добавлено позиций: {len(get_data_from_json(data))}')
if len(get_data_from_json(data)) > 0:
data_list.extend(get_data_from_json(data))
else:
print(f'Сбор данных завершен.')
break
return data_list
Функция сохранения данных в excel (save_excel)
Пишем функцию записи в эксель файл, используя библиотеку pandas. На входе принимаем сами данные (data) и название файла (filename) под которым будем их сохранять
def save_excel(data, filename):
df = pd.DataFrame(data)
writer = pd.ExcelWriter(f'{filename}.xlsx')
df.to_excel(writer, 'data')
writer.save()
print(f'Все сохранено в {filename}.xlsx')
Основная функция (parser)
Разберем основную функцию:
Первым делом спарсим каталог применив функцию get_catalogs_wb сохранив его в переменную catalog_list
Далее в блоке try-except из найденного каталога извлекаем название категории (name_category), название каталога (shard) и подраздел (query) при помощи функции search_category_in_catalog.
Создаем список данных о товаре использовав функцию get_content, в которую передаем раздел и подраздел (shard, query) и ограничение в виде ценового диапазона, от нижней цены (low_price) до верхнего предела (top_price) для сокращения результатов выдачи (рекомендую если ее свыше 10 тысяч).
По итогу выполнения кода, полученные результаты передадим в save_excel для сохранения в excel файл, передав сами данные и названия файла в формате: названиекатегории_from_нижняяцена_to_верхняяцена.
def parser(url, low_price, top_price):
catalog_list = get_catalogs_wb()
try:
name_category, shard, query = search_category_in_catalog(url=url, catalog_list=catalog_list)
data_list = get_content(shard=shard, query=query, low_price=low_price, top_price=top_price)
save_excel(data_list, f'{name_category}_from_{low_price}_to_{top_price}')
except TypeError:
print('Ошибка! Возможно не верно указан раздел. Удалите все доп фильтры с ссылки')
except PermissionError:
print('Ошибка! Вы забыли закрыть созданный ранее excel файл. Закройте и повторите попытку')
Запуск парсинга Вайлбериз (Wildberries)
Для запуска воспользуемся конструкцией if __name__ == ‘__main__’
if __name__ == '__main__':
url = input('Введите ссылку на категорию для сбора: ')
low_price = int(input('Введите минимальную сумму товара: '))
top_price = int(input('Введите максимальную сумму товара: '))
parser(url, low_price, top_price)
Добавлю в код тестовые данные: ссылку на каталог велосипедов (url), нижнюю и верхнюю цены товаров 50000 и 100000 соответственно:
if __name__ == '__main__':
url = 'https://www.wildberries.ru/catalog/sport/vidy-sporta/velosport/velosipedy'
low_price = 5000
top_price = 100000
parser(url, low_price, top_price)
Запустим парсер и следим за процессом выполнения скрипта (Рисунок 6):
Мы получили 274 позиции и сохранили их в эксель файл Велосипеды_from_50000_to_100000.xlsx. Откроем и проверим, что у нас получилось (Рисунок 7):
От автора
Спасибо за прочтение, по всем возникающим вопросам и предложениям пишем Мне.
Реализовали тестовый телеграм бот для парсинга Wildberries (Блог разработки)
По данной статье и коду принимаю критику, предложения по улучшению кода. Парсер будет улучшаться, добавляться новые функции, такие как подтягивание более полных данных о товаре, остатки товаров на складах. Так же свои отзывы и предложения вы можете писать в нашу группу ВКонтакте или в чате Telegram.
Статью про парсер комментариев с Wildberries можете почитать в нашей новой статье: Selenium webdriver в python. Поиск элементов на примере парсера комментариев Wildberries
Подпишитесь на рассылку
Genuinely when someone doesn’t understand afterward its up to other viewers that they will help, so here it happens.
Очень крутой материал
I was extremely pleased to uncover this page. I want to to thank you for your time due to this wonderful read!! I definitely savored every little bit of it and i also have you book marked to look at new things in your site.
Не пойму как конкретную страницу парсить — у меня массив с сылками на страницы.
Напишите разработчику
Было бы прикольно если можно было бы вставить ссылку на определенный бренд и он её бы парсил
всего достаточно добавить в функцию get_content, в переменную url один аргумент fbrand, нужно только догадаться откуда его достать. так как он требует id. но это тоже не сложно моно просить сначала ссылку на бренд где все его товары, оттуда доставать id, а уже потом просить ссылку на каталог
Good stuff, thanks! I did this through Scrapy…
import json
import scrapy
import pandas as pd
# scrapy crawl rendering -O Aprint.json
class Scrapylite(scrapy.Spider):
name = ‘rendering’
allowed_domains = [‘catalog.wb.ru’]
start_urls = [‘https://catalog.wb.ru/catalog/dresses/catalog?appType=1&couponsGeo=2,12,7,3,6,18,22,21&curr=rub&dest=-1075831,-72194,-287507,-284542&emp=0&kind=2&lang=ru&locale=ru&page=1&pricemarginCoeff=1.0®=1®ions=80,64,83,4,38,33,70,69,86,30,40,48,1,66,31,68,22&sort=popular&spp=31&sppFixGeo=4&subject=69;70’]
file = open(‘RenderData.csv’, mode=’w’)
file.close()
def parse(self, response, **kwargs):
data = json.loads(response.body)
res = data[‘data’][‘products’]
data_frame = pd.DataFrame(res)
data_frame.to_csv(‘RenderData.csv’, index=False, mode=’a’, encoding=’UTF-8-sig’, sep=’;’)
yield from res
for page in range(2, 3):
next_page = f’https://catalog.wb.ru/catalog/dresses/catalog?appType=1&couponsGeo=2,12,7,3,6,18,22,21&curr=rub&dest=-1075831,-72194,-287507,-284542&emp=0&kind=2&lang=ru&locale=ru&page={page}&pricemarginCoeff=1.0®=1®ions=80,64,83,4,38,33,70,69,86,30,40,48,1,66,31,68,22&sort=popular&spp=31&sppFixGeo=4&subject=69;70′
yield response.follow(next_page, callback=self.parse)
Спасибо, очень крутой материал. А как спарсить ко всем данным еще и картинку этого товара с каталога? Нашла в запросах только вот подобную ссылку. Но не понятно, как для каждого взять эти картинки.
Напишите автору статьи, его данные указаны в конце статьи