Python3爬蟲抓取東方財富網(wǎng)股票數(shù)據(jù)并實現(xiàn)MySQL數(shù)據(jù)庫存儲

1. 環(huán)境:

  • windows10
  • python3
  • mysql 5.7

2.Python爬蟲抓取網(wǎng)頁數(shù)據(jù)并保存到本地數(shù)據(jù)文件中

開啟mysql數(shù)據(jù)庫
首先導入需要的數(shù)據(jù)模塊娘赴,定義函數(shù):

# -*- coding: utf-8 -*-
"""
Created on Fri Dec 29 15:54:40 2017

@author: JayMo
"""

import urllib
import re
import pandas as pd
import pymysql
import os

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

#抓取網(wǎng)頁股票代碼函數(shù)
def getStackCode(html):
    s = r'<li><a target="_blank" 
    pat = re.compile(s)
    print(pat)
    code = pat.findall(html)
    print(code)
    return code

真正干活的代碼塊:

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

修改url中的end的值孽锥,可爬取截止日期不同的股票數(shù)據(jù)茵瘾。先看下抓取的結(jié)果掷空。CodeList是抓取到的所有股票代碼的集合吵血,我們看到它共包含1416條元素煞赢,即1416支股票數(shù)據(jù)慎璧。因為股票太多床嫌,所以只抓取以6開頭的。
抓取到的股票數(shù)據(jù)會分別存儲到csv文件中胸私,一只股票數(shù)據(jù)一個文件厌处。理論上會有1416個csv文件,和股票代碼數(shù)一致岁疼。


圖片.png

打開一個本地數(shù)據(jù)文件看一下抓取的數(shù)據(jù)長什么樣子:


圖片.png

3. 將數(shù)據(jù)存儲到MySQL數(shù)據(jù)庫

首先建立本地數(shù)據(jù)庫連接:

#數(shù)據(jù)庫名稱和密碼
name = 'xxxx'
password = 'xxxx'  #替換為自己的用戶名和密碼
#建立本地數(shù)據(jù)庫連接(需要先開啟數(shù)據(jù)庫服務)
db = pymysql.connect('localhost', name, password, charset='utf8')
cursor = db.cursor()

其中卓嫂,數(shù)據(jù)庫名稱(name)和密碼(password)是安裝MySQL時設(shè)置的庭敦。

創(chuàng)建數(shù)據(jù)庫,專門用來存儲本次股票數(shù)據(jù):

#創(chuàng)建數(shù)據(jù)庫stockDataBase,如果存在則跳過
sqlSentence1 = "create database if not exists stockDataBase"
cursor.execute(sqlSentence1)#選擇使用當前數(shù)據(jù)庫
sqlSentence2 = "use stockDataBase;"
cursor.execute(sqlSentence2)

在首次運行的時候一般都會正常創(chuàng)建數(shù)據(jù)庫氧吐,但如果再次運行,因數(shù)據(jù)庫已經(jīng)存在剧蚣,那么跳過創(chuàng)建趁窃,繼續(xù)往下執(zhí)行。創(chuàng)建好數(shù)據(jù)庫后字逗,選擇使用剛剛創(chuàng)建的數(shù)據(jù)庫京郑,在該數(shù)據(jù)庫中存儲數(shù)據(jù)表。

下面看具體的存儲代碼:

#獲取本地文件列
fileList = os.listdir(filepath)
#依次對每個數(shù)據(jù)文件進行存儲
for fileName in fileList:
    data = pd.read_csv(filepath+fileName, encoding="gbk")
   #創(chuàng)建數(shù)據(jù)表葫掉,如果數(shù)據(jù)表已經(jīng)存在些举,會跳過繼續(xù)執(zhí)行下面的步驟print('創(chuàng)建數(shù)據(jù)表stock_%s'% fileName[0:6])
    sqlSentence3 = "create table if not exists 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)#迭代讀取表中每行數(shù)據(jù),依次存儲(整表存儲還沒嘗試過)
    print('正在存儲stock_%s'% fileName[0:6])
    length = len(data)
    for i in range(0, length):
        record = tuple(data.loc[i])
        #插入數(shù)據(jù)語句
        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
            #獲取的表中數(shù)據(jù)很亂俭厚,包含缺失值户魏、Nnone、none等挪挤,插入數(shù)據(jù)庫需要處理成空值
            sqlSentence4 = sqlSentence4.replace('nan','null').replace('None','null').replace('none','null') 
            cursor.execute(sqlSentence4)
        except:#如果以上插入過程出錯绪抛,跳過這條數(shù)據(jù)記錄,繼續(xù)往下進行
            break

結(jié)果:


圖片.png
圖片.png

圖片.png

代碼并不復雜电禀,只要注意其中幾個點就好了幢码。

1.邏輯層次:
包含兩層循環(huán),外層循環(huán)是對股票代碼的循環(huán)尖飞,內(nèi)層循環(huán)是對當前股票的每一條記錄的循環(huán)症副。說白了就是按照股票一支一支的存儲店雅,對于每一支股票,按照它每日的記錄一條一條的存儲贞铣。是不是很簡單很暴力闹啦?是的!完全沒有考慮更加優(yōu)化的方式辕坝。

2.讀取本地數(shù)據(jù)文件的編碼方式:
使用'gbk'編碼窍奋,默認應該是'utf8',但好像不支持中文酱畅。

3.創(chuàng)建數(shù)據(jù)表:
同樣的琳袄,如果數(shù)據(jù)表已經(jīng)存在(判斷是否存在if not exists),則跳過創(chuàng)建纺酸,繼續(xù)執(zhí)行下面的步驟(會繼續(xù)存儲)窖逗。有個問題是,有可能數(shù)據(jù)重復存儲餐蔬,可以選擇跳過存儲或者只存儲最新數(shù)據(jù)碎紊。我在這里沒有考慮太多額外的處理。其次樊诺,指定字段格式仗考,后邊幾個字段成交量、成交金額词爬、總市值秃嗜、流通市值,因為數(shù)據(jù)較大缸夹,選擇使用bigint類型痪寻。

4.沒有指定數(shù)據(jù)表的主鍵:
最初是打算使用日期作為主鍵的,后來發(fā)現(xiàn)獲取到的數(shù)據(jù)中竟然包含重復日期的數(shù)據(jù)虽惭,這就打破了主鍵的唯一性橡类,會出bug的,然后我也沒有多去思考數(shù)據(jù)文件的內(nèi)容芽唇,也不會進一步使用這些個數(shù)據(jù)顾画,也就圖省事直接不設(shè)置主鍵了。

5.構(gòu)造sql語句sqlSentence4:
該過程實現(xiàn)中匆笤,直接把股票數(shù)據(jù)記錄tuple了研侣,然后使用字符串格式化(%操作符)。造成的精度問題沒有多考慮炮捧,不知道會不會產(chǎn)生什么樣的影響庶诡。%s有的上邊帶著' ',是為了在sql語句中表示字符串咆课。其中有一個%s'末誓,只有右邊有單引號扯俱,匹配的是股票代碼,只有一邊單引號喇澡,這是因為從數(shù)據(jù)文件中讀取到的字符串已經(jīng)包含了左邊的單引號迅栅,左邊不需要再添加了。這是數(shù)據(jù)文件格式的問題晴玖,為了表示文本形式預先使用了單引號读存。

6.異常值處理:
文本文件中,包含有空值呕屎、None让簿、none等不標準化數(shù)據(jù),這里全部替換為null了榨惰,即數(shù)據(jù)庫的空值拜英。

完成MySQL數(shù)據(jù)庫數(shù)據(jù)存儲后静汤,需要關(guān)閉數(shù)據(jù)庫連接:

#關(guān)閉游標琅催,提交,關(guān)閉數(shù)據(jù)庫連接
cursor.close()
db.commit()
db.close()

不關(guān)閉數(shù)據(jù)庫連接虫给,就無法在MySQL端進行數(shù)據(jù)庫的查詢等操作藤抡,相當于數(shù)據(jù)庫被占用。

4.MySQL數(shù)據(jù)庫查詢

db = pymysql.connect('localhost', name, password, 'stockDataBase', charset='utf8')
cursor = db.cursor()
#查詢數(shù)據(jù)庫并打印內(nèi)容
cursor.execute('select * from stock_600000')
results = cursor.fetchall()
for row in results:
    print(row)
#關(guān)閉
cursor.close()
db.commit()
db.close()

以上逐條打印抹估,會凌亂到死的缠黍。也可以在MySQL端查看,先選中數(shù)據(jù)庫:use stockDatabase;药蜻,然后查詢:select * from stock_600000;

5.完整代碼

實際上瓷式,整個事情完成了兩個相對獨立的過程:1.爬蟲獲取網(wǎng)頁股票數(shù)據(jù)并保存到本地文件;2.將本地文件數(shù)據(jù)儲存到MySQL數(shù)據(jù)庫语泽。并沒有直接的考慮把從網(wǎng)頁上抓取到的數(shù)據(jù)實時(或者通過一個臨時文件)扔進數(shù)據(jù)庫贸典,跳過本地數(shù)據(jù)文件這個過程。這里只是嘗試著去實現(xiàn)了一下這件事情踱卵,代碼沒有做任何的優(yōu)化考慮廊驼。本身不實際去使用,只是樂趣而已惋砂,差不多先這樣妒挎。哈哈~~

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

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

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


##########################將股票數(shù)據(jù)存入數(shù)據(jù)庫###########################

#數(shù)據(jù)庫名稱和密碼
name = 'xxxx'
password = 'xxxx'  #替換為自己的賬戶名和密碼
#建立本地數(shù)據(jù)庫連接(需要先開啟數(shù)據(jù)庫服務)
db = pymysql.connect('localhost', name, password, charset='utf8')
cursor = db.cursor()
#創(chuàng)建數(shù)據(jù)庫stockDataBase
sqlSentence1 = "create database stockDataBase"
cursor.execute(sqlSentence1)#選擇使用當前數(shù)據(jù)庫
sqlSentence2 = "use stockDataBase;"
cursor.execute(sqlSentence2)

#獲取本地文件列表
fileList = os.listdir(filepath)
#依次對每個數(shù)據(jù)文件進行存儲
for fileName in fileList:
    data = pd.read_csv(filepath+fileName, encoding="gbk")
   #創(chuàng)建數(shù)據(jù)表西饵,如果數(shù)據(jù)表已經(jīng)存在酝掩,會跳過繼續(xù)執(zhí)行下面的步驟print('創(chuàng)建數(shù)據(jù)表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('數(shù)據(jù)表已存在!')

    #迭代讀取表中每行數(shù)據(jù)眷柔,依次存儲(整表存儲還沒嘗試過)
    print('正在存儲stock_%s'% fileName[0:6])
    length = len(data)
    for i in range(0, length):
        record = tuple(data.loc[i])
        #插入數(shù)據(jù)語句
        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
            #獲取的表中數(shù)據(jù)很亂期虾,包含缺失值积蜻、Nnone、none等彻消,插入數(shù)據(jù)庫需要處理成空值
            sqlSentence4 = sqlSentence4.replace('nan','null').replace('None','null').replace('none','null') 
            cursor.execute(sqlSentence4)
        except:
            #如果以上插入過程出錯丙笋,跳過這條數(shù)據(jù)記錄御板,繼續(xù)往下進行
            break

#關(guān)閉游標怠肋,提交笙各,關(guān)閉數(shù)據(jù)庫連接
cursor.close()
db.commit()
db.close()


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

#重新建立數(shù)據(jù)庫連接
db = pymysql.connect('localhost', name, password, 'stockDataBase', charset='utf8)
cursor = db.cursor()
#查詢數(shù)據(jù)庫并打印內(nèi)容
cursor.execute('select * from stock_600000')
results = cursor.fetchall()
for row in results:
    print(row)
#關(guān)閉
cursor.close()
db.commit()
db.close()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末础芍,一起剝皮案震驚了整個濱河市杈抢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仑性,老刑警劉巖惶楼,帶你破解...
    沈念sama閱讀 211,423評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诊杆,居然都是意外死亡歼捐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評論 2 385
  • 文/潘曉璐 我一進店門宰缤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颂翼,“玉大人,你說我怎么就攤上這事慨灭‰Γ” “怎么了?”我有些...
    開封第一講書人閱讀 157,019評論 0 348
  • 文/不壞的土叔 我叫張陵镊尺,是天一觀的道長弄砍。 經(jīng)常有香客問我莱坎,道長碴卧,這世上最難降的妖魔是什么烫葬? 我笑而不...
    開封第一講書人閱讀 56,443評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮蒋歌,結(jié)果婚禮上碧绞,老公的妹妹穿的比我還像新娘院峡。我一直安慰自己,他們只是感情好实抡,可當我...
    茶點故事閱讀 65,535評論 6 385
  • 文/花漫 我一把揭開白布俺孙。 她就那樣靜靜地躺著场靴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上苟弛,一...
    開封第一講書人閱讀 49,798評論 1 290
  • 那天囤躁,我揣著相機與錄音,去河邊找鬼。 笑死狸演,一個胖子當著我的面吹牛言蛇,可吹牛的內(nèi)容都是我干的腊尚。 我是一名探鬼主播婿斥,決...
    沈念sama閱讀 38,941評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼哨鸭,長吁一口氣:“原來是場噩夢啊……” “哼民宿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起只估,我...
    開封第一講書人閱讀 37,704評論 0 266
  • 序言:老撾萬榮一對情侶失蹤志群,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蛔钙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锌云,經(jīng)...
    沈念sama閱讀 44,152評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,494評論 2 327
  • 正文 我和宋清朗相戀三年吁脱,在試婚紗的時候發(fā)現(xiàn)自己被綠了桑涎。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,629評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡豫喧,死狀恐怖石洗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情紧显,我是刑警寧澤,帶...
    沈念sama閱讀 34,295評論 4 329
  • 正文 年R本政府宣布缕棵,位于F島的核電站孵班,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏招驴。R本人自食惡果不足惜篙程,卻給世界環(huán)境...
    茶點故事閱讀 39,901評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望别厘。 院中可真熱鬧虱饿,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至爽冕,卻和暖如春仇祭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背颈畸。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評論 1 266
  • 我被黑心中介騙來泰國打工乌奇, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人眯娱。 一個月前我還...
    沈念sama閱讀 46,333評論 2 360
  • 正文 我出身青樓礁苗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親徙缴。 傳聞我的和親對象是個殘疾皇子寂屏,可洞房花燭夜當晚...
    茶點故事閱讀 43,499評論 2 348