Python 爬虫实战:股票数据定向爬虫

本文作者:hang 本文来源:https://segmentfault.com/a/1190000010520835

功能简介

  • 目标: 获取上交所和深交所所有股票的名称和交易信息。
  • 输出: 保存到文件中。
  • 技术路线: 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来对程序进行异常处理,代码如下:

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

接下来是获得百度股票网链接描述(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代码中,因此对其进行解析:

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文件,里面存放了股票的信息。

原文发布于微信公众号 - 大数据杂谈(BigData07)

原文发表时间:2018-03-29

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FreeBuf

一种几乎无法被检测到的Punycode钓鱼攻击,Chrome、Firefox和Opera等浏览器都中招

国内的安全专家最近发现一种新的钓鱼攻击,“几乎无法检测”,即便平时十分谨慎的用户也可能无法逃过欺骗。黑客可利用Chrome、Firefox和Opera浏览器中的...

2069
来自专栏来自地球男人的部落格

python中scrapy点击按钮

最初遇到的问题的是在用scrapy爬取微博时需要按照指定关键字来爬取特定微博,主要还是解决需要输入关键字然后点击搜索按钮的问题。于是: 首先 找了scrapy的...

3337
来自专栏申龙斌的程序人生

零基础学编程004:集成开发环境IDE

几天前介绍了《用在线编程环境快速上手》学习Python等编程语言,这种教学环境中的例子都非常简单,你不需要在自己的电脑中安装任何的软件,就可以马上动手学习Pyt...

3155
来自专栏CDA数据分析师

用Python爬虫获取自己感兴趣的博客文章

作者 CDA数据分析师 在CSDN上有很多精彩的技术博客文章,我们可以把它爬取下来,保存在本地磁盘,可以很方便以后阅读和学习,现在我们就用python编写一段...

3388
来自专栏CSDN技术头条

NewSQL数据库大对象块存储原理与应用

一、前言 企业内容管理(EnterpriseContent Management,ECM)系统是一种管理非结构化内容的系统,传统代表为EMC Document...

2465
来自专栏北京马哥教育

Python 爬虫实战:股票数据定向爬虫

功能简介 目标: 获取上交所和深交所所有股票的名称和交易信息。 输出: 保存到文件中。 技术路线: requests—bs4–re 语言:python3.5 ...

37611
来自专栏ImportSource

并发编程-多线程的好处

上一文:并发编程-并发的简史 如果线程使用得当,多线程可以降低你的开发和维护成本,而且还能改善复杂应用程序的性能。多线程让模仿人类工作方式以及交互变得简单,多线...

3556
来自专栏前端杂货铺

deno深入揭秘及未来展望

node.js之父Ryan Dahl在一个月前发起了名为deno的项目,项目的初衷是打造一个基于v8引擎的安全的TypeScript运行时,同时实现HTML5...

1631
来自专栏Timhbw博客

iOS面试中被面试官问到的问题答案(一)

2016-03-1016:30:14 发表评论 1,091℃热度 1.请你谈谈static和宏定义的区别。什么时候用static什么时候用宏定义。 让你声...

5478
来自专栏腾讯移动品质中心TMQ的专栏

【腾讯TMQ】和开发一起写代码,让测试左移起来

软件工程中有提到测试人员越早的介入到研发的流程当中,就可以越早的发现问题,从而降低发现问题的成本。因此"左移"变得非常的有必要了起来,当然左移的方式有很多,例如...

4720

扫码关注云+社区