Python爬虫爬取动态JS网页股票信息

前期准备工作

在本例中使用的是python爬虫需要的两个基础的库,一个是requests库,另一个是BeautifulSoup库。在这里假设已经安装了这两个库,如果没有可以通过pip安装。接下来简单说一下两个库的作用,requests库的主要作用是通过url获取到服务器的前端代码数据,使用这两个库抓取的数据都是服务器的前端代码中的数据。而BeautifulSoup库主要用来从抓取到的前端代码中提取需要的信息。

数据抓取

本次抓取的数据的url为http://quote.eastmoney.com/center/gridlist.html#hs_a_board
建议使用谷歌或者火狐浏览器打开,可以使用快捷键CTRL+U查看服务器的网页源代码。在抓取数据之前需要对数据的格式有大概的了解,首先要抓取的数据必须是在源码中能找到的才能直接抓取到。相信有一点html语言基础的都能看懂个大概,要留意的是,我们可以在源码中看到script的标签,因为JavaScript是在网页加载时动态加载的,所以我们抓取到的源码也显示的是JavaScript的代码,而并非JavaScript加载出来的数据。所以我们在源码中是看不到股票的数据的。所以如果我们直接抓取requests库返回的代码数据,是抓取不到股票信息的。
在这里插入图片描述

解决方法

一种比较特殊的方法就是不直接从目标网站抓取数据,而是找到PC端发出的请求,更改get方法的参数在新的窗口打开请求的资源。通过更改请求参数可以让服务器返回不同的数据。这种方法需要对HTTP协议等原理有所了解。
具体方法是,在需要抓取的数据上右键选择检查,谷歌和火狐都是支持元素检查的。然后可以看到对应的数据在本地是存在的。选择network,选择下面的JS,然后刷新一次,就可以看到get方法的请求。
在这里插入图片描述
通过检查get方法得到的返回数据与前端页面对比,可以发现是一致的。可以直接选择右键鼠标在新的网页打开。但是此时返回的只有一部分数据,并非所有的数据,通过修改get方法的参数可以获取到所有的数据。在此处只修改了np=2即可,至于为什么修改这个参数这里不进一步讨论。修改后的请求如下:http://52.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112405554850877717066_1581422771754&pn=1&pz=20&po=1&np=2&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs=m:0+t:6,m:0+t:13,m:0+t:80,m:1+t:2,m:1+t:23&fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152&_=1581422771755
在这里插入图片描述
可以看到都是结构化的数据,我们直接进行数据抓取即可。可以利用正则表达式匹配对应的数据。我们第一次只能抓取到股票代码等简单的信息,详细的交易信息需要使用http://info.stcn.com/dc/stock/index.jsp?stockcode=’ + '股票代码’才能抓取到,我们同样使用这两个库重复这个过程就可以了,而且可以直接从源码中抓取到,不用再这么麻烦。下面直接上代码

import requests
from bs4 import BeautifulSoup
import re
finalCodeList = []
finalDealData = [['股票代码','今开','最高','最低','昨收','成交量','成交额','总市值','流通市值','振幅','换手率','市净率','市盈率',]]

def getHtmlText(url):
    head={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:70.0) Gecko/20100101 Firefox/70.0',
          'Cookie': 'qgqp_b_id=54fe349b4e3056799d45a271cb903df3; st_si=24637404931419; st_pvi=32580036674154; st_sp=2019-11-12%2016%3A29%3A38; st_inirUrl=; st_sn=1; st_psi=2019111216485270-113200301321-3411409195; st_asi=delete'
         }
    try:
        r = requests.get(url,timeout = 30,headers = head)
        r.raise_for_status()
        r.encoding = 'utf-8'
        return r.text
    except:
        return ""

def getCodeList(htmltxt):
    getSourceStr = str(htmltxt)
    pattern = re.compile(r'.f12...\d{6}.')
    listcode = pattern.findall(getSourceStr)
    for code in listcode:
        numPattern = re.compile(r'\d{6}')
        finalCodeList.append(numPattern.findall(code)[0])

def getData(CodeList):
    total = len(CodeList)
    finished = int(0)
    for code in CodeList:
        finished = finished + 1
        finishedco = (finished/total)*100
        print("total : {0}   finished : {1}    completion : {2}%".format(total,finished,finishedco))
        dealDataList = []
        dataUrl = 'http://info.stcn.com/dc/stock/index.jsp?stockcode=' + code
        dataHtml = getHtmlText(dataUrl)
        soup = BeautifulSoup(dataHtml,"html.parser")
        dealDataList.append(code)
        for i in range(1,4):
            classStr = 'sj_r_'+str(i)
            divdata =soup.find_all('div',{'class':classStr})
            if len(divdata) == 0:
                dealDataList.append('该股票暂时没有交易数据!')
                break
            dealData = str(divdata[0])
            dealPattern = re.compile(r'\d+.\d+[\u4e00-\u9fa5]|\d+.+.%|\d+.\d+')
            listdeal = dealPattern.findall(dealData)
            for j in range(0,4):
                dealDataList.append(listdeal[j])
        
        finalDealData.append(dealDataList)

def savaData(filename,finalData):
    file = open(filename,'a+')
    for i in range(len(finalData)):
        if i == 0:
            s = str(finalData[i]).replace('[','').replace(']','')
            s = s.replace("'",'').replace(',',' \t')+'\n'
        else:
            s = str(finalData[i]).replace('[','').replace(']','')
            s = s.replace("'",'').replace(',','\t')+'\n'
        file.write(s)
    file.close()

url = ' http://51.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112408349318807687469_1574045112932&pn=1&pz=20&po=1&np=2&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs=m:0+t:6,m:0+t:13,m:0+t:80,m:1+t:2,m:1+t:23&fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152&_=1574045112933'
htmltxt = getHtmlText(url)
soup = BeautifulSoup(htmltxt,"html.parser")
getCodeList(soup)
recordfile = 'stockData.txt'
getData(finalCodeList)
savaData(recordfile,finalDealData)

至于其中head的信息,可以通过上述检查元素的方法获得。
在这里插入图片描述我将获取的股票信息存在了txt文件中,并对格式进行了相应的调整,方便查看。最终的结果如下(上次抓取的数据信息)
在这里插入图片描述

小结

在最初进行抓取的时候,因为参考了书上的例子,所以一开始并不知道该题目中要抓取的网页是使用了JavaScript编写的,使用一般抓取静态网页的方法是抓取不到的。我尝试了很多的方法,一开始以为是因为没有加Headers参数,但是加上之后仍然抓取不到,最终在网上查资料的时候发现了一篇介绍反爬虫的文章,其中说明了使用JavaScript编写的网址是抓不到的,并例举出了两种对应的方案。第一种是使用dryscape库进行抓取,第二种是使用selenium库进行抓取。我先尝试了第一种方法,但是因为dryscape库已经不再维护了,所以在安装库的时候就失败了,于是我尝试了第二种方法,使用selenium库进行抓取。使用该方法确实能抓取到数据,但是前提是需要配合浏览器打开页面后才能抓取到,考虑到要抓取的页数太多,不可能一页一页地抓取,所以我又放弃了第二种方法。最后转而分析JavaScript的数据是如何通过JavaScript脚本传到网页前端的,并最终发现了加载页面时JavaScript会有一个请求网址,最终通过这个请求地址找到了想要的数据,并且对参数做一些修改就可以一次性得到所有想要的数据。抓取过程中也遇到了一些问题,最后的抓取过程,因为有一些股票没有交易数据,导致我在抓取这些没有交易数据的股票的时候程序异常报错。最终我加了一个判断,没有交易数据的时候就显示“该股票暂时没有交易数据!”。本次设计过程最终的收获很大,最大的收获还是在于积累了这方面的经验,更重要的是在这个题目设计中解决一个个问题的过程。对我以后面对各种各样的问题也很有帮助和启发。

发布了4 篇原创文章 · 获赞 1 · 访问量 348

猜你喜欢

转载自blog.csdn.net/SELF_REDEEM/article/details/104269532