爬取东方财富网的部分股票信息(1)

爬取东方财富网的部分股票信息(1)

目标:爬取东方财富网的部分股票的名称、代码、涨跌幅、融资余额、融资融券余额、股东户数
编程语言:Python 3.7
开发IDE:Visual Studio 2019
看惯了小黑框,也喜欢VS2019的界面设计,所以没有用主流的Python开发IDE

  • 东方财富网里有上海股票和深圳股票,我不懂股票,所以就只爬取上海股票中以“6”开头的股票了。
    直接进东方财富网的官网没有直接的显示所有股票,但我找了一下,发现了显示所有股票名称和代码的地方——东方财富网所有股票信息(http://quote.eastmoney.com/stock_list.html),我们先去看看这个网页的源代码

在这里插入图片描述
可以看到股票名称和代码都在一个”li“标签里,我们只要取到这些”li"标签里的值就行了。我们ctrl+f找一下有多少个“li”标签,结果显示有10326个,我们只要其中包含股票信息的那部分,所以直接抓“li”标签是行不通的。那我们就看这些“li”标签的父标签是什么,发现父标签是“ul”标签,搜索发现“ul”标签有34个,但我们只要有股票信息的那个,所以直接抓“ul”标签也不行。那就看这个“ul”标签的父标签,发现是一个id为“quotesearch”的“div”标签,而且整个网页的源代码中只有一个id为“quotesearch”的“div”标签。那我们直接去抓这个“div”标签,然后找到其中的所有“li”标签就能爬到股票的名称和代码了。
(我这里用的是requests库里的get方法来爬取数据,这个方法只适用于数据量比较小的爬虫,所以不能爬取到所有的以“6”开头的股票。如果要爬取东方财富网所有的股票信息,建议用Scrapy框架,这个适用于数据量大的爬虫)
爬取代码如下:

url = 'http://quote.eastmoney.com/stock_list.html'
html = requests.get(url)
soup = BeautifulSoup(html.content,'lxml')
a = soup.find("div",attrs = {"class":"quotebody"}).find_all("li")

我们把它打印出来看一下:
在这里插入图片描述
到这里还没有结束,我们只要股票名称和代码,不需要多余的HTML代码,所以用一个for循环取出内容。
在这里插入图片描述
到这里总算有点成就感了,接下来进一步处理我们爬出来的这些股票信息

  • 随便点开一个股票的具体界面,可以看到一个“融资融券”的超链接,点进去可以看到这只股票的历史涨跌幅、融资余额、融资融券余额等,但没有股东户数。那就放开股东户数,先把我们要的涨跌幅、融资余额、融资融券余额爬出来。
    在这里插入图片描述
    查看网页的源代码,发现表格里的数据不是直接写在网页里的,也就是说我们不能像爬股票名称和代码那样通过get方法直接抓数据。这些数据是通过“script”标签异步加载js来显示的,是动态显示的一种方法,现在的大部分网站都用这种方法来实现数据的更新。以前的网站没有用这种方法,所以要看到更新后的数据只能刷新网页。所以当你点开网页的时候,浏览器会向服务器发送请求,然后获得的响应就是这些数据,我们按F12进入调试模式,找到网络这一按钮,选择全部。然后就能看到很多请求项。在这里插入图片描述
    再点击下一页,让浏览器向服务器发起一次新的请求,我们在网络里就可以看到新的请求项出现。新出现的请求项里就有下一页的数据,我们找到这一请求项。在这里插入图片描述
    然后在浏览器里打开右边的请求url链接,如下图。
    在这里插入图片描述
    然后我们直接用get方法去抓这个链接就可以得到具体的json数据了。

  • 现在的问题就是要生成这个包含json数据的url了,每一个股票的每一页数据都是一个新的url。观察同一只股票的不同数据页的url,发现只有链接中的“p=”后的数字变了,这个数字表示第几页数据。
    用我选的这只股票为例:
    http://datacenter.eastmoney.com/api/data/get?——p=2——&rt=53149371是第二页数据
    http://datacenter.eastmoney.com/api/data/get?——p=3——&rt=53149371是第三页数据
    http://datacenter.eastmoney.com/api/data/get?——p=4——&rt=53149371是第四页数据
    用一个循环来改变“p=”后面数字的值来生成不同页的url。

  • 如果是不同股票呢?同样观察url,发现其中蕴含了股票代码,就是“scode=”后面双引号里的代码,改变这个代码就对应新的股票数据url。然后再来一个循环改变股票代码,来生成不同股票信息的url。
    这时我们之前爬取到的股票名称和股票代码就有用了,但我们之前爬到的都是“股票名称(股票代码)”这样的格式,现在只要其中的股票代码,那只把括号里的内容取出来就行了嘛。

  • 同样用一个循环来提取爬到的字符串中括号里的内容,代码如下:

for k in a:
    if(k.get_text() != ""):
        Stock_Number = re.findall(r'[(](.*?)[)]',k.get_text())
        Stock_Name = re.sub('\(.*?\)','',k.get_text())
        first_number = Stock_Number[0]
        print(Stock_Name,Stock_Number,first_number)
    else:continue  

这里用一个if语句来判断是否为空,不写的话会报错,因为for语句会多循环一次,多处理一次为“空”的字符串。这里用了两次正则表达式来匹配需要的内容,第一次是找到括号里的内容,第二次是去掉括号和括号里的内容。这样我们就把股票名称和股票代码成功分开了,可以用来生成数据的url了。(re函数返回的是列表,因为我们只有一项,所以取Stock_Number[0])

  • 接下来就是url的生成了,代码如下:
if first_number[0:1] == '6' :
        part1 = 'http://datacenter.eastmoney.com/api/data/get?type=RPTA_WEB_RZRQ_GGMX&sty=ALL&source=WEB&p='
        part2 = '&ps=50&st=date&sr=-1&filter=(scode=%22'
        part3 = '%22)&rt=53137855'
        data_page = 0
        while(data_page < 7):
            data_page = data_page + 1
            dataurl = part1 + str(data_page) + part2 + first_number + part3
        else: continue

因为我们要的是以“6”开头的股票,所以要筛选一下,这里我选则爬取前七页的数据,应该是从2018年末开始的数据。这里的url被我做了一点处理,去掉了原始请求url的一部分东西。据我观察发现用浏览器打开请求url时开头会出现一个“var xxxxx = ”格式的东西,其中xxxxx代表的东西请求url里也出现过,然后我去掉了这个xxxxx,发现还是可以打开json数据,只不过开头的“var xxxxx = ”消失不见了。
为什么要这么做?之后会解答。

  • 然后就是用这个url去爬取数据了,代码如下:
if(requests.get(dataurl)):
                datahtml = json.loads(requests.get(dataurl).text)
                number = 0
                if(datahtml['result']):
                    while(number < len(datahtml['result']['data'])):
                        ##日期
                        Stock_Date = datahtml['result']['data'][number]['DATE'][0:10]
                        ##收盘价
                        Stock_SPJ = float(datahtml['result']['data'][number]['SPJ'])
                        ##涨跌幅
                        if(datahtml['result']['data'][number]['ZDF'] != None):
                            Stock_ZDF = float(datahtml['result']['data'][number]['ZDF'])
                        else:Stock_ZDF = 0
                        ##融资余额
                        Stock_RZYE = float(datahtml['result']['data'][number]['RZYE'])
                        ##融资融券余额
                        Stock_RZRQYE = float(datahtml['result']['data'][number]['RZRQYE'])
                        print(Stock_Name,Stock_Number,Stock_Date,Stock_SPJ,Stock_RZYE,Stock_RZRQYE)
                        number = number + 1
                else:break

这里要注意的就是json.loads()这个方法,目的是把json转换为python对象。而且括号里的内容要严格遵循json的格式,不然会报错。所以上面去掉url里的东西就为了符合json的格式,而且直接用原始请求url时get到的json内容结尾会有个“;”,和json的格式不符,要去掉“;”才能被json.loads()方法正常处理

  • 再观察获得的json内容,发现我们需要的数据都在"result"的"DATE"、“RZYE”、“RZRQYE”、“ZDF”、"SPJ"这几个键值对里。那我们直接取就行了。

但这里要注意几个问题:

  1. 不是所有的股票都有融资融券的,有些股票用我们生成的url去抓的时候"result"对应的值为null,也就是没有内容,那接下来的处理就没有意义了,要规避这个错误。
  2. 和①相同的道理,不是所有的股票都有我们需要的这几个数据的。(从600000开始,我总共只试着爬了不到100只股票,发现有只股票在某个时间段里没有涨跌幅,所以我加了一个if,其他的还没有发现有缺少数据的情况,所以我没加if。考虑到这点应该都加一个if来判断是否为空,防止程序出错)
  3. 不是所有股票都有超过七页数据的,有些股票可能只有四页或五页数据,在程序中要规避这个错误。
  4. 每页数据中有50个日期,但还有些股票一页中不足五十个日期,直接循环50次程序会报错。
  • 为了避免以上问题,要对程序做出适当的调整,具体方法都体现在上面的代码中了。
    (这些问题都是基于前几十只股票发现的,后面的股票有可能出现其他问题)

到这里所要的数据就只剩一个股东户数了,我会在下一个文章里具体聊聊怎么爬股东户数,和这次爬的方法略有不同。
来看一下我们目前取得的成果吧:
截图一

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值