Парсинг данных о криптовалютах: От простого к сложному

Криптовалюты — это динамичный мир, где данные меняются ежеминутно. Парсинг помогает трейдерам и аналитикам извлекать ценную информацию из API, веб-сайтов и файлов. В этой статье мы разберём парсинг от простого к сложному: начнём с разбора строк и JSON, перейдём к XML и CSV, а закончим веб-скрейпингом HTML с использованием Python.

1. Введение в парсинг: Почему это важно для крипты?

Парсинг — это процесс извлечения структурированных данных из неструктурированного или полуструктурированного источника. В криптовалютах данные приходят из API (CoinMarketCap), веб-сайтов (CoinGecko) или логов транзакций. Без парсинга это займёт часы ручной работы, с парсингом — секунды автоматизации.

Предварительные требования: Установите Python 3 и библиотеки:

pip install requests beautifulsoup4 lxml

2. Простой парсинг: Разбор строк

Начнём с простого. Допустим, у вас есть строка: «Bitcoin: 45000 USD, Ethereum: 3000 USD».

Пример 1: Парсинг строки с помощью split()

data_string = "Bitcoin: 45000 USD, Ethereum: 3000 USD"

# Разделяем строку по запятой, затем по двоеточию
parts = data_string.split(", ")
btc_info = parts[0].split(": ")
eth_info = parts[1].split(": ")

btc_name = btc_info[0]
btc_price = int(btc_info[1].split(" ")[0])
eth_name = eth_info[0]
eth_price = int(eth_info[1].split(" ")[0])

print(f"{btc_name} цена: {btc_price} USD")
print(f"{eth_name} цена: {eth_price} USD")

Что делает код: Делит строку по запятой и двоеточию, извлекает названия и цены, преобразует цены в числа. Это простой метод для логов транзакций.

Результат:

3. Парсинг JSON: Данные из API

JSON — стандарт для API криптобирж. Используем CoinGecko API для получения цен.

Пример 2: Парсинг JSON

import requests
import json

url = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=usd"

response = requests.get(url)
if response.status_code == 200:
    data = json.loads(response.text)
    btc_price = data['bitcoin']['usd']
    eth_price = data['ethereum']['usd']
    print(f"Bitcoin: {btc_price} USD")
    print(f"Ethereum: {eth_price} USD")
else:
    print("Ошибка запроса")

Что делает код: Запрашивает JSON, преобразует его в словарь, извлекает цены. Проверка status_code предотвращает сбои. Полезно для трейдинг-ботов.

Результат:

4. Парсинг XML: Для специфических источников

XML используется в RSS-фидах (например, CoinDesk). Пример XML:

<cryptonews>
    <item>
        <title>Bitcoin растёт</title>
        <price>45000</price>
    </item>
    <item>
        <title>Ethereum обновление</title>
        <price>3000</price>
    </item>
</cryptonews>

Пример 3: Парсинг XML с ElementTree

import xml.etree.ElementTree as ET

xml_data = """
<cryptonews>
    <item>
        <title>Bitcoin растёт</title>
        <price>45000</price>
    </item>
    <item>
        <title>Ethereum обновление</title>
        <price>3000</price>
    </item>
</cryptonews>
"""

root = ET.fromstring(xml_data)
for item in root.findall('item'):
    title = item.find('title').text
    price = int(item.find('price').text)
    print(f"Новость: {title}, Цена: {price} USD")

Что делает код: Парсит XML в дерево, извлекает заголовки и цены. Полезно для новостных фидов.

5. Парсинг CSV: Анализ транзакций

CSV — формат для экспорта данных с бирж. Пример: «coin,price,date».

Пример 4.0: Получение цен валют и сохранение в CSV

import requests
import csv
from datetime import datetime

url = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=usd"

response = requests.get(url)
if response.status_code == 200:
    data = response.json()
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    with open('crypto_prices.csv', 'w', newline='') as f:
        writer = csv.writer(f)
        writer.writerow(['coin', 'price', 'timestamp'])
        writer.writerow(['Bitcoin', data['bitcoin']['usd'], timestamp])
        writer.writerow(['Ethereum', data['ethereum']['usd'], timestamp])
    print("Данные сохранены в crypto_prices.csv")
else:
    print("Ошибка запроса")

Что делает код: Запрашивает цены Bitcoin и Ethereum через API CoinGecko, сохраняет их в CSV-файл с временной меткой.

Результат:

Пример 4.1: Извлечение данных из CSV

import csv

with open('crypto_prices.csv', 'r') as f:
    reader = csv.DictReader(f)
    for row in reader:
        coin = row['coin']
        price = float(row['price'])
        timestamp = row['timestamp']
        print(f"{coin}: {price} USD на {timestamp}")

Что делает код: Читает CSV-файл, созданный в примере 4.1, и выводит данные о монетах, ценах и времени.

Результат:

6. Продвинутый парсинг: Веб-скрейпинг

Скрейпинг CoinMarketCap для топ-крипты с BeautifulSoup.

Пример 5: Базовый скрейпинг

import requests
from bs4 import BeautifulSoup

url = "https://coinmarketcap.com/"
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')

table = soup.find('table', class_='cmc-table')
rows = table.find_all('tr')[1:3]

for row in rows:
    cols = row.find_all('td')
    name = cols[1].text.strip()
    price = cols[3].text.strip()
    print(f"{name}: {price}")

Что делает код: Извлекает имена и цены из таблицы. Уважайте robots.txt!

Результат:

Пример 6: Продвинутый парсинг

Пример 6 демонстрирует продвинутый веб-парсинг данных о криптовалютах с сайта CoinMarketCap (https://coinmarketcap.com/) с использованием библиотек Python requests и BeautifulSoup. Код извлекает названия, тикеры и цены криптовалют из таблицы на двух страницах сайта, обрабатывает возможные ошибки, использует CSS-селекторы для точного парсинга. Основная цель — получить структурированные данные (название, тикер и цена) для первых пяти монет с каждой страницы и вывести их в консоль.

Основные особенности

  • Пагинация: Код обрабатывает две страницы (?page=1 и ?page=2), чтобы извлечь данные из разных частей рейтинга. по 5 монет из каждой страницы.
  • Обработка ошибок: Проверяет HTTP-ошибки и отсутствие таблицы.
  • Этичный скрейпинг: Задержка в 2 секунды между запросами снижает нагрузку на сервер.
  • CSS-селекторы: Использует точные селекторы для извлечения данных из HTML.
  • Ограничение вывода: Извлекает только первые 5 монет с каждой страницы для упрощения.

Код

import requests
from bs4 import BeautifulSoup
import time

def scrape_page(page_num):
    url = f"https://coinmarketcap.com/?page={page_num}"
    try:
        response = requests.get(url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        print(f"Ошибка: {e}")
        return []

    soup = BeautifulSoup(response.text, 'lxml')
    table = soup.select_one('table')
    if not table:
        print("Таблица не найдена")
        return []

    data = []
    for index, row in enumerate(table.select('tbody tr')[0:5], 1):  # Первые 5 монет
        name_cell = row.select_one('p.sc-65e7f566-0.iPbTJf.coin-item-name')
        ticker_cell = row.select_one('td:nth-child(2) span.sc-65e7f566-0')
        price_cell = row.select_one('td:nth-child(4) span')
        name = name_cell.text.strip() if name_cell else "N/A"
        ticker = ticker_cell.text.strip() if ticker_cell else ""
        price = price_cell.text.strip() if price_cell else "N/A"
        full_name = f"{name} {ticker}".strip()
        print(f"{index}: {full_name} - {price}")
        data.append((full_name, price))
    return data

all_data = []
for page in range(1, 3):
    all_data.extend(scrape_page(page))
    time.sleep(2)

print("\nИтоговые данные:")
for index, (name, price) in enumerate(all_data, 1):
    print(f"{index}: {name} - {price}")

Результат:

Пошаговое объяснение кода

Импорт библиотек

import requests
from bs4 import BeautifulSoup
import time
  • requests: Для отправки HTTP-запросов к сайту.
  • BeautifulSoup (из bs4): Для парсинга HTML и извлечения данных.
  • time: Для добавления задержки между запросами.

Функция scrape_page(page_num)

def scrape_page(page_num):
    url = f"https://coinmarketcap.com/?page={page_num}"
    try:
        response = requests.get(url, timeout=10, headers={'User-Agent': 'Mozilla/5.0'})
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        print(f"Ошибка: {e}")
        return []
  • Назначение: Принимает номер страницы и извлекает данные о криптовалютах.
  • URL: Формирует URL для конкретной страницы (например, ?page=1).
  • HTTP-запрос: Отправляет GET-запрос с таймаутом 10 секунд и User-Agent для имитации браузера.
  • Обработка ошибок: Проверяет успешность запроса; при ошибке (например, 404) возвращает пустой список.

Парсинг HTML

soup = BeautifulSoup(response.text, 'lxml')
table = soup.select_one('table')
if not table:
    print("Таблица не найдена")
    return []
  • BeautifulSoup(response.text, 'lxml'): Парсит HTML с парсером lxml (быстрее стандартного).
  • soup.select_one('table'): Находит первый тег <table> с данными.
  • Если таблица не найдена, возвращается пустой список.

Извлечение данных

data = []
for index, row in enumerate(table.select('tbody tr')[0:5], 1):  # Первые 5 монет
    name_cell = row.select_one('p.sc-65e7f566-0.iPbTJf.coin-item-name')
    ticker_cell = row.select_one('td:nth-child(2) span.sc-65e7f566-0')
    price_cell = row.select_one('td:nth-child(4) span')
    name = name_cell.text.strip() if name_cell else "N/A"
    ticker = ticker_cell.text.strip() if ticker_cell else ""
    price = price_cell.text.strip() if price_cell else "N/A"
    full_name = f"{name} {ticker}".strip()
    print(f"{index}: {full_name} - {price}")
    data.append((full_name, price))
return data
  • Инициализация: Создаётся список data для хранения пар (название+тикер, цена).
  • Цикл: Перебирает первые 5 строк таблицы (tbody tr[0:5]), нумеруя с 1.
  • Извлечение:
    • Имя: p.sc-65e7f566-0.iPbTJf.coin-item-name извлекает название (например, «Bitcoin»).
    • Тикер: td:nth-child(2) span.sc-65e7f566-0 пытается извлечь тикер (например, «BTC»).
    • Цена: td:nth-child(4) span извлекает цену (например, «$115,407.32»).
  • Обработка: Если элемент не найден, возвращается «N/A» или пустая строка. Имя и тикер объединяются в full_name.
  • Вывод: Печатает строку вида 1: Bitcoin BTC - $115,407.32 и добавляет данные в data.
  • Возврат: Возвращает список data.

Сбор данных с нескольких страниц

all_data = []
for page in range(1, 3):
    all_data.extend(scrape_page(page))
    time.sleep(2)
  • all_data: Список для хранения данных со всех страниц.
  • Цикл: Перебирает страницы 1 и 2, вызывая scrape_page.
  • extend: Добавляет данные страницы в all_data.
  • time.sleep(2): Задержка 2 секунды для этичности.

Итоговый вывод

print("\nИтоговые данные:")
for index, (name, price) in enumerate(all_data, 1):
    print(f"{index}: {name} - {price}")
  • Выводит заголовок и все данные из all_data в формате 1: Bitcoin BTC - $115,407.32.

Проблемы и рекомендации

Ограничение: Код извлекает только 5 монет на страницу ([0:5]). Для большего количества измените на [0:10].

API: Для надёжности используйте API CoinMarketCap (https://coinmarketcap.com/api/).

Антибот-защита: Если сайт блокирует, добавьте заголовки:

headers = {
    'User-Agent': 'Mozilla/5.0',
    'Accept': 'text/html',
    'Accept-Language': 'en-US,en;q=0.9'
}

7. Заключение

Мы прошли от split() до скрейпинга с BeautifulSoup. Парсинг криптоданных открывает путь к торговым ботам и анализу. Экспериментируйте с базами данных или asyncio.
Смотрите примеры и изучайте уроки на https://parsertools.ru

Похожие темы: