目标: 获取上交所和深交所全部股票的名称和交易信息。
输出: 保存到文件中。
技术路线: requests---bs4--re
语言:python3.5html
网站选择原则: 股票信息静态存在于html页面中,非js代码生成,没有Robbts协议限制。
选取方法: 打开网页,查看源代码,搜索网页的股票价格数据是否存在于源代码中。
如打开新浪股票网址:连接描述,以下图所示:python
上图中左边为网页的界面,显示了天山股份的股票价格是13.06。右边为该网页的源代码,在源代码中查询13.06发现没有找到。因此判断该网页的数据使用js生成的,不适合本项目。所以换一个网页。正则表达式
再打开百度股票的网址:连接描述,以下图所示:app
从上图中能够发现百度股票的数据是html代码生成的,符合咱们本项目的要求,因此在本项目中选择百度股票的网址。函数
因为百度股票只有单个股票的信息,因此还须要当前股票市场中全部股票的列表,在这里咱们选择东方财富网,网址为:连接描述,界面以下图所示:网站
查看百度股票每只股票的网址:https://gupiao.baidu.com/stock/sz300023.html
,能够发现网址中有一个编号300023
正好是这只股票的编号,sz
表示的深圳交易所。所以咱们构造的程序结构以下:url
接着查看百度个股信息网页的源代码,发现每只股票的信息在html代码中的存储方式以下:spa
所以,在咱们存储每只股票的信息时,能够参考上图中html代码的存储方式。每个信息源对应一个信息值,即采用键值对的方式进行存储。在python中键值对的方式能够用字典类型。所以,在本项目中,使用字典来存储每只股票的信息,而后再用字典把全部股票的信息记录起来,最后将字典中的数据输出到文件中。code
首先是得到html网页数据的程序,在这里很少作介绍了,代码以下:orm
#得到html文本 def getHTMLText(url): try: r = requests.get(url) r.raise_for_status() r.encoding = r.apparent_encoding return r.text except: return ""
接下来是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
来对程序进行异常处理,代码以下:
for i in a: try: href = i.attrs['href'] lst.append(re.findall(r"[s][hz]\d{6}", href)[0]) except: 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
接下来是得到百度股票网连接描述单只股票的信息。咱们先查看该页面的源代码,以下图所示:
股票的信息就存在上图所示的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
代码中,所以对其进行解析:
soup = BeautifulSoup(html, 'html.parser') 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) try: 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' ) except: continue
其中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 def getHTMLText(url): try: r = requests.get(url) r.raise_for_status() r.encoding = r.apparent_encoding return r.text except: return "" 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 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':'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' ) count = count + 1 print("\r当前进度: {:.2f}%".format(count*100/len(lst)),end="") except: count = count + 1 print("\r当前进度: {:.2f}%".format(count*100/len(lst)),end="") continue 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) main()
上述代码中的print
语句用于打印爬取的进度。执行完上述代码后在D盘
会出现BaiduStockInfo.txt
文件,里面存放了股票的信息。