Python爬蟲練習:爬數字貨幣行情網站CoinMarketCap歷史記錄裏TOP100數字貨幣數據並保存至excel/MongoDB數據庫中

這周除了備戰二級口譯之外,閱讀並實踐了下崔神的《Python3網絡爬蟲開發實戰》,試了下貓眼的排行榜數據和頭條街拍圖片的抓取和保存,充分感受到了python大法的強悍之處。作爲一名python小小白和入坑區塊鏈兩年半的小韭菜,出於好奇心爬了下CoinMarketCap上的歷史記錄,代碼雖短,情深可長,保存在csdn上,說不定以後的以後用得上哈哈哈~之後如果學了數據分析,會把爬出來的數據拿來練習練習!

提醒,要導入的包如下(要記得安裝連接MongoDB吼吼):

import random #用於生成隨機數
import time #用於打印系統時間
from pyquery import PyQuery as pq #用於解析提取所需數據
import requests #用於獲取網頁源碼
from fake_useragent import UserAgent #用於隨機生成user-agent
from openpyxl import workbook  # 寫入Excel表所用
from openpyxl import load_workbook  # 讀取Excel表所用
import os #用於指定保存路徑
import re #用於提取信息
import pymongo #用於保存數據到mongodb中

第一步:抓“歷史記錄”主頁的核心內容——日期

每頁數據的url規律是https://coinmarketcap.com/zh/historical/+日期,比如2019年3月3日的數據頁url是https://coinmarketcap.com/zh/historical/20190303/,因此,我們需要到“歷史記錄”頁面拿到日期列表。

01.獲取網頁源代碼

def get_one_page(url): #參數爲"歷史記錄"主頁的url鏈接
    #爲了不輕易被網站管理人員發現是爬蟲,就僞裝user-agent,模擬真實的瀏覽器去抓服務器響應的內容
    ua = UserAgent()
    headers = {"User-Agent": ua.random}
    #構造請求頭並得到服務器響應結果
    response=requests.get(url,headers=headers)
    #如果響應結果的狀態碼爲200,說明正常訪問,否則返回none
    if response.status_code==200:
        #返回響應內容,即網頁源代碼
        return  response.text #
    return None

02.觀察源代碼並獲取所需數據

https://coinmarketcap.com/zh/historical/部分源代碼

可以發現,我們所需要的日期數據就在row節點下的href的屬性值中,只要獲取到href再提取下數據就可以拿到日期了。

def getUrlData(html):
    #記得導入pyquery庫
    doc = pq(html)
    #定位到row節點的a標籤
    page = doc('.row a')
    #遍歷提取href屬性值,並添加到hisdate列表中
    hisdate=[]
    for data in page.items():
        date=data.attr('href')
        hisdate.append(date)

    return hisdate

#清洗日期數據,獲得讀取數據的日期
def cleanUrlData(list):
    #定義一個空列表用於存放清洗後的乾淨數據
    clurldata=[]
    #遍歷找到任何符合以/zh/historical/開頭的字符串,然後去掉所有非數字,留下的數字便是我們要的數據
    for data in list:
        if data.startswith('/zh/historical/'):
            clurldata.append(re.sub("\D", "", data))
    return clurldata #獲取到的乾淨數據可以存到文檔中,之後直接讀取文件就行,我比較懶,直接返回過去,使得每次運行的時候都要先到主頁再去分頁提取數據,不過,因爲日期會更新,所以,看個人喜好啦

第二步:獲取每頁數據,觀察並提取所需數據,清洗後保存

#獲取每頁數據,並保存
def getData(clurldata):
    #定義url的起始部分
    start_url='https://coinmarketcap.com/zh/historical/'
    #這裏臨時定義了一個temp列表,是因爲運行過程中,因爲訪問頻率經常被服務器禁了,沒有去搞代理池的咕涼我於是只能出此下策,哪裏被禁了就把日期改成最後搞定的那一天的日期,然後重新運行(比較傻的方法了吼吼吼)
    temp=clurldata[clurldata.index('20140803')+1:]
    #然後繼續從被打斷的部分開始抓
    for end_url in temp:
        #構造最後的html網頁
        final_url=start_url+end_url
        #獲得網頁源碼
        final_html=get_one_page(final_url)
        #因爲發現每個數字貨幣的信息都是tr節點開始,因此node在之前全局變量定義:node='tr'
        doc = pq(final_html)
        page = doc.find(node)

        #想把數據分列保存在excel裏,因此建立對應的列表,每讀一頁數據重置一次
        index = []
        symbol = []
        name = []
        marketcap = []
        price = []
        #因爲越到後面,每頁的數據量較多,實際分析用不上,就定義count,最多隻獲取前100的數字貨幣
        count=0
        #開始遍歷提取這一頁的每個數字貨幣的數據
        for data in page.items():
            dict = {}
            inx = data.find('.text-center').text() #排名
            syb = data.find('.currency-symbol.visible-xs').text() #數字貨幣簡寫
            nm = data.find('.currency-name-container.link-secondary').text()#數字貨幣名稱
            mcap = re.sub(",", "", str(data.find('.no-wrap.market-cap.text-right').text())[1:])#首先去掉開頭的美元符號$,再用re庫去掉逗號(清洗數據)
            pri = re.sub(",", "", str(data.find('.price').text())[1:])#一樣先去掉開頭的美元符號$,再用re庫去掉逗號(清洗數據)
            #一個個添加到列表中(用於excel保存)
            index.append(inx)
            symbol.append(syb)
            name.append(nm)
            marketcap.append(mcap)
            price.append(pri)
            #添加到字典中(用於MongoDB保存)
            dict['index'] = inx
            dict['symbol'] = syb
            dict['name'] = nm
            dict['marketcap'] = mcap
            dict['price'] = pri
            dict['date'] = end_url
            #取前100數據,太多分析價值不大
            count+=1
            if count==101:
                break

            # 一條一條地寫進mongodb數據庫中
            collection.insert_one(dict)
        print(end_url)

        #寫進excel表格中
        wb = workbook.Workbook()  # 創建Excel對象
        ws = wb.active  # 獲取當前正在操作的表對象
        # 寫進excel
        for i in range(len(index)):
            ws.append([index[i], symbol[i], name[i], marketcap[i], price[i],end_url])
        #保存的路徑和名稱
        wb.save(data_path+os.path.sep+end_url+ '.xlsx')
        print(end_url,'excel success')

        #sleep下下,防止被禁,輸出下時間,可以稍微瞭解下實際的隨機等待時間
        print("Start : %s" % time.ctime())
        time.sleep(random.randint(15, 20))
        print("End : %s" % time.ctime())

醬紫就完成數據的抓取啦~有些地方寫得比較笨吼吼~剛入門python一週的咕涼我很多用法還不太熟悉,希望有更好的解決方法的大神多多指教吼吼~去健身啦啦啦~春天到啦,要減肥啦~咕涼我要瘦瘦瘦!

附上完整代碼:

import json
import random
import time
from pyquery import PyQuery as pq
import requests
from fake_useragent import UserAgent
from openpyxl import workbook  # 寫入Excel表所用
from openpyxl import load_workbook  # 讀取Excel表所用
import os
import re
import pymongo

client=pymongo.MongoClient(host='localhost',port=27017)
db=client.test
collection=db.coinmarketcap
hisdate=[]
node='tr' #目標信息所在節點
data_path= 'CoinMarketCap'+ os.path.sep +'excel'
#如果沒有該路徑,就自動生成對應文件夾
if not os.path.exists(data_path):
    os.makedirs(data_path)

def get_one_page(url): #參數爲"歷史記錄"主頁的url鏈接
    #爲了不輕易被網站管理人員發現是爬蟲,就僞裝user-agent,模擬真實的瀏覽器去抓服務器響應的內容
    ua = UserAgent()
    headers = {"User-Agent": ua.random}
    #構造請求頭並得到服務器響應結果
    response=requests.get(url,headers=headers)
    #如果響應結果的狀態碼爲200,說明正常訪問,否則返回none
    if response.status_code==200:
        #返回響應內容,即網頁源代碼
        return  response.text #
    return None

#獲取後半截url數據
def getUrlData(html):
    #記得導入pyquery庫
    doc = pq(html)
    #定位到row節點的a標籤
    page = doc('.row a')
    #遍歷提取href屬性值,並添加到hisdate列表中
    for data in page.items():
        date=data.attr('href')
        hisdate.append(date)

    return hisdate

#清洗日期數據,獲得後續讀取數據的日期
def cleanUrlData(list):
    #定義一個空列表用於存放清洗後的乾淨數據
    clurldata=[]
    #遍歷找到任何符合以/zh/historical/開頭的字符串,然後去掉所有非數字,留下的數字便是我們要的數據
    for data in list:
        if data.startswith('/zh/historical/'):
            clurldata.append(re.sub("\D", "", data))
    return clurldata

#獲取每頁數據,並保存
def getData(clurldata):
    #定義url的起始部分
    start_url='https://coinmarketcap.com/zh/historical/'
    #這裏臨時定義了一個temp列表,是因爲運行過程中,因爲訪問頻率經常被服務器禁了,沒有去搞代理池的咕涼我於是只能出此下策,哪裏被禁了就把日期改成最後搞定的那一天的日期
    temp=clurldata[clurldata.index('20150118')+1:]
    #然後繼續從被打斷的部分開始抓
    for end_url in temp:
        #構造最後的html網頁
        final_url=start_url+end_url
        #獲得網頁源碼
        final_html=get_one_page(final_url)
        #因爲發現每個數字貨幣的信息都是tr節點開始,因此node在之前全局變量定義:node='tr'
        doc = pq(final_html)
        page = doc.find(node)

        #想把數據分列保存在excel裏,因此建立對應的列表,每讀一頁數據重置一次
        index = []
        symbol = []
        name = []
        marketcap = []
        price = []
        #因爲越到後面,每頁的數據量較多,實際分析用不上,就定義count,最多隻獲取前100的數字貨幣
        count=0
        #開始遍歷提取這一頁的每個數字貨幣的數據
        for data in page.items():
            dict = {}
            inx = data.find('.text-center').text() #排名
            syb = data.find('.currency-symbol.visible-xs').text() #數字貨幣簡寫
            nm = data.find('.currency-name-container.link-secondary').text()#數字貨幣名稱
            mcap = re.sub(",", "", str(data.find('.no-wrap.market-cap.text-right').text())[1:])#首先去掉開頭的美元符號$,再用re庫去掉逗號(清洗數據)
            pri = re.sub(",", "", str(data.find('.price').text())[1:])#一樣先去掉開頭的美元符號$,再用re庫去掉逗號(清洗數據)
            #一個個添加到列表中(用於excel保存)
            index.append(inx)
            symbol.append(syb)
            name.append(nm)
            marketcap.append(mcap)
            price.append(pri)
            #添加到字典中(用於MongoDB保存)
            dict['index'] = inx
            dict['symbol'] = syb
            dict['name'] = nm
            dict['marketcap'] = mcap
            dict['price'] = pri
            dict['date'] = end_url
            #取前100數據,太多分析價值不大
            count+=1
            if count==101:
                break

            # 一條一條地寫進mongodb數據庫中
            collection.insert_one(dict)
        print(end_url)

         #寫進excel表格中
        wb = workbook.Workbook()  # 創建Excel對象
        ws = wb.active  # 獲取當前正在操作的表對象
        # 寫進excel
        for i in range(len(index)):
            ws.append([index[i], symbol[i], name[i], marketcap[i], price[i],end_url])

        wb.save(data_path+os.path.sep+end_url+ '.xlsx')
        print(end_url,'excel success')

        #sleep下下,防止被禁,輸出下時間,可以稍微瞭解下實際的隨機等待時間
        print("Start : %s" % time.ctime())
        time.sleep(random.randint(15, 20))
        print("End : %s" % time.ctime())



if __name__ == '__main__':
    url = 'https://coinmarketcap.com/zh/historical/'
    html = get_one_page(url)
    getData(cleanUrlData(getUrlData(html)))
    # print(html)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章