Wikipedia хранит значительную часть своих наиболее полезных данных внутри таблиц: списки стран по площади, данные о населении, спортивные рейтинги, исторические хронологии и тысячи других сортируемых сеток. Эти табличные данные публичны и хорошо структурированы, что делает их идеальным материалом для исследований и анализа, однако копировать их ячейку за ячейкой в таблицу не получится уже на второй-третьей таблице.
В этом руководстве показано, как скрапить таблицы Wikipedia с помощью Python правильным способом. Вы создаёте небольшой запускаемый скрипт, который получает статью через Crawling API, находит нужную таблицу, разбирает её прямо в DataFrame pandas, очищает и экспортирует в аккуратный CSV. Руководство ограничивается публичными табличными данными, а раздел о законности ближе к концу охватывает лицензию CC-BY-SA Wikipedia и официальные массовые пути, поэтому ознакомьтесь с ним перед тем, как направить это на множество статей. Данная статья посвящена именно таблицам; для получения заголовков страниц, изображений и полей информационной таблицы смотрите сопутствующее руководство как скрапить Wikipedia.
Что вы создадите
Python-скрипт, который принимает URL публичной статьи Wikipedia, получает отрисованный HTML через Crawling API, выбирает конкретную таблицу по её CSS-классу, считывает её в DataFrame pandas, очищает столбцы и записывает результат в CSV. Рабочим примером служит статья «Список стран и зависимых территорий по площади». Выходная запись содержит следующие поля для каждой строки:
- Rank порядковый номер строки в исходной таблице, если присутствует.
- Country / dependency название, как оно отображается в ячейке таблицы.
- Total area показатель площади в квадратных километрах и милях.
- Land area площадь суши, если таблица её выделяет.
- Water area водная площадь и её доля от общей.
- Notes любой столбец со сносками или аннотациями, который содержит таблица.
Понимание структуры таблиц Wikipedia
Таблицы Wikipedia написаны в смеси HTML и вики-текста, однако к тому моменту, когда страница поступает к вашему скраперу, они уже отрисованы в обычные элементы <table>, <tr>, <th> и <td> с заголовочными строками и ячейками данных.
Наиболее важная деталь для скрапинга это CSS-класс. Большинство таблиц с данными несут класс wikitable, который применяет стандартный обрамлённый стиль, знакомый по всем статьям. Этот общий класс служит вашим якорем: он позволяет выбирать таблицы с данными и пропускать таблицы макета или навигации на той же странице, а сортируемые таблицы добавляют класс sortable как дополнительный признак чистых столбчатых данных. Статья нередко содержит несколько таблиц, поэтому обычно приходится уточнять выбор по классу, тексту подписи или по индексу, когда вы знаете нужную.
Почему простой запрос может оказаться недостаточным
Для одной статьи голый HTTP-запрос возвращает пригодный HTML, поскольку Wikipedia выдаёт содержимое статей на стороне сервера. Трудности возникают при масштабировании: если получить десятки или сотни статей в плотном цикле с одного датацентрового IP, вы ничем не будете напоминать обычного читателя, а именно такой паттерн трафика и создан для замедления ограничениями скорости и защитой от ботов. Вы также можете столкнуться с временными блокировками или неполными ответами, которые тихо нарушают работу без надзора.
Маршрутизация запросов через Crawling API сглаживает оба аспекта. Он получает каждую страницу за счёт ротирующего пула доверенных IP, так что более крупный обход распределяется по множеству адресов вместо нагрузки на один, и возвращает готовый HTML для передачи прямо в парсер. Для общего обзора смотрите как скрапить сайты без блокировок.
Требования
Перед написанием кода необходимо подготовить несколько вещей. Ни одна из них не займёт много времени.
Базовые знания Python. Вы должны уметь писать и запускать Python-скрипт и устанавливать пакеты через pip. Если вы только начинаете работу с парсингом, руководство по BeautifulSoup хорошо дополняет этот материал.
Python 3.8 или новее. Проверьте версию командой python --version. Если её нет, установите с python.org или через дистрибутив вроде Anaconda и убедитесь, что Python есть в PATH.
Аккаунт и токен Crawlbase. Зарегистрируйтесь, откройте панель управления и скопируйте обычный токен со страницы документации аккаунта. Crawlbase включает до 20 000 бесплатных запросов на старте, чего вполне достаточно для прохождения этого руководства. Относитесь к токену как к паролю: он аутентифицирует ваши запросы, поэтому не включайте его в систему контроля версий.
Настройка проекта
Создайте виртуальное окружение для изоляции зависимостей проекта, затем установите необходимые библиотеки.
python --version python -m venv wiki_env source wiki_env/bin/activate pip install crawlbase beautifulsoup4 pandas lxml
На Windows активируйте окружение командой wiki_env\Scripts\activate вместо строки с source. Четыре зависимости выполняют основную работу: crawlbase является официальным клиентом для Crawling API, beautifulsoup4 изолирует нужную таблицу, pandas считывает её в DataFrame и экспортирует CSV, а lxml является быстрым HTML-парсером, который pandas использует под капотом для read_html. Модуль csv входит в стандартную библиотеку, поэтому для шага экспорта ничего дополнительно устанавливать не нужно.
Шаг 1: Получение отрисованной статьи Wikipedia
Начните с получения HTML статьи. Импортируйте класс CrawlingAPI, инициализируйте его с вашим токеном, запросите URL статьи и проверьте статус ответа перед парсингом. Проверка status_code Crawlbase первым делом делает сбои явными, а не скрытыми.
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__": article_url = "https://en.wikipedia.org/wiki/List_of_countries_and_dependencies_by_area" html = crawl(article_url) print(html[:500] if html else "No HTML returned")
Запустите скрипт командой python wikipedia_scraper.py, и вы должны увидеть реальную разметку статьи в первых 500 символах: это подтверждает, что загрузка работает ещё до написания единого селектора. Функция crawl возвращает декодированный HTML при статусе 200 и None в остальных случаях, так что остальной скрипт может проверять на ложное возвращаемое значение вместо аварийного завершения при плохом ответе.
Вспомогательная функция crawl выше упрощает ваш код: один вызов возвращает готовый HTML для любой статьи. За этим вызовом Crawling API ротирует доверенные IP и обрабатывает блокировки за вас, поэтому при масштабировании от одной статьи до сотен таблиц вам не нужно самостоятельно создавать и обслуживать пул прокси. Направьте его на публичную статью с бесплатного уровня.
Шаг 2: Поиск нужной таблицы
Статья обычно содержит несколько таблиц, поэтому следующий шаг это выбор нужной. Загрузите HTML в BeautifulSoup и используйте select_one с классом wikitable, чтобы захватить первую таблицу с данными. Когда страница содержит много wikitable, переключитесь на select и индексируйте нужную, или отфильтруйте по тексту подписи таблицы.
from bs4 import BeautifulSoup def find_table(html, index=0): soup = BeautifulSoup(html, "html.parser") tables = soup.select("table.wikitable") if not tables: print("No wikitable found on this page.") return None print(f"Found {len(tables)} wikitable(s); using index {index}.") return tables[index]
Вспомогательная функция find_table возвращает один отрисованный элемент <table> или None с понятным сообщением, если на странице нет wikitable. Аргумент index позволяет нацелиться на вторую или третью таблицу данных в более насыщенных статьях без переписывания селектора. Вывод количества таблиц это небольшая деталь, которая с первого же запуска сообщает вам, нацелены ли вы на ожидаемую таблицу.
Можно передать всю страницу в pandas.read_html и получить обратно список всех таблиц, но это смешает таблицы данных с боковыми панелями и навигационными блоками, оставив вас угадывать индексы. Предварительный выбор одной нужной wikitable с помощью BeautifulSoup с последующим разбором только этого элемента даёт единственный предсказуемый DataFrame каждый раз.
Шаг 3: Разбор таблицы в DataFrame
Имея элемент таблицы, pandas выполняет основную работу. Передайте HTML таблицы в pandas.read_html, который возвращает список DataFrame; поскольку вы изолировали единственную таблицу, берите первый элемент. Это ядро скрапинга таблиц: одна функция превращает отрисованные HTML-строки и ячейки в типизированный столбчатый DataFrame.
import pandas as pd from io import StringIO def table_to_df(table): frames = pd.read_html(StringIO(str(table))) if not frames: return None df = frames[0] print(f"Parsed table with {df.shape[0]} rows and {df.shape[1]} columns.") return df
Обёртка str(table) в StringIO соответствует тому, как текущий pandas ожидает получать HTML в read_html, и избавляет функцию от предупреждений об устаревшем использовании. Вывод размерности служит проверкой здравого смысла: если количество строк и столбцов совпадает с тем, что вы видите в статье, разбор попал на правильную таблицу. Если вы предпочитаете обходить строки самостоятельно, можно пройтись в цикле по table.select("tr") с BeautifulSoup и вручную считывать каждую ячейку th и td, но read_html быстрее и автоматически определяет заголовки.
Шаг 4: Очистка DataFrame
Сырые таблицы Wikipedia имеют особенности: многоуровневые заголовки столбцов, маркеры сносок в ячейках, пустые столбцы и артефакты объединённых ячеек. Короткий шаг очистки превращает разобранный фрейм в нечто готовое к анализу перед экспортом.
def clean_df(df): # Flatten multi-level headers into single strings. if isinstance(df.columns, pd.MultiIndex): df.columns = [" ".join(str(p) for p in col if "Unnamed" not in str(p)).strip() for col in df.columns] # Strip footnote markers like [1] and [a] from string cells. df = df.replace(r"\[.*?\]", "", regex=True) # Drop fully empty rows and columns. df = df.dropna(axis=0, how="all").dropna(axis=1, how="all") # Trim surrounding whitespace on string cells. for col in df.select_dtypes(include="object").columns: df[col] = df[col].astype(str).str.strip() return df.reset_index(drop=True)
Каждый шаг направлен против реальной проблемы. Сплющивание MultiIndex превращает вложенные строки заголовков в единые читаемые имена столбцов и убирает заполнители Unnamed, которые pandas вставляет для пустых ячеек заголовка. Замена по регулярному выражению удаляет заключённые в скобки маркеры сносок, которые Wikipedia рассыпает по ячейкам, например [1] или [a], иначе они загрязняют числовые столбцы. Удаление полностью пустых строк и столбцов очищает артефакты объединённых ячеек, а финальный обрез убирает лишние пробелы. Адаптируйте шаги к конкретной таблице; не каждая таблица требует каждого прохода.
Шаг 5: Сборка полного скрипта
Теперь соедините части в один запускаемый скрипт: получите статью, изолируйте таблицу, разберите её, очистите и экспортируйте в CSV.
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 find_table(html, index=0): soup = BeautifulSoup(html, "html.parser") tables = soup.select("table.wikitable") if not tables: return None return tables[index] def table_to_df(table): frames = pd.read_html(StringIO(str(table))) return frames[0] if frames else None def clean_df(df): if isinstance(df.columns, pd.MultiIndex): df.columns = [" ".join(str(p) for p in col if "Unnamed" not in str(p)).strip() for col in df.columns] df = df.replace(r"\[.*?\]", "", regex=True) df = df.dropna(axis=0, how="all").dropna(axis=1, how="all") for col in df.select_dtypes(include="object").columns: df[col] = df[col].astype(str).str.strip() return df.reset_index(drop=True) def main(): article_url = "https://en.wikipedia.org/wiki/List_of_countries_and_dependencies_by_area" html = crawl(article_url) if not html: return table = find_table(html, index=0) if table is None: print("No table found.") return df = table_to_df(table) if df is None: print("Table could not be parsed.") return df = clean_df(df) df.to_csv("wikipedia_table.csv", index=False) print(f"Saved {df.shape[0]} rows to wikipedia_table.csv") print(df.head()) if __name__ == "__main__": main()
Скрипт получает статью, изолирует первую wikitable, разбирает её в DataFrame, выполняет шаг очистки и записывает wikipedia_table.csv со строкой заголовка и без столбца индекса. Вывод df.head() в конце даёт мгновенный предпросмотр в терминале. Чтобы нацелиться на другую статью или другую таблицу на той же странице, измените article_url и аргумент index в вызове find_table.
Как выглядит результат
Запустите полный скрипт командой python wikipedia_scraper.py и вы получите чистый CSV: по одной строке на каждую строку таблицы, готовый для pandas, базы данных или электронной таблицы.
Rank,Country / dependency,Total area (km2),Total area (mi2),Land,Water,Notes ,World,510072000,196940000,148940000,361132000, 1,Russia,17098246,6601665,16376870,721391, 2,Antarctica,14200000,5500000,14200000,0, 3,Canada,9984670,3855100,9093507,891163, 4,China,9596961,3705407,9326410,270550, 5,United States,9525067,3677649,9147593,377424,
Столбцы соответствуют исходной таблице, маркеры сносок удалены, а числа достаточно чисты для непосредственной загрузки в pandas для фильтрации, сортировки или объединения с другими наборами данных. Подставьте любую статью с wikitable, и те же пять функций произведут такой же аккуратный результат.
Масштабирование на множество статей
Получение одной таблицы это строительный блок. Для сбора одной и той же таблицы из множества статей оберните пять функций в цикл по списку URL, сделайте небольшую паузу между запросами и объедините очищенные фреймы. Несколько привычек обеспечивают здоровье более длительного прогона.
- Темпируйте запросы. Добавляйте короткую паузу между запросами и поддерживайте разумный объём, особенно при работе с таким ресурсом на общественных началах, как Wikipedia.
- Используйте ротацию. Маршрутизация каждого запроса через Crawling API распределяет нагрузку по множеству IP, так что более крупный обход не концентрируется на одном адресе.
- Отдавайте предпочтение официальным массовым путям. Для больших объёмов Wikipedia API и официальные дампы базы данных являются предназначенным маршрутом и значительно меньше нагружают живой сайт, чем скрапинг, как описано в следующем разделе.
Для более крупных обходов асинхронный Crawler ставит запросы в очередь и доставляет результаты на веб-хук, что удобно для обработки множества статей без удержания открытых соединений. Для загрузки очищенных таблиц в хранилище подход из статьи веб-скрапинг в SQL применим непосредственно к DataFrame, которые вы создаёте здесь.
Законно ли скрапить Wikipedia?
Скрапинг публичных таблиц Wikipedia для исследований или анализа в целом допустим, однако важной частью является лицензия, а не только доступ. Текстовый контент Wikipedia опубликован под лицензией Creative Commons Attribution-ShareAlike (CC-BY-SA): вы можете свободно повторно использовать и адаптировать его при условии указания источника и распространения производных работ под той же лицензией. Если вы публикуете или распространяете таблицу, которую извлекли, укажите Wikipedia в качестве источника и дайте ссылку на статью, из которой она взята, а также помните об условии сохранения лицензии для всего, что вы создаёте на её основе. Скрапинг не отменяет эти условия; он лишь перемещает данные.
Придерживайтесь нескольких разумных границ. Соблюдайте условия использования Wikipedia и её robots.txt, поддерживайте низкий темп запросов, чтобы не перегружать серверы некоммерческой организации, и ограничивайтесь таблицами и другим публичным контентом вместо перепубликации целых статей. Именно поэтому данное руководство ограничено табличными данными: это фрагмент, наиболее полезный для повторного использования и простейший для корректного указания авторства.
Когда данные нужны в большом объёме, скрапинг обычно является неправильным инструментом. Фонд Wikimedia предоставляет официальные пути, созданные именно для этого: официальный MediaWiki API для структурированных запросов и периодические дампы базы данных для массовой загрузки целых вики. Они значительно меньше нагружают живой сайт, дают более чистые данные и являются маршрутом, который проект явно предлагает для активного использования. Обращайтесь к ним в первую очередь, рассматривая живой скрапинг как вариант для разовых или небольших задач, где дамп был бы излишеством.
Ключевые выводы
-
Класс wikitable является вашим якорем. Большинство таблиц данных Wikipedia несут CSS-класс
wikitable, поэтому выбирайте нужную сетку по классу и пропускайте таблицы макета и навигации на той же странице. -
pandas read_html выполняет разбор. Изолируйте одну таблицу с BeautifulSoup, затем передайте её HTML в
read_html, чтобы получить типизированный DataFrame за один вызов, а не обходить строки и ячейки вручную. - Очищайте перед экспортом. Сплющивайте многоуровневые заголовки, удаляйте маркеры сносок в скобках и убирайте пустые строки и столбцы, чтобы CSV был готов к анализу.
-
Маршрутизируйте запросы через Crawling API для масштабирования. Один вызов
crawlвозвращает готовый HTML и ротирует IP, так что сбор таблиц из множества статей не нагружает один адрес. - Указывайте авторство и используйте официальные пути. Контент Wikipedia лицензирован под CC-BY-SA, поэтому при повторном использовании указывайте источник, соблюдайте условия использования и robots.txt, а для массовой работы предпочитайте Wikipedia API и дампы базы данных.
Часто задаваемые вопросы
Как извлечь конкретную таблицу со страницы Wikipedia?
Выберите её по CSS-классу с помощью BeautifulSoup. Большинство таблиц данных несут класс wikitable, поэтому soup.select("table.wikitable") возвращает все таблицы данных на странице; проиндексируйте нужную и передайте её HTML в pandas.read_html. Когда несколько таблиц разделяют класс, уточняйте по индексу или тексту подписи таблицы, как показывает вспомогательная функция find_table в этом руководстве.
Что лучше использовать для разбора таблицы: pandas read_html или BeautifulSoup?
Оба, последовательно. Используйте BeautifulSoup для изоляции точного нужного <table> по классу, затем передайте этот единственный элемент в pandas.read_html для преобразования в DataFrame. Передача всей страницы в read_html тоже работает, но возвращает список со всеми таблицами на странице, включая боковые панели, что оставляет вас угадывать индексы.
Зачем вообще маршрутизировать запросы Wikipedia через Crawling API?
Для одной статьи это может и не понадобиться, поскольку Wikipedia выдаёт контент на стороне сервера. Ценность проявляется при масштабировании: получение множества статей с одного датацентрового IP выглядит как бот и провоцирует ограничения скорости и временные блокировки. Crawling API ротирует доверенные IP и возвращает готовый HTML, так что более крупный обход распределяется по множеству адресов.
Законно ли скрапить таблицы Wikipedia?
Скрапинг публичных таблиц для исследований в целом допустим, однако контент Wikipedia лицензирован под CC-BY-SA, поэтому при публикации таблицы необходимо указать источник и распространять производные работы под той же лицензией. Соблюдайте условия использования и robots.txt, поддерживайте низкий темп и ограничивайтесь таблицами, а не перепубликуйте целые статьи. Для массовых нужд Wikipedia API и дампы базы данных являются официальным путём.
Как сохранить собранную таблицу в CSV?
После того как таблица стала DataFrame, вызовите df.to_csv("wikipedia_table.csv", index=False). Аргумент index=False предотвращает запись индекса строк pandas как дополнительного столбца, так что вы получите чистую строку заголовка и по одной строке на каждую строку таблицы. После этого CSV загружается обратно в pandas или в любую электронную таблицу.
Чем это отличается от общего руководства по скрапингу Wikipedia?
Данный материал ограничен таблицами: выбор wikitable, разбор с помощью pandas, очистка столбцов и экспорт в CSV. Сопутствующее руководство как скрапить Wikipedia охватывает более широкое содержимое страницы: заголовок, изображения и поля информационной таблицы. Используйте это руководство, когда вашей целью являются столбчатые данные, и то, когда вам нужны другие части статьи.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.


