与雪球网交互抓取股票数据

这些天写了一个简单的与雪球网交互的小程序,功能是运行后可以获取实时的股票价格,还有股票的历史价格,并将历史价格绘制成走势图。
python在爬虫方面有urllib、requests、BeautifulSoup4等工具库。urllib可用于抓取静态页面的html文本,requests可用于向网页发送请求(get/post)并获取返回的响应,BeautifulSoup库可用于对html页面的解析。

#设置matplotlib中文字体
font = FontProperties(fname=r"c:\\windows\\fonts\\simsun.ttc", size=14) 
#伪装浏览器登录
headers={
    "User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36"
}
#可以写一个url管理器来对url列表进行操作,此处先行指定几个
url=["https://xueqiu.com/S/NVDA","https://xueqiu.com/S/AMD","https://xueqiu.com/S/TSLA","https://xueqiu.com/S/BABA","https://xueqiu.com/S/AAPL"]
#抓取现在股票价格
def get_price(url):
    response=urllib.request.Request(url,headers=headers)
    html=urllib.request.urlopen(response).read().decode("utf-8")
    soup=BeautifulSoup(html,"html.parser")
    name=soup.find("div",class_="stock-name").get_text()
    price=soup.find("div",class_="stock-current").get_text()
    print(name+"现在的股价是:"+price)

雪球网对机器访问进行了限制,因此我在请求时加入了headers,并指定了User-Agent参数,伪装成从浏览器进行登录。我使用了urllib.request的Request方法进行请求,使用urlopen().read().decode()进行UTF-8格式的解码,获得我们可读的html页面。
然后通过bs4的soup.find()方法找到股票名称与价格所在的标签。

然后我只需要调用get_price()函数就可以获取股票价格了。该函数需要输入一个参数,就是该股票的网站地址。我在url列表先行存储了英伟达、AMD、特斯拉、阿里巴巴以及苹果的网址页面。

接下来是抓取股票历史价格,并绘制相关走势图。python最常用的绘图是通过numpy+matplotlib来实现的。numpy是python一个常用的进行科学计算的工具库,可以存储多维数组、进行矩阵运算等等。该程序抓取数据量并不大,暂时也不需要用到numpy。matplotlib是python常用的一个绘图库,绘制折线图、散点图、饼图、直方图等等都非常方便,也具有3D绘图的功能,是很强大的一个拓展库。具体功能可详见官方文档。

#抓取Tesla股票历史价格
history_url="https://finance.yahoo.com/quote/TSLA/history?ltr=1"
Date=[]
Open=[]
High=[]
Low=[]
Close=[]
def get_history_price(url,headers):
    response=urllib.request.Request(url,headers=headers)
    html=urllib.request.urlopen(response).read().decode("utf-8")
    soup=BeautifulSoup(html,"html.parser")
#查找日期,根据data-reactid属性寻找标签
    x=52    
    while x<=1537:
        date=soup.find("td",attrs={"data-reactid":x}).get_text()
        Date.append(date)
        x=x+15
#查找开盘价格
    x=54
    while x<=1539:
        op=soup.find("td",attrs={"data-reactid":x}).get_text()
        Open.append(op)
        x=x+15
#查找高位价格
    x=56
    while x<=1541:
        high=soup.find("td",attrs={"data-reactid":x}).get_text()
        High.append(high)
        x=x+15
#查找低位价格
    x=58
    while x<=1543:
        low=soup.find("td",attrs={"data-reactid":x}).get_text()
        Low.append(low)
        x=x+15
#查找收盘价格
    x=60
    while x<=1545:
        close=soup.find("td",attrs={"data-reactid":x}).get_text()
        Close.append(close)
        x=x+15
    test=soup.find("td",attrs={"data-reactid":54})

雪球网的历史价格点击后会跳转到雅虎金融的页面,此处我选择了特斯拉来做尝试。
我新建了5个空列表Open、Close、High、Low、Date来存储相关的数据。由于该页面取得的Date数据格式为”Jun 30, 2017”这样的字符串,我必须将其转换为matplotlib可以识别的日期格式

#将Date转化为matplotlib可识别的格式
Date.reverse()
Date_new=[]
for d in Date:
    d=d.replace("Dec ","12/")
    d=d.replace("Nov ","11/")
    d=d.replace("Oct ","10/")
    d=d.replace("Sep ","09/")
    d=d.replace("Aug ","08/")
    d=d.replace("Jul ","07/")
    d=d.replace("Jun ","06/")
    d=d.replace("May ","05/")
    d=d.replace("Apr ","04/")
    d=d.replace("Mar ","03/")
    d=d.replace("Feb ","02/")
    d=d.replace("Jan ","01/")
    d=d.replace(", ","/")
    Date_new.append(d)
Date_new=[datetime.strptime(d, '%m/%d/%Y').date() for d in Date_new]
Date=Date_new
Open.reverse()
Close.reverse()

通过进行字符串的拼接,”Jun 30, 2017”就变成了6/30/2017这种格式。由于爬取的日期(以及其他数据)的时间线是往前的,因此使用了reverse将该列表进行倒序。

def print_mat():
    fig1=plt.figure()
    ax1=fig1.add_subplot(1,1,1)
    ax1.xaxis.set_major_formatter(DateFormatter('%m-%d'))#设置时间标签显示格式
    ax1.xaxis.set_major_locator(AutoDateLocator())#设置x轴自动时间刻度
    ax1.yaxis.set_major_locator(AutoLocator())#设置y轴自动刻度
    plt.plot(Date,Open,label="Open",color="red")
    plt.plot(Date,Close,label="Close",color="blue")
    plt.title(u"抓取特斯拉股票历史开盘、收盘价格",fontproperties=font)
    plt.xlabel("时间",fontproperties=font)
    plt.legend()
    plt.show()
print_mat()

在程序开始我指定了字体,否则matplotlib无法正确识别中文。plot是绘制折线图的方法,我使用AutoLocator和AutoDateLocator分别设置了y轴与x轴的刻度,如果忽略此步数据量过大将无法正确显示刻度。
最后的成果如下:

以上。
该程序其实还有很多改进空间。
1.可以编写URL管理器来进行管理。调用get_price()方法或者get_history_price()方法均需输入网址,但是用户需要提前去找的话就不需要该程序了。因此可以编辑一个字典将网址存储起来,例如用户只需要输入”特斯拉”便可以自动输入”https://xueqiu.com/S/AAPL"。
2.编写一个的可视化界面。
3.当抓取数据量庞大时,可以考虑接入数据库。
4.可与itchat联动,每天早上微信自动推送关注股票的信息。
5.可手动指定刻度,提高图片精度
6.想到再加。。。
具体全部代码可移步我的github@APlanckFish。