Audible, это сервис аудиокниг Amazon, чей публичный каталог насчитывает сотни тысяч наименований в каждом жанре, каждое из которых указано с автором, чтецом, продолжительностью, звёздным рейтингом и ценой. Страницы поиска и категорий, один из самых чистых срезов рынка аудиокниг в открытом вебе, именно поэтому аналитики, библиотекари и энтузиасты обращаются к ним для отслеживания цен, составления списков для чтения и изучения того, что продаётся.

Это руководство показывает, как парсить данные аудиокниг Audible с помощью Python и собирать результаты в небольшой файл "мини-библиотеки". Вы строите рабочий парсер, который получает страницу поиска или категории Audible через Crawling API, разбирает чистую запись на каждую аудиокнигу, обрабатывает пагинацию и экспортирует набор в JSON и CSV. Всё руководство ограничено публичными данными каталога: названиями, авторами, чтецами, продолжительностью, рейтингами и ценами, которые любой может видеть на странице результатов без входа в аккаунт. Аудиофайлы мы никогда не трогаем.

Что вы построите

Python-скрипт, принимающий URL поиска или категории Audible, получающий отрендеренный листинг через Crawling API и извлекающий структурированную запись для каждой аудиокниги. В качестве рабочего примера мы используем страницу результатов категории и извлекаем следующие поля из каждой карточки товара:

  • Title, название аудиокниги, как показано на карточке листинга.
  • Author, автор, указанный на обложке, "By: ..." на карточке.
  • Narrator, исполнитель, "Narrated by: ..." на карточке.
  • Length, общая продолжительность, например "10 hrs and 32 mins".
  • Rating, средний звёздный рейтинг, если у наименования он есть.
  • Price, указанная цена, если карточка её отображает.
  • Link, URL собственной страницы аудиокниги.

Почему простой запрос не работает на Audible

Если направить голый HTTP-клиент на URL результатов Audible, вы редко получаете нужный листинг. Два фактора работают против вас. Во-первых, Audible рендерит большую часть сетки товаров на стороне клиента: он отправляет лёгкую оболочку и заполняет карточки по мере выполнения JavaScript страницы, поэтому исходный HTML нередко не содержит продолжительности, цен и рейтингов. Во-вторых, как продукт Amazon, Audible быстро помечает автоматизированный трафик. Диапазоны IP дата-центров и паттерны запросов, непохожие на реальный браузер, встречаются CAPTCHA, межстраничным интерстициалом "проверка робота" или прямой блокировкой ещё до того, как вы доберётесь до списка.

Таким образом, рабочий парсер Audible нуждается в двух вещах в одном запросе: браузере, рендерящем страницу, и IP, который Audible воспринимает как реального посетителя. Можно собрать это самостоятельно с headless-браузером и пулом ротирующих жилых прокси, но поддержание этого стека в рабочем состоянии, это большая часть всей работы. Crawling API объединяет оба аспекта в один вызов: вы отправляете ему URL результатов, он рендерит страницу за доверенным жилым IP, обрабатывает ротацию и решение CAPTCHA и возвращает готовый HTML для разбора.

Предварительные требования

Перед написанием кода нужно подготовить несколько вещей. Ни одна из них не займёт много времени.

Базовые знания Python. Вы должны уметь писать и запускать Python-скрипты и устанавливать пакеты с помощью pip. Если вы новичок в языке, официальная документация Python или любой вводный курс охватывает уровень, предполагаемый в этом руководстве.

Python 3.8 или выше. Проверьте версию командой python --version (или python3 --version). Если Python не установлен, скачайте его с python.org и убедитесь, что Python добавлен в системный PATH.

Аккаунт Crawlbase и токен. Зарегистрируйте бесплатный аккаунт, откройте дашборд и скопируйте токен. Бесплатный тариф включает до 20 000 запросов без карты, чего вполне достаточно для создания и тестирования этого парсера. Относитесь к токену как к паролю и не храните его в системе контроля версий.

Настройка проекта

Создайте виртуальное окружение, чтобы зависимости проекта оставались изолированными, а затем установите две необходимые библиотеки. crawlbase, официальный клиент Crawling API, а beautifulsoup4 разбирает возвращённый HTML, чтобы вы могли извлечь каждое поле из карточек листинга по CSS-селектору.

bash
python --version

python -m venv audible_env
source audible_env/bin/activate

pip install crawlbase beautifulsoup4

В Windows активируйте окружение командой audible_env\Scripts\activate вместо строки source. Установив обе библиотеки, создайте файл скрипта, который строится в остальной части руководства:

bash
touch audible_library.py

Понимание страницы результатов Audible

Audible организует каталог по принципу библиотеки, где одно наименование может одновременно относиться к нескольким перекрывающимся категориям. Каждая категория и каждый поиск находятся по стабильному URL, например https://www.audible.com/search?node=18573211011 для узла категории или https://www.audible.com/search?keywords=science+fiction для поиска по ключевому слову. Оба рендерят одинаковую сетку результатов: упорядоченный список карточек товаров, по одной на аудиокнигу, каждая содержит название, строку автора, строку чтеца, продолжительность, рейтинг и цену.

Перед написанием селекторов откройте страницу результатов в браузере, щёлкните правой кнопкой мыши на карточку товара и выберите "Inspect". Audible оборачивает каждый результат в элемент списка с пометкой li.productListItem, помещает название в ссылку h3.bc-heading и обозначает строки автора и чтеца с помощью li.authorLabel и li.narratorLabel. Продолжительность находится в li.runtimeLabel, а рейтинг, в li.ratingsLabel. Именно эти элементы вы и целите. Имена утилитарных классов Audible меняются со временем, поэтому опирайтесь на более устойчивые классы меток, а не на хрупкую цепочку сгенерированных имён.

Шаг 1: получение отрендеренной страницы результатов

Начните с получения готовой страницы. Импортируйте класс CrawlingAPI, инициализируйте его токеном, задайте URL результатов и запросите его. Проверка кода статуса перед разбором делает ошибки явными, а не тихими.

python
from crawlbase import CrawlingAPI

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 4000}
    response = api.get(page_url, options)
    if response["status_code"] == 200:
        return response["body"].decode("latin1")
    print(f"Request failed: {response['status_code']}")
    return None

if __name__ == "__main__":
    results_url = "https://www.audible.com/search?keywords=science+fiction"
    html = crawl(results_url)
    print(html[:500] if html else "No HTML returned")

Два параметра ожидания важны для сетки, заполняемой по мере загрузки страницы. ajax_wait говорит API дождаться завершения асинхронного контента, а page_wait выдерживает фиксированное количество миллисекунд после загрузки, чтобы карточки с поздним рендерингом появились перед захватом страницы. Тело декодируется как latin1, потому что страницы Audible содержат символы, на которых может захлебнуться строгое декодирование в UTF-8. Запустите скрипт, и вы должны увидеть реальную разметку листинга, а не оболочку с проверкой робота. Это подтверждает работу рендеринга до написания единого селектора.

Crawlbase Crawling API

Страница результатов Audible требует отрендеренной сетки за доверенным IP за один вызов. Crawling API принимает токен, запускает страницу поиска в настоящем браузере, ротирует через жилые IP на стороне сервера и обрабатывает решение CAPTCHA, затем передаёт готовый HTML. Вы не запускаете сами флот headless-браузеров и пул прокси. Сначала направьте его на URL поиска или категории на бесплатном тарифе с лимитом до 20 000 запросов.

Шаг 2: разбор карточек аудиокниг с помощью BeautifulSoup

Имея отрендеренный HTML, загрузите его в BeautifulSoup, найдите каждую карточку товара и извлеките каждое поле по его селектору. Audible оборачивает каждый результат в li.productListItem, помещает название в ссылку заголовка и обозначает строки автора, чтеца, продолжительности и рейтинга собственными классами. Читайте ссылку на страницу сведений из якоря заголовка. Оборачивайте каждую карточку в try/except, чтобы одна некорректная запись не роняла весь запуск.

python
from bs4 import BeautifulSoup

BASE = "https://www.audible.com"

def text_of(card, selector):
    el = card.select_one(selector)
    return el.get_text(strip=True) if el else None

def strip_label(value, label):
    if value and value.startswith(label):
        return value[len(label):].strip()
    return value

def parse_link(card):
    a = card.select_one("h3.bc-heading a[href]")
    if not a:
        return None
    href = a["href"].split("?")[0]
    return href if href.startswith("http") else BASE + href

def scrape_audiobooks(html):
    soup = BeautifulSoup(html, "html.parser")
    cards = soup.select("li.productListItem")
    results = []
    for card in cards:
        try:
            author = text_of(card, "li.authorLabel")
            narrator = text_of(card, "li.narratorLabel")
            results.append({
                "title": text_of(card, "h3.bc-heading a"),
                "author": strip_label(author, "By:"),
                "narrator": strip_label(narrator, "Narrated by:"),
                "length": strip_label(text_of(card, "li.runtimeLabel"), "Length:"),
                "rating": text_of(card, "li.ratingsLabel span.bc-text"),
                "price": text_of(card, "p.buybox-regular-price span.bc-text"),
                "link": parse_link(card),
            })
        except Exception as e:
            print(f"Skipped a card: {e}")
    return results

Вспомогательная функция text_of запрашивает один элемент внутри карточки и возвращает None при его отсутствии вместо того, чтобы выбрасывать исключение при вызове .get_text() для ничего. Это делает извлечение устойчивым, когда поле отсутствует, что типично, поскольку не каждое наименование показывает цену или рейтинг. Вспомогательная функция strip_label убирает префиксы By:, Narrated by: и Length:, которые Audible печатает внутри строк этих меток, чтобы вы хранили чистые значения. Ссылка читается из якоря заголовка, строка запроса отбрасывается, и она нормализуется до абсолютного URL, поскольку Audible отдаёт относительный href.

Selectors drift

Генерированные утилитарные имена классов Audible меняются без предупреждения, тогда как семантические классы меток (li.authorLabel, li.narratorLabel, li.runtimeLabel, li.ratingsLabel) более устойчивы. Относитесь к приведённым выше селекторам как к начальному шаблону, а не к контракту. Когда поле возвращается как None для каждой карточки, повторно проверьте страницу живых результатов в инструментах разработчика браузера и обновите селектор. Периодическое обслуживание селекторов нормально для любого продакшн-парсера.

Шаг 3: обработка пагинации, сборка и экспорт

Одна страница результатов, это демо; настоящая мини-библиотека охватывает всю категорию. Audible пагинирует страницы поиска и категорий с помощью параметра ?page=, поэтому вы последовательно обходите страницы, разбираете каждую и останавливаетесь, когда страница не возвращает карточек. Затем соедините получение и разбор в один запускаемый скрипт и запишите записи в JSON и CSV, чтобы их можно было загрузить в блокнот или таблицу.

python
import csv
import json
import time
from crawlbase import CrawlingAPI
from bs4 import BeautifulSoup

api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})
BASE = "https://www.audible.com"
FIELDS = ["title", "author", "narrator", "length", "rating", "price", "link"]

def crawl(page_url):
    options = {"ajax_wait": "true", "page_wait": 4000}
    response = api.get(page_url, options)
    if response["status_code"] == 200:
        return response["body"].decode("latin1")
    print(f"Request failed: {response['status_code']}")
    return None

def text_of(card, selector):
    el = card.select_one(selector)
    return el.get_text(strip=True) if el else None

def strip_label(value, label):
    if value and value.startswith(label):
        return value[len(label):].strip()
    return value

def parse_link(card):
    a = card.select_one("h3.bc-heading a[href]")
    if not a:
        return None
    href = a["href"].split("?")[0]
    return href if href.startswith("http") else BASE + href

def scrape_audiobooks(html):
    soup = BeautifulSoup(html, "html.parser")
    cards = soup.select("li.productListItem")
    results = []
    for card in cards:
        try:
            author = text_of(card, "li.authorLabel")
            narrator = text_of(card, "li.narratorLabel")
            results.append({
                "title": text_of(card, "h3.bc-heading a"),
                "author": strip_label(author, "By:"),
                "narrator": strip_label(narrator, "Narrated by:"),
                "length": strip_label(text_of(card, "li.runtimeLabel"), "Length:"),
                "rating": text_of(card, "li.ratingsLabel span.bc-text"),
                "price": text_of(card, "p.buybox-regular-price span.bc-text"),
                "link": parse_link(card),
            })
        except Exception as e:
            print(f"Skipped a card: {e}")
    return results

def build_library(search_url, max_pages=5):
    library = []
    for page in range(1, max_pages + 1):
        sep = "&" if "?" in search_url else "?"
        page_url = f"{search_url}{sep}page={page}"
        html = crawl(page_url)
        if not html:
            break
        found = scrape_audiobooks(html)
        if not found:
            break
        library.extend(found)
        print(f"Page {page}: {len(found)} audiobooks")
        time.sleep(2)
    return library

def export(rows, name="audible_library"):
    with open(f"{name}.json", "w", encoding="utf-8") as f:
        json.dump(rows, f, indent=2, ensure_ascii=False)
    with open(f"{name}.csv", "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=FIELDS)
        writer.writeheader()
        writer.writerows(rows)
    print(f"Saved {len(rows)} audiobooks to {name}.json and {name}.csv")

def main():
    url = "https://www.audible.com/search?keywords=science+fiction"
    library = build_library(url, max_pages=5)
    if library:
        export(library)

if __name__ == "__main__":
    main()

Запустите полный скрипт командой python audible_library.py. Он обходит до пяти страниц результатов, разбирает по одной строке на аудиокнигу и записывает как audible_library.json, так и audible_library.csv. Прерывание при пустых результатах останавливает вас раньше, когда в категории кончаются страницы, time.sleep(2) между запросами пейсит запуск, чтобы вас не заблокировали за быстрый трафик, а общий список FIELDS синхронизирует порядок столбцов CSV с ключами словаря, чтобы два экспорта никогда не расходились.

Как выглядит вывод

Вы получаете чистый список записей аудиокниг в порядке листинга, готовый для записи в JSON, CSV или базу данных. Это ваша мини-библиотека.

json
[
  {
    "title": "Project Hail Mary",
    "author": "Andy Weir",
    "narrator": "Ray Porter",
    "length": "16 hrs and 10 mins",
    "rating": "4.9 out of 5 stars",
    "price": "$24.49",
    "link": "https://www.audible.com/pd/Project-Hail-Mary-Audiobook/B08G9PRS1K"
  },
  {
    "title": "Dune",
    "author": "Frank Herbert",
    "narrator": "Scott Brick, Orlagh Cassidy, Euan Morton",
    "length": "21 hrs and 2 mins",
    "rating": "4.6 out of 5 stars",
    "price": "$29.65",
    "link": "https://www.audible.com/pd/Dune-Audiobook/B002V1OF70"
  }
]

Отсюда мини-библиотека в вашем распоряжении. Загрузите CSV в таблицу для сортировки по продолжительности или рейтингу, отфильтруйте JSON по наименованиям ниже ценового порога или передайте набор в список рекомендаций. Поскольку каждая запись содержит ссылку на страницу сведений, вы можете вернуться позже и спарсить страницу отдельного наименования для получения полного описания или информации об издателе, когда вам понадобится больше, чем поля листинга.

Масштабирование по категориям

Один поиск, это отправная точка; более полная библиотека охватывает несколько категорий. Audible раскрывает страницу результатов для каждого узла категории и каждого поиска по ключевым словам, каждая по своему URL, поэтому можно вести карту имён в URL и запускать одну и ту же процедуру build_library для каждой, ключуя вывод по категории. Пейсите запросы с задержкой, уже встроенной в цикл, и ограничивайте max_pages, чтобы широкий запуск не разбух. Для отслеживания тенденций цен и рейтингов со временем запускайте задание по расписанию, ставьте метку даты для каждого экспорта и сравнивайте последовательные снимки, чтобы видеть, что изменилось. Тот же подход обеспечивает любой проект парсинга электронной коммерции, отслеживающий каталог со временем.

Сохранение незаблокированности

Даже при обработанном рендеринге Audible следит за трафиком, похожим на парсер. Несколько привычек поддерживают работоспособность запуска, и они применяются к любой сложной коммерческой цели.

  • Пейсите запросы. Распределяйте запросы с задержкой между страницами и категориями, а не обходите всё на полной скорости. Запускайте более интенсивные задания в непиковые часы, чтобы снизить нагрузку на серверы Audible.
  • Полагайтесь на ротацию. Пул жилых IP распределяет запросы по многим реальным адресам пользователей, чтобы ни один из них не превысил ограничение частоты. Crawling API обрабатывает это за вас; если вы строите собственный стек, именно эту часть нужно реализовать правильно.
  • Храните только то, что нужно. Сохраняйте поля каталога, используемые вашим проектом, и отбрасывайте остальное. Периодически проверяйте селекторы, чтобы парсер успевал за изменениями разметки.

Полный свод правил по предотвращению блокировок см. в статье как парсить сайты без блокировок. Если вы хотите углубиться в сторону разбора, руководство по использованию BeautifulSoup в Python подробно охватывает библиотеку, а для связанной цели каталога пошаговое руководство по парсингу рейтингов и комментариев Goodreads хорошо дополняет набор аудиокниг.

Законно ли парсить Audible?

Допустимость парсинга Audible зависит от условий использования Audible и Amazon, вашей юрисдикции и того, что вы делаете с данными. Эти условия ограничивают автоматизированный доступ, поэтому парсинг может им противоречить независимо от того, насколько аккуратен ваш инструментарий. Ни один из кодов здесь это не меняет; он лишь обеспечивает техническую работу. Прочитайте условия использования Audible и его robots.txt и воспринимайте оба документа как границу того, что вы собираете. Для коммерческого или конкурентного использования правовая картина усложняется, и консультация с юридическим экспертом относительно вашего конкретного случая является разумным шагом.

Несколько строк, которых стоит придерживаться. Собирайте только публичные данные каталога: названия, авторов, чтецов, продолжительность, рейтинги, цены и ссылки листинга, которые любой может видеть на странице результатов без аккаунта. Это руководство никогда не касается самих аудиофайлов, которые являются защищённым авторским правом контентом, которые вы не вправе скачивать или распространять, и не затрагивает ничего за логином, данные аккаунта или покупок и персональную информацию об идентифицируемых слушателях или рецензентах. Держите объём запросов достаточно низким, чтобы не нагружать серверы Audible, и если вы планируете повторно использовать данные коммерческим образом, получите разрешение или официальное соглашение, а не предполагайте, что молчание означает согласие.

Это руководство намеренно ограничено публичными страницами поиска и категорий, потому что именно это делает работу обоснованной. Для лицензионного или массового доступа Amazon предлагает Product Advertising API и другие официальные программы, и это правильный инструмент, когда вам нужны большие объёмы, гарантированная структура или коммерческие права. Если вашему проекту нужно больше, чем публичные метаданные каталога, официальный API или соглашение о данных, правильный путь, а не более хитрый парсер, и это всегда лучший выбор, когда такой вариант существует.

Итоги

Ключевые выводы

  • Каталог Audible, богатые публичные метаданные. На каждой странице результатов указаны название, автор, чтец, продолжительность, рейтинг и цена, что и делает его таким полезным для составления списка для чтения или изучения рынка аудиокниг.
  • Вам нужны рендеринг и доверенный IP вместе. Audible заполняет сетку товаров на стороне клиента и блокирует трафик ботов, поэтому Crawling API рендерит страницу за жилым IP за один вызов.
  • BeautifulSoup выполняет извлечение. Перебирайте карточки li.productListItem и сопоставляйте название, автора, чтеца, продолжительность, рейтинг, цену и ссылку с текущими селекторами, и ожидайте, что эти селекторы будут меняться.
  • Пагинация строит библиотеку. Обходите страницы с ?page= до тех пор, пока одна не вернёт пустые карточки, затем экспортируйте в JSON и CSV с общим списком полей, чтобы два файла были синхронизированы.
  • Работайте только с публичными метаданными. Уважайте условия использования и robots.txt Audible, никогда не трогайте защищённые авторским правом аудиофайлы или что-либо за логином, и используйте официальный API Amazon для лицензионных или массовых данных.

Часто задаваемые вопросы

Почему простой запрос не возвращает аудиокниги из Audible?

По двум причинам. Audible заполняет большую часть сетки товаров на стороне клиента по мере загрузки страницы, поэтому сырой запрос нередко получает оболочку без продолжительности, рейтингов и цен. Кроме того, как продукт Amazon, Audible бросает вызов или блокирует трафик, непохожий на настоящий браузер. Рендеринг страницы через Crawling API за доверенным IP решает обе проблемы, именно поэтому парсер здесь маршрутизирует запрос через него.

Какие поля можно спарсить из листинга Audible?

Из карточки результатов поиска или категории вы можете получить название, автора, чтеца, общую продолжительность, средний рейтинг, цену и ссылку на страницу сведений аудиокниги. Это публичные поля листинга. Если вам нужно полное описание, издатель или дата выхода, перейдите по ссылке каждой карточки и спарсите отдельную страницу сведений, которая раскрывает больше метаданных.

Как парсить конкретную категорию Audible?

Каждая категория и каждый поиск имеют свой URL, например /search?keywords=science+fiction для поиска по ключевому слову или /search?node=... для узла категории. Направьте парсер на нужный URL. Чтобы охватить множество категорий, ведите карту имён в URL и перебирайте её, пейся запросы с небольшой задержкой.

Как работает пагинация на Audible?

Audible добавляет параметр ?page= (или &page=, когда URL уже содержит строку запроса) для обхода страниц результатов. Скрипт увеличивает номер страницы, разбирает каждую и останавливается, когда страница не возвращает карточек товаров, что является сигналом о том, что вы достигли конца категории.

Можно ли скачивать аудиокниги?

Нет, и не стоит пытаться. Аудиофайлы, это защищённый авторским правом контент, привязанный к аккаунтам и покупкам Audible, и это руководство намеренно их избегает. Оно собирает только публичные метаданные каталога: названия, авторов, чтецов, продолжительность, рейтинги и цены, отображаемые на страницах листинга, но не аудио.

Как избежать блокировок при парсинге Audible?

Держите низкую частоту запросов на IP, добавляйте задержку между страницами и категориями и маршрутизируйте через ротирующие жилые IP, чтобы ни один адрес не превысил ограничение частоты. Crawling API управляет ротацией, пулом доверенных IP и обработкой CAPTCHA за вас; если вы строите собственный стек, именно в это стоит вложиться. Следите за кодами статуса и отступайте, когда начинаете видеть вызовы.

Начать создавать

Обходите любой сайт в масштабе, без борьбы с инфраструктурой.

Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.

Самообслуживание · Звонок отдела продаж не требуется · Доступны корпоративные объёмы краулинга