股票数据定向爬虫-Python网络爬虫与信息提取-北京理工大学嵩天教授

股票数据定向爬虫

一、功能描述

1.目标:获取上交所和深交所所有股票的名称和交易信息;
2. 输出:保存到文件中;
3. 技术路线:requests-bs4-re

二、候选数据网站的选择

1.证券之星:获取所有股票代码列表;
2.网易财经:获取个股信息;
选取原则:股票信息静态存在于HTML页面中,非js代码生成,没有robots协议限制;

三、程序的结构设计

1.从证券之星网获取股票列表;
2.根据股票列表逐个到网易财经获取个股信息;
3.将结果存储到文件;

四、具体代码实现

1.获取网页html文本

def getHTMLText(url):
    try:
        kv = {'user-agent': 'Mozilla/5.0'}   # Mozilla/5.0是一个浏览器的身份标识字段
        r = requests.get(url, headers=kv, timeout=30)   #模拟浏览器对目标网站发送请求
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""

注意:需要模拟浏览器来对目标网站发送请求;
2. 获取所有股票代码数据存进列表中

  • 查看证券之星网站源代码,找到含所有股票代码的位置,如图所示:在这里插入图片描述
  • 故可通过获取所有a标签,再利用正则表达式得到所有股票代码,如下所示:
def getStockList(lst, stockURL):
    html = getHTMLText(stockURL)   #获取html文本
    soup = bs(html, 'html.parser')   #解析文本
    ul = soup.find('ul', attrs={"id": "index_data_0"})   #一共有4大类股,此处查找标识为"index_data_0"的沪A股
    for a in ul('a'):   #遍历ul下的所有a标签
        try:
            href = a.attrs['href']   #获得a标签中的href属性
            stockCode = re.search(r'\d{6}', href).group(0)   #由正则表达式匹配href中6位数的代码
            if stockCode and stockCode not in lst:
                lst.append(stockCode)   #将个股加入到列表lst中
        except:
            continue

3.获取列表中每支股票的详细信息并存入文本文档

  • 查看在网易财经每一支个股的源代码,这里以“600000”为例,查找含有股票信息的代码所在的位置,如图所示:

在这里插入图片描述

  • 故可获得这些信息,分隔存放进字典,如下所示:
def getStockInfo(lst, stockURL, fpath):
    with open(fpath, 'w', encoding='utf-8') as obj:   #使用w模式
        obj.write('')
    count = 0
    for stock in lst:   #遍历列表中的每一支个股
        url = stockURL + '0' + stock + '.html'   #每一支个股的url
        html = getHTMLText(url)
        try:
            if html == '':
                continue   #判断是否空页面
            infoDict = {}   #用字典存储个股信息
            soup = bs(html, 'html.parser')   #返回页面解析的信息
            div = soup.find('div', attrs={'class': 'relate_stock clearfix'})   #股票信息所在位置
            script = div('script')   #div中的script标签
            info = script[0].string.strip().split(',')   #逗号标识分割信息
            infoDict['股票名称'] = eval(re.search(r'name\: \'.*\'', info[0]).group(0).split(':')[1])   # name: '浦发银行'
            infoDict['股票代码'] = eval(re.search(r'code\: \'\d{6}\'', info[1]).group(0).split(":")[1])   #code: '600000',
            infoDict['现价'] = eval(re.search(r'price\: \'.*\'', info[2]).group(0).split(":")[1])   #price: '10.28',
            infoDict['涨跌幅'] = re.search(r'change\: \'.*%', info[3]).group(0).split("'")[1]   #change: '0.19%25',
            infoDict['昨收'] = eval(re.search(r'yesteday\: \'.*\'', info[4]).group(0).split(":")[1])   #yesteday: '10.26',
            infoDict['今开'] = eval(re.search(r'today\: \'.*\'', info[5]).group(0).split(":")[1])   #today: '10.21',
            infoDict['最高'] = eval(re.search(r'high\: \'.*\'', info[6]).group(0).split(":")[1])   #high: '10.41',
            infoDict['最低'] = eval(re.search(r'low\: \'.*\'', info[7]).group(0).split(":")[1])   #low: '10.12',

            with open(fpath, 'a', encoding='utf-8') as obj:
                obj.write(str(infoDict) + '\n')
                count += 1
                print("\r当前进度:{:.2f}%".format(count * 100 / len(lst)), end="")   #持续计数并转换显示为数据爬取进度
        except:
            traceback.print_exc()
            print("\r当前进度:{:.2f}%".format(count * 100 / len(lst)), end="")
            continue

4.主函数

def main():
    tick1 = time.time()   #返回当前时间
    stock_list_url = "http://quote.stockstar.com/stock/stock_index.htm"   #获取所有股票列表的链接
    stock_info_url = "http://quotes.money.163.com/"   #获取个股信息的链接
    outputPath = 'D:\\stockData.txt'   #你所希望列表信息存储的位置
    slist = []
    getStockList(slist, stock_list_url)   #获取股票列表
    getStockInfo(slist, stock_info_url, outputPath)   #获取个股信息
    tick2 = time.time()   #再次返回当前时间
    interval = tick2 - tick1   #得到总共爬取时间
    if interval > 60:
        print("\n程序运行了{0:.2f}分钟".format(interval / 60))   #转换为分钟显示
    else:
        print("\n程序运行了{0:.2f}秒".format(interval))

main()

5.总代码

import re
import time
import traceback

import requests
from bs4 import BeautifulSoup as bs


# 获取网页html文本
def getHTMLText(url):
    try:
        kv = {'user-agent': 'Mozilla/5.0'}   # Mozilla/5.0是一个浏览器的身份标识字段
        r = requests.get(url, headers=kv, timeout=30)   #模拟浏览器对目标网站发送请求
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    except:
        return ""

# 获取所有股票代码数据存进列表中
def getStockList(lst, stockURL):
    html = getHTMLText(stockURL)   #获取html文本
    soup = bs(html, 'html.parser')   #解析文本
    ul = soup.find('ul', attrs={"id": "index_data_0"})   #一共有4大类股,此处查找标识为"index_data_0"的沪A股
    for a in ul('a'):   #遍历ul下的所有a标签
        try:
            href = a.attrs['href']   #获得a标签中的href属性
            stockCode = re.search(r'\d{6}', href).group(0)   #由正则表达式匹配href中6位数的代码
            if stockCode and stockCode not in lst:
                lst.append(stockCode)   #将个股加入到列表lst中
        except:
            continue

# 获取列表中每支股票的详细信息并存入文本文档
def getStockInfo(lst, stockURL, fpath):
    with open(fpath, 'w', encoding='utf-8') as obj:   #使用w模式
        obj.write('')
    count = 0
    for stock in lst:   #遍历列表中的每一支个股
        url = stockURL + '0' + stock + '.html'   #每一支个股的url
        html = getHTMLText(url)
        try:
            if html == '':
                continue   #判断是否空页面
            infoDict = {}   #用字典存储个股信息
            soup = bs(html, 'html.parser')   #返回页面解析的信息
            div = soup.find('div', attrs={'class': 'relate_stock clearfix'})   #股票信息所在位置
            script = div('script')   #div中的script标签
            info = script[0].string.strip().split(',')   #逗号标识分割信息
            infoDict['股票名称'] = eval(re.search(r'name\: \'.*\'', info[0]).group(0).split(':')[1])   # name: '浦发银行'
            infoDict['股票代码'] = eval(re.search(r'code\: \'\d{6}\'', info[1]).group(0).split(":")[1])   #code: '600000',
            infoDict['现价'] = eval(re.search(r'price\: \'.*\'', info[2]).group(0).split(":")[1])   #price: '10.28',
            infoDict['涨跌幅'] = re.search(r'change\: \'.*%', info[3]).group(0).split("'")[1]   #change: '0.19%25',
            infoDict['昨收'] = eval(re.search(r'yesteday\: \'.*\'', info[4]).group(0).split(":")[1])   #yesteday: '10.26',
            infoDict['今开'] = eval(re.search(r'today\: \'.*\'', info[5]).group(0).split(":")[1])   #today: '10.21',
            infoDict['最高'] = eval(re.search(r'high\: \'.*\'', info[6]).group(0).split(":")[1])   #high: '10.41',
            infoDict['最低'] = eval(re.search(r'low\: \'.*\'', info[7]).group(0).split(":")[1])   #low: '10.12',

            with open(fpath, 'a', encoding='utf-8') as obj:
                obj.write(str(infoDict) + '\n')
                count += 1
                print("\r当前进度:{:.2f}%".format(count * 100 / len(lst)), end="")   #持续计数并转换显示为数据爬取进度
        except:
            traceback.print_exc()
            print("\r当前进度:{:.2f}%".format(count * 100 / len(lst)), end="")
            continue

#主函数
def main():
    tick1 = time.time()   #返回当前时间
    stock_list_url = "http://quote.stockstar.com/stock/stock_index.htm"   #获取所有股票列表的链接
    stock_info_url = "http://quotes.money.163.com/"   #获取个股信息的链接
    outputPath = 'D:\\stockData.txt'   #你所希望列表信息存储的位置
    slist = []
    getStockList(slist, stock_list_url)   #获取股票列表
    getStockInfo(slist, stock_info_url, outputPath)   #获取个股信息
    tick2 = time.time()   #再次返回当前时间
    interval = tick2 - tick1   #得到总共爬取时间
    if interval > 60:
        print("\n程序运行了{0:.2f}分钟".format(interval / 60))   #转换为分钟显示
    else:
        print("\n程序运行了{0:.2f}秒".format(interval))

main()

6.爬取结果


当前进度:100.00%
程序运行了26.20分钟

Process finished with exit code 0

在这里插入图片描述
到此,整个爬取就结束了,可见所用时间相比scrapy爬取较长。

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值