Wikipedia является крупнейшим справочным изданием из когда-либо созданных, и практически все её статьи имеют одинаковую структуру: заголовок, вводное резюме, раздел с подзаголовками, инфоблок с ключевыми фактами и произвольное количество таблиц с данными. Такая регулярность делает её одним из наиболее полезных общедоступных источников в сети для исследований, обогащения контента, построения графов знаний и обучающих датасетов. В этом руководстве показано, как парсить Wikipedia с помощью Python чисто и воспроизводимым способом.

Всё здесь ограничено публичным энциклопедическим контентом: заголовками статей, вводными резюме, подзаголовками разделов, полями инфоблоков и таблицами, которые любой может прочитать без входа в систему. Мы создадим небольшой скрапер, который получает отрендеренную страницу статьи через Crawling API, разбирает эти поля с помощью BeautifulSoup и экспортирует результаты в JSON и CSV. Текст Wikipedia свободно лицензирован по CC-BY-SA, поэтому прежде чем применять это в реальных задачах, прочитайте раздел об атрибуции и законности в конце, а также рассмотрите официальный MediaWiki API, который является санкционированным путём для большинства проектов.

Что вы создадите

Скрипт на Python, который принимает URL статьи Wikipedia, получает страницу через Crawling API и разбирает несколько структурированных полей:

  • Заголовок статьи заголовок страницы из элемента firstHeading.
  • Краткое описание вводные абзацы, открывающие статью.
  • Подзаголовки разделов теги h2 и h3, формирующие структуру статьи.
  • Поля инфоблока пары метка-значение из бокового инфоблока (дата рождения, гражданство, профессия и т.д.).
  • Таблицы таблицы данных wikitable, разобранные по строкам для записи в CSV.

Каждое поле соответствует стабильному CSS-классу или идентификатору элемента Wikipedia, поэтому скрапер работает на большинстве страниц статей, а не только на одной.

Зачем парсить через Crawling API

Страница статьи Wikipedia преимущественно состоит из HTML, отрендеренного на сервере, поэтому обычный запрос нередко возвращает пригодную разметку. Сложности возникают при масштабировании. Wikimedia требует от автоматических клиентов идентифицировать себя, строго соблюдает ограничения на частоту запросов и замедляет или блокирует трафик, который усиленно обращается к серверам с одного адреса. Если вы запускаете плотный цикл с одного IP датацентра, вы быстро достигнете этих лимитов, а блокировка IP остановит всю задачу.

Маршрутизация запросов через Crawling API решает операционную сторону вопроса. Вы отправляете ему URL статьи, он получает страницу через ротирующий пул доверенных IP, обрабатывает повторные попытки и возвращает готовый HTML для разбора. Это не позволяет ни одному адресу превысить ограничение на частоту запросов, и вам не нужно самостоятельно поддерживать пул прокси. Описанный ниже подход к разбору аналогичен тому, который вы бы использовали с любым другим HTML-источником, поэтому если он вам незнаком, наше руководство по использованию BeautifulSoup в Python подробно охватывает сторону извлечения данных.

Используйте официальный API там, где это возможно

Wikipedia предоставляет MediaWiki API и публикует полные дампы базы данных. Для крупных структурированных выгрузок они являются предпочтительным путём, и мы рекомендуем их в разделе о законности. В этом руководстве рассматривается HTML-парсинг, поскольку это наиболее прямой способ читать именно то, что видит читатель на отдельной странице, и техники применимы к любому сайту.

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

Несколько вещей, которые нужно иметь под рукой. На это не уйдёт много времени.

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

Python версии 3.8 или выше. Проверьте с помощью python --version. Если не установлен, загрузите с python.org.

Аккаунт Crawlbase и токен. Зарегистрируйтесь, откройте панель управления и скопируйте токен со страницы документации аккаунта. Wikipedia представляет собой статический HTML, поэтому здесь подходит токен обычного запроса; JavaScript-рендеринг не нужен. Не храните токен в системе контроля версий.

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

Создайте изолированное виртуальное окружение, затем установите три библиотеки, необходимые скраперу.

bash
python --version

python -m venv wikipedia_env
source wikipedia_env/bin/activate

pip install crawlbase beautifulsoup4 pandas

В Windows активируйте окружение командой wikipedia_env\Scripts\activate вместо строки с source. Три зависимости выполняют основную работу: crawlbase является официальным клиентом для Crawling API, beautifulsoup4 разбирает возвращаемый HTML, а pandas преобразует инфоблок и таблицы в фреймы данных, которые можно записать в CSV.

Шаг 1: Получение HTML статьи

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

python
from crawlbase import CrawlingAPI

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

def crawl(page_url):
    response = api.get(page_url)
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

if __name__ == "__main__":
    page_url = "https://en.wikipedia.org/wiki/Ada_Lovelace"
    html = crawl(page_url)
    print(html[:500] if html else "No HTML returned")

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

Crawlbase Crawling API

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

Шаг 2: Разбор заголовка и краткого описания

Имея HTML, загрузите его в BeautifulSoup. Wikipedia присваивает заголовку страницы идентификатор firstHeading, а краткое описание представляет собой серию абзацев внутри основного контента до первого подзаголовка раздела. Мы получаем заголовок из этого идентификатора, затем собираем вводные абзацы в качестве краткого описания.

python
from bs4 import BeautifulSoup

def parse_title_and_summary(html):
    soup = BeautifulSoup(html, "html.parser")

    title = soup.find("h1", id="firstHeading").get_text(strip=True)

    content = soup.find("div", class_="mw-parser-output")
    summary = []
    for p in content.find_all("p", recursive=False):
        text = p.get_text(strip=True)
        if text:
            summary.append(text)
        if len(summary) >= 3:
            break

    return title, " ".join(summary)

Вызов find('h1', id='firstHeading') точно нацеливается на заголовок страницы, используя тот же селектор, который вы найдёте при инспектировании страницы в браузерных инструментах разработчика. Для краткого описания мы перебираем прямые дочерние абзацы элемента mw-parser-output, обёртки тела статьи, и берём первые непустые из них. Ограничение тремя абзацами позволяет получить вводное введение без загрузки всей статьи в одну строку.

Шаг 3: Сбор подзаголовков разделов

Wikipedia структурирует каждую статью с помощью единообразной иерархии заголовков. На отрендеренной странице текст заголовка раздела находится внутри элементов с классом mw-headline, вложенных в теги h2 и h3. Сбор этих элементов даёт оглавление в порядке документа.

python
def parse_sections(soup):
    sections = []
    for tag in soup.find_all(["h2", "h3"]):
        headline = tag.find("span", class_="mw-headline")
        if headline:
            sections.append({
                "level": tag.name,
                "heading": headline.get_text(strip=True),
            })
    return sections

Мы записываем только заголовки, содержащие span с mw-headline, что отфильтровывает несвязанные теги h2 и h3 в обёртке страницы и оставляет только настоящие разделы статьи. Запись уровня позволяет восстановить иерархию позднее: h2 для разделов верхнего уровня, h3 для подразделов.

Шаг 4: Извлечение полей инфоблока

Инфоблок представляет собой боковую сводку ключевых фактов во многих статьях. Wikipedia помечает его классом infobox, и каждый факт является строкой таблицы, сопоставляющей ячейку-метку (infobox-label) с ячейкой данных (infobox-data). Перебор этих строк превращает инфоблок в чистый словарь полей.

python
def parse_infobox(soup):
    infobox = soup.find("table", class_="infobox")
    if not infobox:
        return {}

    fields = {}
    for row in infobox.find_all("tr"):
        label = row.find("th", class_="infobox-label")
        data = row.find("td", class_="infobox-data")
        if label and data:
            key = label.get_text(strip=True)
            value = data.get_text(" ", strip=True)
            fields[key] = value

    image = infobox.select_one(".infobox-image img")
    if image and image.has_attr("src"):
        fields["image"] = "https:" + image["src"]

    return fields

Каждая пара infobox-label и infobox-data становится одной записью ключ-значение, поэтому инфоблок персоны даёт поля «Born», «Died», «Resting place», «Citizenship» и «Occupation» без необходимости указывать их имена заранее. Вызов get_text(" ", strip=True) объединяет многострочные значения через пробел, что сохраняет читаемость списков, например, нескольких гражданств. Мы также получаем изображение из .infobox-image img и добавляем https:, поскольку Wikipedia использует относительные протоколу URL изображений.

Шаг 5: Разбор таблиц данных

Таблицы в статьях используют класс wikitable. Pandas умеет читать HTML-таблицы напрямую, поэтому наиболее чистый подход, передать HTML каждой таблицы в pandas.read_html и получить DataFrame. Это даёт строки и столбцы, готовые для CSV, с минимальным перебором ячеек. Если вам нужна общая техника за пределами Wikipedia, смотрите наше руководство по парсингу таблиц с веб-сайтов.

python
import pandas as pd
from io import StringIO

def parse_tables(soup):
    tables = []
    for node in soup.find_all("table", class_="wikitable"):
        try:
            df = pd.read_html(StringIO(str(node)))[0]
            tables.append(df)
        except ValueError:
            continue
    return tables

Мы перебираем каждую таблицу wikitable, передаём её HTML в read_html и сохраняем первый возвращаемый DataFrame для каждой. Обёртка вызова в блок try позволяет пропустить некорректную таблицу без прерывания работы. Результатом является список DataFrame-ов, по одному на таблицу, которые можно записать в отдельные CSV-файлы или объединить по мере необходимости. Для очистки этих фреймов перед последующим использованием наше руководство по структурированию и очистке спарсенных веб-данных для AI и ML охватывает основные шаги.

Шаг 6: Сборка и экспорт

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

python
import json
from io import StringIO
import pandas as pd
from bs4 import BeautifulSoup
from crawlbase import CrawlingAPI

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

def crawl(page_url):
    response = api.get(page_url)
    if response["status_code"] == 200:
        return response["body"].decode("utf-8")
    print(f"Request failed: {response['status_code']}")
    return None

def scrape_article(html):
    soup = BeautifulSoup(html, "html.parser")

    title = soup.find("h1", id="firstHeading").get_text(strip=True)

    content = soup.find("div", class_="mw-parser-output")
    summary = []
    for p in content.find_all("p", recursive=False):
        text = p.get_text(strip=True)
        if text:
            summary.append(text)
        if len(summary) >= 3:
            break

    sections = []
    for tag in soup.find_all(["h2", "h3"]):
        headline = tag.find("span", class_="mw-headline")
        if headline:
            sections.append(headline.get_text(strip=True))

    infobox = {}
    box = soup.find("table", class_="infobox")
    if box:
        for row in box.find_all("tr"):
            label = row.find("th", class_="infobox-label")
            data = row.find("td", class_="infobox-data")
            if label and data:
                infobox[label.get_text(strip=True)] = data.get_text(" ", strip=True)

    tables = []
    for node in soup.find_all("table", class_="wikitable"):
        try:
            tables.append(pd.read_html(StringIO(str(node)))[0])
        except ValueError:
            continue

    return {
        "title": title,
        "summary": " ".join(summary),
        "sections": sections,
        "infobox": infobox,
    }, tables

def main():
    page_url = "https://en.wikipedia.org/wiki/Ada_Lovelace"
    html = crawl(page_url)
    if not html:
        return

    article, tables = scrape_article(html)
    article["source_url"] = page_url
    article["license"] = "CC BY-SA 4.0"

    with open("wikipedia.json", "w", encoding="utf-8") as f:
        json.dump(article, f, indent=2, ensure_ascii=False)

    for i, df in enumerate(tables):
        df.to_csv(f"wikipedia_table_{i}.csv", index=False)

    print(json.dumps(article, indent=2, ensure_ascii=False))
    print(f"Saved {len(tables)} table(s) to CSV")

if __name__ == "__main__":
    main()

Скрипт записывает заголовок, краткое описание, разделы и инфоблок в wikipedia.json, а каждую таблицу wikitable в отдельный пронумерованный CSV-файл. Обратите внимание на два дополнительных поля, которые мы добавляем перед сохранением: source_url и license. Запись источника данных и лицензии CC-BY-SA является не формальностью, а обязательным условием соблюдения требования об атрибуции, которое рассматривается в разделе о законности ниже.

Как выглядит результат

Запустите полный скрипт, и JSON-файл будет содержать чистую структурированную запись статьи.

json
{
  "title": "Ada Lovelace",
  "summary": "Augusta Ada King, Countess of Lovelace, was an English mathematician and writer...",
  "sections": [
    "Biography",
    "Work",
    "Commemoration",
    "In popular culture"
  ],
  "infobox": {
    "Born": "Augusta Ada Byron 10 December 1815 London, England",
    "Died": "27 November 1852 (aged 36) Marylebone, London, England",
    "Occupation": "Mathematician"
  },
  "source_url": "https://en.wikipedia.org/wiki/Ada_Lovelace",
  "license": "CC BY-SA 4.0"
}

Вдобавок вы получаете по одному CSV-файлу на таблицу с названиями wikipedia_table_0.csv, wikipedia_table_1.csv и т.д., каждый со строкой заголовка и строками данных, которые разобрал pandas. Отсюда JSON поступает в базу знаний или контентный конвейер, а CSV-файлы сразу открываются в таблицах или загружаются в базу данных.

Масштабирование на множество статей

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

python
import time

urls = [
    "https://en.wikipedia.org/wiki/Ada_Lovelace",
    "https://en.wikipedia.org/wiki/Alan_Turing",
    "https://en.wikipedia.org/wiki/Grace_Hopper",
]

dataset = []
for url in urls:
    html = crawl(url)
    if html:
        article, _ = scrape_article(html)
        article["source_url"] = url
        dataset.append(article)
    time.sleep(2)

print(f"Collected {len(dataset)} articles")

time.sleep(2) между запросами является важнейшей привычкой при работе с Wikipedia в любом объёме. Задавайте темп работы, ограничивайте размер пакетов и останавливайтесь, получив нужную выборку. Однако для крупных структурированных выгрузок MediaWiki API и дампы базы данных действительно быстрее и менее нагружают серверы Wikimedia, и мы рекомендуем их далее.

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

Wikipedia является одним из наиболее разрешительных крупных сайтов для работы, поскольку её текстовый контент свободно лицензирован под Creative Commons Attribution-ShareAlike (CC-BY-SA). Это означает, что вы можете повторно использовать и даже распространять текст статей, в том числе в коммерческих проектах, при двух условиях: вы указываете источник (ссылаетесь на Wikipedia и авторов, как правило, ссылкой на статью) и распространяете любые производные работы под той же лицензией. Некоторые встроенные медиафайлы, например определённые изображения, имеют собственные отдельные лицензии, поэтому перед повторным использованием изображения проверяйте его страницу. Поля license и source_url, которые записывает скрипт, существуют именно для того, чтобы вы могли выполнить требование об атрибуции в дальнейшем.

Разрешительная лицензия не является лицензией игнорировать серверы. Условия использования Wikimedia требуют от автоматических клиентов соблюдать ограничения на частоту запросов, идентифицировать себя и не ухудшать работу сервиса для читателей-людей. Интенсивный обход сайта в плотном цикле является одновременно невежливым поведением и, вероятно, приведёт к блокировке вашего IP. Поддерживайте умеренный объём, задавайте темп запросов, как показано выше, и читайте robots.txt сайта. Данное руководство ограничено исключительно публичным энциклопедическим контентом; здесь не затрагиваются страницы аккаунтов пользователей, история правок, связанная с конкретными людьми, или что-либо за аутентификацией.

Для работы с более чем несколькими страницами санкционированным путём является официальный инструментарий. MediaWiki API возвращает структурированный контент статей, включая разобранные разделы и данные инфоблока, без скрапинга отрендеренного HTML, а Wikimedia также публикует полные дампы базы данных всей энциклопедии для массового использования. Оба варианта быстрее, стабильнее и значительно меньше нагружают инфраструктуру Wikimedia, чем HTML-скрапинг в масштабе. Используйте HTML-скрапинг, когда вам нужно именно то, что видит читатель на одной конкретной странице; используйте API или дампы, когда вам нужен объём.

Итоги

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

  • Wikipedia имеет высокоструктурированный формат. Заголовок (firstHeading), краткое описание, разделы mw-headline, infobox и таблицы wikitable соответствуют стабильным селекторам, работающим в большинстве статей.
  • Маршрутизируйте через Crawling API, чтобы оставаться незаблокированным. Ротация доверенных IP и встроенные повторные попытки не дают ни одному адресу превысить ограничения Wikimedia, без необходимости поддерживать собственный пул прокси.
  • Доверьте таблицы pandas. Передача каждой таблицы wikitable в pandas.read_html превращает её в DataFrame, который сразу экспортируется в CSV.
  • Указывайте источник. Текст Wikipedia лицензирован по CC-BY-SA, поэтому записывайте URL источника и лицензию и ссылайтесь на Wikipedia при любом повторном использовании; проверяйте медиафайлы на наличие собственных лицензий.
  • Предпочитайте официальный путь при масштабировании. MediaWiki API и дампы базы данных являются санкционированным, более лёгким способом получения структурированных данных Wikipedia в объёме.

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

Нужен ли мне JavaScript-токен для парсинга Wikipedia?

Нет. Страницы статей Wikipedia представляют собой статический HTML, отрендеренный на сервере, поэтому достаточно обычного токена запроса. JavaScript-токен предназначен для сайтов с клиентским рендерингом, которые формируют контент в браузере, что не относится к Wikipedia. Использование обычного токена делает каждый запрос легче и избавляет от лишнего шага рендеринга.

Как надёжно извлечь поля инфоблока?

Найдите элемент table.infobox, затем перебирайте его строки, сопоставляя каждую ячейку th.infobox-label с ячейкой td.infobox-data. Такая структура метка-значение единообразна во всех статьях, поэтому одинаковый цикл превращает инфоблок персоны, страны или фильма в чистый словарь без предварительного указания имён полей.

Можно ли парсить таблицы Wikipedia в CSV?

Да. Выберите каждую таблицу table.wikitable, передайте HTML каждой в pandas.read_html и получите DataFrame на таблицу, который вы записываете через to_csv. Обёртка вызова в блок try позволяет пропустить некорректную таблицу вместо прерывания работы.

Законно ли коммерческое использование спарсенного контента Wikipedia?

Текст Wikipedia лицензирован по CC-BY-SA, что разрешает коммерческое повторное использование при условии атрибуции Wikipedia и авторов, а также распространения производных работ под той же лицензией. Встроенные медиафайлы могут иметь собственные лицензии, поэтому проверяйте каждый файл перед повторным использованием изображений. Записывайте URL источника и лицензию вместе с данными, чтобы атрибуция была удобной в дальнейшем.

Стоит ли использовать MediaWiki API вместо парсинга?

Для работы в объёме, да. MediaWiki API возвращает структурированный контент статей напрямую, а Wikimedia публикует полные дампы базы данных для массового использования. Оба варианта быстрее и значительно меньше нагружают серверы Wikipedia, чем HTML-скрапинг. HTML-скрапинг является правильным инструментом, когда вам нужно именно то, что видит читатель на конкретной странице; API и дампы лучше подходят для построения больших датасетов.

Как не попасть под блокировку при парсинге Wikipedia?

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

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

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

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

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