python爬蟲之股票數據定向爬取
功能描述
- 目標:獲取上交所和深交所所有股票的名稱和交易的信息
- 輸出:保存到文件中
- 技術路線:requests-bs4-re
前期分析
- 選取原則:股票的信息靜態存在HTML頁面中,非js代碼生成,沒有robots協議限制
- 選取方法:查看網頁原碼不糾結於某個網站,多找信息源嘗試
沒有成功,價格沒有搜索到
在源碼中搜索價格,不存在
搜索價格沒有
沒有找到相關的價格信息
沒有找到相關價格信息
沒有找到相關的價格信息
多此嘗試之後,發現基本上都沒有找到,於是找教程推薦的
百度股票,已經不見了
- 總結:個人觀點,股票價格這種實時更新的數據怎麼會寫在網頁,大部分應該都是寫在js中,然後又服務器發送相關數據,但是仍舊不失爲一個練習的思路,還是來分析一下吧
教程提供的信息:
-
關於單個股票的信息
- 點擊每個股票的連接,發現會出現相關的跳轉,反映在網址上的變化就是多了幾個關鍵字
- 思路:獲取每個股票的標號,輸入到對應的網址中,即可獲得相關股票的實時價格
- 通過東方財富網獲取所有股票的序號
- 東方財富網的股票的序號
從圖上就可以看出,是在對應的a標籤中,可以採用正則表達式進行篩選r’[zh|sh]\d{6}’
程序編寫
- 第一步,編寫相關的整體步驟
- 從東方財富網獲取股票的列表 getHTMLText(url)
- 根據股票列表逐個到百度股票中獲取個股的信息 getStockList(lst,stockURL)
- 將結果存儲到文件中 getStockInfo(lst,stockURL,fpath)
- main函數將所有的函數連接起來
import requests
import re
from bs4 import BeautifulSoup
# 獲取相關網頁的html文件
def getHTMLText(url):
return''
# 獲取所有股票的序號
def getStockList(lst,stockURL):
return ''
# 獲取所有股票的價格
def getStockInfo(lst,stockURL,fpath):
return ''
def main():
stock_list_url = 'http://quote.eastmony.com/stocklist.html'
# 獲取股票信息序號的網站
stock_info_url = 'https://gupiao.baidu.com/stock/'
# 獲取單個股票的價格的網頁
output_file = 'D://SpiderTest//BaiduStockInfo.txt'
# 文件保存的連接
slist = []
getStockList(slist,stock_info_url)
getStockInfo(slist,stock_info_url,output_file)
main()
-
第二步,逐步完善各個步驟
- 總是必須的獲取相關頁面的代碼
def getHTMLText(url):
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
return r.text
except:
return''
- 獲取相關的股票列表
這裏有值得學習的東西,先獲取所有的a標籤,然後再逐個進行排除,如果是a標籤,那就添加,不是那就跳過當前的循環,學會用try——except語句
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))
except:
continue
- 獲取相關股票實時信息並將之寫入相關的文件
def getStockInfo(lst,stockURL,fpath):
count = 0
for stock in lst:
# 遍歷所有的股票編碼列表
url = stockURL + stock + '.html'
# 生成麼一個股票特定的網頁的信息
html = getHTMLText(url)
try :
if html == '':
# 如果沒有獲取到相關網頁信息,說明網頁沒有意義,那就跳過當前的循環
continue
infoDict = {}
# 創建對應的字典容器,將存儲股票序號——價格的鍵值對信息
soup = BeautifulSoup(html,'html.parser')
# 獲取對應的網頁的信息
stockInfo = soup.find('div',attrs={'class':'bets-name'})
# 結合屬性和名稱,獲取特定的標籤
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')
except:
traceback.print_exc()
continue
- 這裏寫的還是很好看的,分析一下,首先,看下圖,百度股市通中,某單股的原碼
- 清晰可見,關於股票的信息都在對應的< div > … < /div >標籤中,並且屬性中的class是極特殊的class = ‘stock-bets’的
- 而在< div > … < /div >的標籤中的,a標籤的值在對應的就是對應的信息,不同的信息他的屬性又是不同
- 在其子標籤中dt和dd標籤有都含有所有與該股票相關的信息
- 第一步,先獲取最外層最特殊的div標籤,並且說明屬性
stockInfo = soup.find('div',attrs={'class':'stock-bets'})
# 結合屬性和名稱,獲取特定的標籤
- 第二步,提取div標籤的具有相關信息屬性的標籤,這個屬性,就說明了這個標籤代表的內容就是名字或者對應的信息
- 注意:這裏有一個注意點,這裏標籤的text屬性,不是對應的string屬性,text是輸出所有的子節點和自身的string內容,用空格連接
。string僅僅輸出當前節點的string內容,如果有字節點,那就輸出None
詳見 https://www.cnblogs.com/gl1573/archive/2018/11/14/9958716.html
- 注意:這裏有一個注意點,這裏標籤的text屬性,不是對應的string屬性,text是輸出所有的子節點和自身的string內容,用空格連接
name = stockInfo.find_all(attrs={'class':'bets-name'})[0]
infoDict.update({'股票名稱':name.text.split()[0]})
- 第三步,提取所有的dd標籤和dt標籤,二者的數量相同,並作爲鍵值對進行保存
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
- 第四步,採用IO流進行寫入,注意類型的轉換
with open(fpath,'a',encoding = 'utf-8') as f:
f.write(str(infoDict) + '\n')
- 最後一步,就是異常的處理,調用traceback庫,進行異常的處理
except:
traceback.print_exc()
continue
最後一步,代碼的優化
- 爲了創造一個更好的用戶體驗,就創建了寫入一個會實時顯示進度的語塊
count = count + 1
print('\r 當前進度:{:.2f}%'.format(count * 100 / len(lst)),end = "")
‘\r’會將輸出的光標移到開頭,覆蓋原來的輸出
總結
- 關於搜索特定的標籤,不僅僅是結合標籤的名稱,更是要結合標籤的屬性,通過屬性和名稱可以很好的對某一個標籤進行定位
- 關於try—except的處理,要知道引用traceback庫函數,會反應出報錯對的地方,不然不知道哪裏出錯很鬱悶
- 有一種設想,從一個網站爬取一定的數據或者項目序列,可以連續的爬取多個同類的網站