功能簡介
目标: 擷取上交所和深交所所有股票的名稱和交易資訊。
輸出: 儲存到檔案中。
技術路線: requests—bs4–re
語言:python3.5
說明
網站選擇原則: 股票資訊靜态存在于html頁面中,非js代碼生成,沒有robbts協定限制。
選取方法: 打開網頁,檢視源代碼,搜尋網頁的股票價格資料是否存在于源代碼中。
如打開新浪股票網址:連結描述(http://finance.sina.com.cn/realstock/company/sz000877/nc.shtml),如下圖所示:
上圖中左邊為網頁的界面,顯示了天山股份的股票價格是13.06。右邊為該網頁的源代碼,在源代碼中查詢13.06發現沒有找到。是以判斷該網頁的資料使用js生成的,不适合本項目。是以換一個網頁。
再打開百度股票的網址:連結描述(https://gupiao.baidu.com/stock/sz300023.html),如下圖所示:
從上圖中可以發現百度股票的資料是html代碼生成的,符合我們本項目的要求,是以在本項目中選擇百度股票的網址。
由于百度股票隻有單個股票的資訊,是以還需要目前股票市場中所有股票的清單,在這裡我們選擇東方财富網,網址為:連結描述(http://quote.eastmoney.com/stocklist.html),界面如下圖所示:
原理分析
檢視百度股票每隻股票的網址:https://gupiao.baidu.com/stock/sz300023.html,可以發現網址中有一個編号300023正好是這隻股票的編号,sz表示的深圳交易所。是以我們構造的程式結構如下:
步驟1: 從東方财富網擷取股票清單;
步驟2: 逐一擷取股票代碼,并增加到百度股票的連結中,最後對這些連結進行逐個的通路獲得股票的資訊;
步驟3: 将結果存儲到檔案。
接着檢視百度個股資訊網頁的源代碼,發現每隻股票的資訊在html代碼中的存儲方式如下:
是以,在我們存儲每隻股票的資訊時,可以參考上圖中html代碼的存儲方式。每一個資訊源對應一個資訊值,即采用鍵值對的方式進行存儲。在python中鍵值對的方式可以用字典類型。是以,在本項目中,使用字典來存儲每隻股票的資訊,然後再用字典把所有股票的資訊記錄起來,最後将字典中的資料輸出到檔案中。
代碼編寫
首先是獲得html網頁資料的程式,在這裡不多做介紹了,代碼如下:
#獲得html文本
def gethtmltext(url):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return ""
接下來是html代碼解析程式,在這裡首先需要解析的是東方财富網頁面:連結描述(http://quote.eastmoney.com/stocklist.html),我們打開其源代碼,如下圖所示:
由上圖可以看到,a标簽的href屬性中的網址連結裡面有每隻股票的對應的号碼,是以我們隻要把網址裡面對應股票的号碼解析出來即可。解析步驟如下:
第一步,獲得一個頁面:
html = gethtmltext(stockurl)
第二步,解析頁面,找到所有的a标簽:
soup = beautifulsoup(html, 'html.parser')
a = soup.find_all('a')
第三步,對a标簽中的每一個進行周遊來進行相關的處理。處理過程如下:
1.找到a标簽中的href屬性,并且判斷屬性中間的連結,把連結後面的數字取出來,在這裡可以使用正規表達式來進行比對。由于深圳交易所的代碼以sz開頭,上海交易所的代碼以sh開頭,股票的數字有6位構成,是以正規表達式可以寫為[s][hz]\d{6}。也就是說構造一個正規表達式,在連結中去尋找滿足這個正規表達式的字元串,并把它提取出來。代碼如下:
for i in a:
href = i.attrs['href']
lst.append(re.findall(r"[s][hz]\d{6}", href)[0])
2.由于在html中有很多的a标簽,但是有些a标簽中沒有href屬性,是以上述程式在運作的時候出現異常,所有對上述的程式還要進行try…except來對程式進行異常處理,代碼如下:
href = i.attrs['href']
lst.append(re.findall(r"[s][hz]\d{6}", href)[0])
continue
從上面代碼可以看出,對于出現異常的情況我們使用了continue語句,直接讓其跳過,繼續執行下面的語句。通過上面的程式我們就可以把東方财富網上股票的代碼資訊全部儲存下來了。
将上述的代碼封裝成一個函數,對東方财富網頁面解析的完整代碼如下所示:
def getstocklist(lst, stockurl):
html = gethtmltext(stockurl)
soup = beautifulsoup(html, 'html.parser')
a = soup.find_all('a')
for i in a:
try:
href = i.attrs['href']
lst.append(re.findall(r"[s][hz]\d{6}", href)[0])
except:
continue
接下來是獲得百度股票網連結描述(https://gupiao.baidu.com/stock/sz300023.html)單隻股票的資訊。我們先檢視該頁面的源代碼,如下圖所示:
股票的資訊就存在上圖所示的html代碼中,是以我們需要對這段html代碼進行解析。過程如下:
1.百度股票網的網址為:https://gupiao.baidu.com/stock/
一隻股票資訊的網址為:https://gupiao.baidu.com/stock/sz300023.html
是以隻要百度股票網的網址+每隻股票的代碼即可,而每隻股票的代碼我們已經有前面的程式getstocklist從東方财富網解析出來了,是以對getstocklist函數傳回的清單進行周遊即可,代碼如下:
for stock in lst:
url = stockurl + stock + ".html"
2.獲得網址後,就要通路網頁獲得網頁的html代碼了,程式如下:
html = gethtmltext(url)
3.獲得了html代碼後就需要對html代碼進行解析,由上圖我們可以看到單個股票的資訊存放在标簽為div,屬性為stock-bets的html代碼中,是以對其進行解析:
stockinfo = soup.find('div',attrs={'class':'stock-bets'})
4.我們又發現股票名稱在bets-name标簽内,繼續解析,存入字典中:
infodict = {}
name = stockinfo.find_all(attrs={'class':'bets-name'})[0]
infodict.update({'股票名稱': name.text.split()[0]})
split()的意思是股票名稱空格後面的部分不需要了。
5.我們從html代碼中還可以觀察到股票的其他資訊存放在dt和dd标簽中,其中dt表示股票資訊的鍵域,dd标簽是值域。擷取全部的鍵和值:
keylist = stockinfo.find_all('dt')
valuelist = stockinfo.find_all('dd')
并把獲得的鍵和值按鍵值對的方式村放入字典中:
for i in range(len(keylist)):
key = keylist[i].text
val = valuelist[i].text
infodict[key] = val
6.最後把字典中的資料存入外部檔案中:
with open(fpath, 'a', encoding='utf-8') as f:
f.write( str(infodict) + '\n' )
将上述過程封裝成完成的函數,代碼如下:
def getstockinfo(lst, stockurl, fpath):
for stock in lst:
url = stockurl + stock + ".html"
html = gethtmltext(url)
if html=="":
continue
infodict = {}
soup = beautifulsoup(html, 'html.parser')
stockinfo = soup.find('div',attrs={'class':'stock-bets'})
name = stockinfo.find_all(attrs={'class':'bets-name'})[0]
infodict.update({'股票名稱': name.text.split()[0]})
keylist = stockinfo.find_all('dt')
valuelist = stockinfo.find_all('dd')
for i in range(len(keylist)):
key = keylist[i].text
val = valuelist[i].text
infodict[key] = val
with open(fpath, 'a', encoding='utf-8') as f:
f.write( str(infodict) + '\n' )
其中try…except用于異常處理。
接下來編寫主函數,調用上述函數即可:
def main():
stock_list_url = 'http://quote.eastmoney.com/stocklist.html'
stock_info_url = 'https://gupiao.baidu.com/stock/'
output_file = 'd:/baidustockinfo.txt'
slist=[]
getstocklist(slist, stock_list_url)
getstockinfo(slist, stock_info_url, output_file)
項目完整程式
# -*- coding: utf-8 -*-
import requests
from bs4 import beautifulsoup
import traceback
import re
return ""
continue
count = 0
count = count + 1
print("\r目前進度: {:.2f}%".format(count*100/len(lst)),end="")
count = count + 1
print("\r目前進度: {:.2f}%".format(count*100/len(lst)),end="")
getstockinfo(slist, stock_info_url, output_file)
main()
上述代碼中的print語句用于列印爬取的進度。執行完上述代碼後在d盤會出現baidustockinfo.txt檔案,裡面存放了股票的資訊。
作者:佚名
來源:51cto