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库函数,会反应出报错对的地方,不然不知道哪里出错很郁闷
- 有一种设想,从一个网站爬取一定的数据或者项目序列,可以连续的爬取多个同类的网站