【Humo】小趴菜系列-CoinMarketCap第一弹 获取历史货币数据

494 阅读2分钟

嘿,兄die,我是小右。交个朋友吧~

CoinMarketCap

需求描述

网址: coinmarketcap.com/historical/

将每个日期打开的的历史数据table抓取并输出到Excel

日期数据页: coinmarketcap.com/historical/…

功能实现

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time        : 2022/12/7 22:31
# @Author      : Mini-Right
# @Email       : www@anyu.wang
# @File        : coin_market_cap.py
# @Software    : PyCharm
# @Description :
import datetime
from typing import List

import arrow
import requests
import xlsxwriter
from requests.adapters import HTTPAdapter

"""
    网址: https://coinmarketcap.com/historical/
    起始日期: 20130428
    间隔时间: 7 day (sun day)

    数据获取API: https://api.coinmarketcap.com/data-api/v3/cryptocurrency/listings/historical?convertId=2781,1&date=2022-12-04&limit=200&start=1

"""


class CoinMarketCap(object):

    def __init__(self):
        self.session = requests.session()
        self.session.mount('https://', HTTPAdapter(max_retries=3))

    def historical_api(self, date: str, start: int = 1, limit: int = 200):
        """
        获取历史数据接口
        :param date:    日期  格式: YYYY-MM-DD
        :param start:   起始条数    默认: 1
        :param limit:   获取条数    默认: 200
        :return:
        """
        # time.sleep(1)
        url = "https://api.coinmarketcap.com/data-api/v3/cryptocurrency/listings/historical"
        params = {
            "convertId": "2781,1",
            "date": date,
            "limit": str(limit),
            "start": str(start)
        }
        headers = {
            "accept": "application/json, text/plain, */*",
            "accept-encoding": "gzip, deflate, br",
            "accept-language": "zh-CN,zh;q\u003d0.9,en;q\u003d0.8",
            "cache-control": "no-cache",
            "origin": "https://coinmarketcap.com",
            "platform": "web",
            "referer": "https://coinmarketcap.com/",
            "sec-ch-ua": "\"Google Chrome\";v\u003d\"107\", \"Chromium\";v\u003d\"107\", \"Not\u003dA?Brand\";v\u003d\"24\"",
            "sec-ch-ua-mobile": "?0",
            "sec-ch-ua-platform": "\"macOS\"",
            "sec-fetch-dest": "empty",
            "sec-fetch-mode": "cors",
            "sec-fetch-site": "same-site",
            "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36",
            "x-request-id": "9f5c086e1a844c29bdf665c050a4bebe",
        }
        response = self.session.get(url=url, params=params, headers=headers)
        if response.status_code == 200:
            return response.json()

    def main(self, date: str):
        start, limit = 1, 200
        excel = ToExcel(excel_path=f"./{date}.xlsx", sheet_name='sheet')
        excel.write_title(['Rank', 'Name', 'Symbol', 'Market Cap', 'Price', 'Circulating Supply', 'volume (24h)', '% 1h', '% 24h', '% 7d'])
        count = 0
        while True:
            # 接口中无分页字段 以start起始条数开始获取  当获取数组为空时 代表这个日期数据全部获取完成
            historical_data: dict = self.historical_api(date=date, start=start)
            item_list: List[dict] = historical_data.get('data')
            if not item_list:
                break
            for item in item_list:
                cmc_rank = item.get('cmcRank')
                name = item.get('name')
                symbol = item.get('symbol')
                quotes = item.get('quotes')
                market_cap = quotes[0].get('marketCap')
                price = quotes[0].get('price')
                total_supply = item.get('totalSupply')
                volume24h = quotes[0].get('volume24h')
                percent_change_1h = quotes[0].get('percentChange1h')
                percent_change_24h = quotes[0].get('percentChange24h')
                percent_change_7d = quotes[0].get('percentChange7d')
                item_info = {
                    "rank": cmc_rank,
                    "name": name,
                    "symbol": symbol,
                    "market_cap": market_cap,
                    "price": price,
                    "total_supply": total_supply,
                    "volume24h": volume24h,
                    "percent_change_1h": percent_change_1h,
                    "percent_change_24h": percent_change_24h,
                    "percent_change_7d": percent_change_7d,
                }
                excel.write(list(item_info.values()))
                count += 1
                print(f"{date}  {count}  {item_info}")

            start += limit

        excel.close()


class ToExcel(object):
    def __init__(self, excel_path: str, sheet_name: str):
        self.f = xlsxwriter.Workbook(
            excel_path,
            options={
                'strings_to_urls': False,
                'default_date_format': '%Y-%m-%d %H:%M:%S'
            })
        self.ws = self.f.add_worksheet(sheet_name)
        self.count = 0

    def write_title(self, data: list):
        for index, value in enumerate(data):
            self.ws.write_string(0, index, str(value))

    def write(self, data: list):
        self.count += 1
        for index, value in enumerate(data):
            self.ws.write_string(self.count, index, str(value))

    def close(self):
        self.f.close()


def get_any_date(date: str, day: int = 0) -> str:
    _format: str = "YYYY-MM-DD"
    return arrow.get(date, _format).shift(days=day).format(_format)


if __name__ == '__main__':
    # 指定日期执行
    # coin = CoinMarketCap()
    # coin.main('2022-12-04')

    # 全量日期执行
    history_date = '2013-04-28'
    while True:
        # 起始时间固定 死循环+7天获取数据  当生成时间大于当天时退出
        if datetime.datetime.strptime(history_date, '%Y-%m-%d') > datetime.datetime.now():
            break
        print(history_date)
        CoinMarketCap().main(history_date)
        history_date = get_any_date(date=history_date, day=7)

公众号: 小右说