1. 程式人生 > >Python爬蟲抓取東方財富網股票數據並實現MySQL數據庫存儲

Python爬蟲抓取東方財富網股票數據並實現MySQL數據庫存儲

alt 插入 pytho width 重新 tab 空值 utf word

Python爬蟲可以說是好玩又好用了。現想利用Python爬取網頁股票數據保存到本地csv數據文件中,同時想把股票數據保存到MySQL數據庫中。需求有了,剩下的就是實現了。

在開始之前,保證已經安裝好了MySQL並需要啟動本地MySQL數據庫服務。提到安裝MySQL數據庫,前兩天在一臺電腦上安裝MySQL5.7時,死活裝不上,總是提示缺少Visual Studio 2013 Redistributable,但是很疑惑,明明已經安裝了呀,原來問題出在版本上,更換一個版本後就可以了。小問題大苦惱,不知道有沒有人像我一樣悲催。

言歸正傳,啟動本地數據庫服務:

用管理員身份打開“命令提示符(管理員)”,然後輸入“net start mysql57”(我把數據庫服務名定義為mysql57了,安裝MySQL時可以修改)就可以開啟服務了。註意使用管理員身份打開小黑框,如果不是管理員身份,我這裏會提示沒有權限,大家可以試試。結果如下:

技術分享

啟動服務之後,我們可以選擇打開“MySQL 5.7 Command Line Client”小黑框,需要先輸入你的數據庫的密碼,安裝的時候定義過,在這裏可以進行數據庫操作。

技術分享

下面開始上正餐。

一、Python爬蟲抓取網頁數據並保存到本地數據文件中

首先導入需要的數據模塊,定義函數:

#導入需要使用到的模塊
import urllib
import re
import pandas as pd
import pymysql
import os

#爬蟲抓取網頁函數
def getHtml(url):
    html = urllib.request.urlopen(url).read()
    html 
= html.decode(gbk) return html #抓取網頁股票代碼函數 def getStackCode(html): s = r<li><a target="_blank" href="http://quote.eastmoney.com/\S\S(.*?).html"> pat = re.compile(s) code = pat.findall(html) return code

真正幹活的代碼塊:

Url = http://quote.eastmoney.com/stocklist.html#東方財富網股票數據連接地址
filepath = ‘D:\\data\\#定義數據文件保存路徑 #實施抓取 code = getStackCode(getHtml(Url)) #獲取所有股票代碼(以6開頭的,應該是滬市數據)集合 CodeList = [] for item in code: if item[0]==6: CodeList.append(item) #抓取數據並保存到本地csv文件 for code in CodeList: print(正在獲取股票%s數據%code) url = http://quotes.money.163.com/service/chddata.html?code=0+code+ &end=20161231&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;TURNOVER;VOTURNOVER;VATURNOVER;TCAP;MCAP urllib.request.urlretrieve(url, filepath+code+.csv)

以上代碼實現了爬蟲網頁抓取股票數據,並保存到本地文件中。關於爬蟲的東西,有很多資料可以參考,大都是一個套路,不再多說。同時,本文實現過程中也參考了很多的網頁資源,在此對所有原創者表示感謝!

先看下抓取的結果。CodeList是抓取到的所有股票代碼的集合,我們看到它共包含1416條元素,即1416支股票數據。因為股票太多,所以抓取的是以6開頭的,貌似是滬市股票數據(原諒我不懂金融)。

技術分享

抓取到的股票數據會分別存儲到csv文件中,一只股票數據一個文件。理論上會有1416個csv文件,和股票代碼數一致。但原諒我的渣網速,下載一個都費勁,也是呵呵了。

技術分享

打開一個本地數據文件看一下抓取的數據長什麽樣子:

技術分享

其實和人工手動下載也沒什麽區別了,硬要說區別,那就是解放了勞動力,提高了生產力(怎麽聽起來像政治?)。

二、將數據存儲到MySQL數據庫

首先建立本地數據庫連接:

#數據庫名稱和密碼
name = ‘xxxx
password = ‘xxxx
#建立本地數據庫連接(需要先開啟數據庫服務)
db = pymysql.connect(localhost, name, password, charset=utf8)
cursor = db.cursor()

其中,數據庫名稱(name)和密碼(password)是安裝MySQL時設置的。

創建數據庫,專門用來存儲本次股票數據:

#創建數據庫stockDataBase,這裏使用了異常處理,避免因數據庫可能已經存在而報錯
try:
    sqlSentence1 = "create database stockDataBase"
    cursor.execute(sqlSentence1)
except Exception as e:
    print(e)
#選擇使用當前數據庫
sqlSentence2 = "use stockDataBase;"
cursor.execute(sqlSentence2)

在首次運行的時候一般都會正常創建數據庫,但如果再次運行,因數據庫已經存在,再次創建會出錯,因此這裏引用了異常處理,如果數據庫已經存在,那麽跳過創建,繼續往下執行。創建好數據庫後,選擇使用剛剛創建的數據庫,在該數據庫中存儲數據表。

下面看具體的存儲代碼:#獲取本地文件列fileList = os.listdir(filepath)

#依次對每個數據文件進行存儲
for fileName in fileList:
    data = pd.read_csv(filepath+fileName, encoding="gbk")
   #創建數據表,如果數據表已經存在,會跳過繼續執行下面的步驟
    try:
        print(創建數據表stock_%s% fileName[0:6])
        sqlSentence3 = "create table stock_%s" % fileName[0:6] + "(日期 date, 股票代碼 VARCHAR(10), 名稱 VARCHAR(10), 收盤價 float,\
最高價 float, 最低價 float, 開盤價 float, 前收盤 float, 漲跌額 float, 漲跌幅 float, 換手率 float,\
成交量 bigint, 成交金額 bigint, 總市值 bigint, 流通市值 bigint)
" cursor.execute(sqlSentence3) except: print(數據表已存在!) #叠代讀取表中每行數據,依次存儲(整表存儲還沒嘗試過) print(正在存儲stock_%s% fileName[0:6]) length = len(data) for i in range(0, length): record = tuple(data.loc[i]) #插入數據語句 try: sqlSentence4 = "insert into stock_%s" % fileName[0:6] + "(日期, 股票代碼, 名稱, 收盤價, 最高價, 最低價, 開盤價,\
前收盤, 漲跌額, 漲跌幅, 換手率, 成交量, 成交金額, 總市值, 流通市值) \
values (‘%s‘,%s‘,‘%s‘,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)
" % record #獲取的表中數據很亂,包含缺失值、Nnone、none等,插入數據庫需要處理成空值 sqlSentence4 = sqlSentence4.replace(nan,null).replace(None,null).replace(none,null) cursor.execute(sqlSentence4) except:#如果以上插入過程出錯,跳過這條數據記錄,繼續往下進行 break

代碼並不復雜,只要註意其中幾個點就好了。

1.邏輯層次:

包含兩層循環,外層循環是對股票代碼的循環,內層循環是對當前股票的每一條記錄的循環。說白了就是按照股票一支一支的存儲,對於每一支股票,按照它每日的記錄一條一條的存儲。是不是很簡單很暴力?是的!完全沒有考慮更加優化的方式。

2.讀取本地數據文件的編碼方式:

使用‘gbk‘編碼,默認應該是‘utf8‘,但好像不支持中文。

3.創建數據表:

同樣的,如果數據表已經存在,則跳過創建,繼續執行下面的步驟(會繼續存儲)。有個問題是,有可能數據重復存儲,可以選擇跳過存儲或者只存儲最新數據。我在這裏沒有考慮太多額外的處理。其次,指定字段格式,後邊幾個字段成交量、成交金額、總市值、流通市值,因為數據較大,選擇使用bigint類型。

4.沒有指定數據表的主鍵:

最初是打算使用日期作為主鍵的,後來發現獲取到的數據中竟然包含重復日期的數據,這就打破了主鍵的唯一性,會出bug的,然後我也沒有多去思考數據文件的內容,也不會進一步使用這些個數據,也就圖省事直接不設置主鍵了。

5.構造sql語句sqlSentence4:

該過程實現中,直接把股票數據記錄tuple了,然後使用字符串格式化(%操作符)。造成的精度問題沒有多考慮,不知道會不會產生什麽樣的影響。%s有的上邊帶著‘ ‘,是為了在sql語句中表示字符串。其中有一個%s‘,只有右邊有單引號,匹配的是股票代碼,只有一邊單引號,這是因為從數據文件中讀取到的字符串已經包含了左邊的單引號,左邊不需要再添加了。這是數據文件格式的問題,為了表示文本形式預先使用了單引號。

6.異常值處理:

文本文件中,包含有空值、None、none等不標準化數據,這裏全部替換為null了,即數據庫的空值。

完成MySQL數據庫數據存儲後,需要關閉數據庫連接:

#關閉遊標,提交,關閉數據庫連接
cursor.close()
db.commit()
db.close()

不關閉數據庫連接,就無法在MySQL端進行數據庫的查詢等操作,相當於數據庫被占用。

三、MySQL數據庫查詢

#重新建立數據庫連接
db = pymysql.connect(localhost, name, password, stockDataBase)
cursor = db.cursor()
#查詢數據庫並打印內容
cursor.execute(select * from stock_600000)
results = cursor.fetchall()
for row in results:
    print(row)
#關閉
cursor.close()
db.commit()
db.close()

以上逐條打印,會淩亂到死的。也可以在MySQL端查看,先選中數據庫:use stockDatabase;,然後查詢:select * from stock_600000;,結果大概就是下面這個樣子了:

技術分享

四、完整代碼

實際上,整個事情完成了兩個相對獨立的過程:1.爬蟲獲取網頁股票數據並保存到本地文件;2.將本地文件數據儲存到MySQL數據庫。並沒有直接的考慮把從網頁上抓取到的數據實時(或者通過一個臨時文件)扔進數據庫,跳過本地數據文件這個過程。這裏只是嘗試著去實現了一下這件事情,代碼沒有做任何的優化考慮。本身不實際去使用,只是樂趣而已,差不多先這樣。哈哈~~

#導入需要使用到的模塊
import urllib
import re
import pandas as pd
import pymysql
import os

#爬蟲抓取網頁函數
def getHtml(url):
    html = urllib.request.urlopen(url).read()
    html = html.decode(gbk)
    return html

#抓取網頁股票代碼函數
def getStackCode(html):
    s = r<li><a target="_blank" href="http://quote.eastmoney.com/\S\S(.*?).html">
    pat = re.compile(s)
    code = pat.findall(html)
    return code
    
#########################開始幹活############################
Url = http://quote.eastmoney.com/stocklist.html#東方財富網股票數據連接地址
filepath = C:\\Users\\Lenovo\\Desktop\\data\\#定義數據文件保存路徑
#實施抓取
code = getStackCode(getHtml(Url)) 
#獲取所有股票代碼(以6開頭的,應該是滬市數據)集合
CodeList = []
for item in code:
    if item[0]==6:
        CodeList.append(item)
#抓取數據並保存到本地csv文件
for code in CodeList:
    print(正在獲取股票%s數據%code)
    url = http://quotes.money.163.com/service/chddata.html?code=0+code+        &end=20161231&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;TURNOVER;VOTURNOVER;VATURNOVER;TCAP;MCAP
    urllib.request.urlretrieve(url, filepath+code+.csv)


##########################將股票數據存入數據庫###########################

#數據庫名稱和密碼
name = root
password = 1234
#建立本地數據庫連接(需要先開啟數據庫服務)
db = pymysql.connect(localhost, name, password, charset=utf8)
cursor = db.cursor()
#創建數據庫stockDataBase,這裏使用了異常處理,避免因數據庫可能已經存在而報錯
try:
    sqlSentence1 = "create database stockDataBase"
    cursor.execute(sqlSentence1)
except Exception as e:
    print(e)
#選擇使用當前數據庫
sqlSentence2 = "use stockDataBase;"
cursor.execute(sqlSentence2)

#獲取本地文件列表
fileList = os.listdir(filepath)
#依次對每個數據文件進行存儲
for fileName in fileList:
    data = pd.read_csv(filepath+fileName, encoding="gbk")
   #創建數據表,如果數據表已經存在,會跳過繼續執行下面的步驟
    try:
        print(創建數據表stock_%s% fileName[0:6])
        sqlSentence3 = "create table stock_%s" % fileName[0:6] + "(日期 date, 股票代碼 VARCHAR(10),     名稱 VARCHAR(10),            收盤價 float,    最高價    float, 最低價 float, 開盤價 float, 前收盤 float, 漲跌額    float,             漲跌幅 float, 換手率 float, 成交量 bigint, 成交金額 bigint, 總市值 bigint, 流通市值 bigint)"
        cursor.execute(sqlSentence3)
    except:
        print(數據表已存在!)

    #叠代讀取表中每行數據,依次存儲(整表存儲還沒嘗試過)
    print(正在存儲stock_%s% fileName[0:6])
    length = len(data)
    for i in range(0, length):
        record = tuple(data.loc[i])
        #插入數據語句
        try:
            sqlSentence4 = "insert into stock_%s" % fileName[0:6] + "(日期, 股票代碼, 名稱, 收盤價, 最高價, 最低價, 開盤價, 前收盤, 漲跌額, 漲跌幅, 換手率,             成交量, 成交金額, 總市值, 流通市值) values (‘%s‘,%s‘,‘%s‘,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)" % record
            #獲取的表中數據很亂,包含缺失值、Nnone、none等,插入數據庫需要處理成空值
            sqlSentence4 = sqlSentence4.replace(nan,null).replace(None,null).replace(none,null) 
            cursor.execute(sqlSentence4)
        except:
            #如果以上插入過程出錯,跳過這條數據記錄,繼續往下進行
            break

#關閉遊標,提交,關閉數據庫連接
cursor.close()
db.commit()
db.close()


###########################查詢剛才操作的成果##################################

#重新建立數據庫連接
db = pymysql.connect(localhost, name, password, stockDataBase)
cursor = db.cursor()
#查詢數據庫並打印內容
cursor.execute(select * from stock_600000)
results = cursor.fetchall()
for row in results:
    print(row)
#關閉
cursor.close()
db.commit()
db.close()

Python爬蟲抓取東方財富網股票數據並實現MySQL數據庫存儲