[Python数据采集]股票信息采集

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

前言

本文将介绍通过抓包的方式,获取使用js进行动态渲染的网站数据爬取,并以股票信息数据为例,进行实战操作。

股票信息采集

要求:用requests和自选提取信息方法定向爬取股票相关信息,并存储在数据库中。

思路:

1. 抓包

由于该网页属于动态渲染网页,数据通过ajax进行动态渲染,因此需要进行抓包。

打开F12并刷新,获取浏览器发送的js请求。

如下进行解析:

  1. 随便复制一个股票名称;

  2. 启动搜索,粘贴复制的股票名称;

  3. 搜索栏中出现一个(或多个 -> 随着时间会进行额外的数据刷新请求)含有该页所有股票代码信息的请求接口;

  4. 右侧Response中可以预览到所有数据。

 2. 参数解析

上步中获取到的接口url如下:

http://67.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112407972169804676412_1634974778877&pn=1&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs=m:0+t:6,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&_=1634974778878
复制代码

可以看到,在url后,跟着很多get参数,可以对参数进行修改来完善爬虫。

因此我进行了一些尝试(请求经过验证,均与实际页面相匹配):

首先,最先看到的是pn和pz两个参数。

在后端编写接口中,一般都会使用page_num和page_size对应页码和分页大小,pn和pz则是这两个变量的缩写。

然后是cb=jQuery.......参数。

jQuery是基于js的一个框架,虽然对前端这块不太了解,但是一般情况,前后端分离项目需有一定的请求规范,而爬取到的接口细看是在Restful API的基础上添加一层jQuery函数封装。

可以大胆推测,该接口是专门对jQuery进行的适配,而用于控制这个适配可能性最高的参数就是cb参数(因为里面出现了jQuery)。

删除后,接口数据使用json格式进行返回(这后端接口不规范):

很直观的看出,data中的diff对应是一个list类型数据,启动包含的 f* 就是我们所需要数据。 接着是数据范围限定

经过人工比对,各字段和参数名对应表如下:

股票代码 f12
名称 f14
最新报价 f2
涨跌幅 f3
涨跌额 f4
成交量 f5
成交额 f6
振幅 f7
最高 f15
最低 f16
今开 f17
昨收 f18

最后是其他一些未知作用的参数,可能是后端进行埋点使用,逐个进行筛选,去掉不必要参数,最后,参数添加如下:

    # 需要的参数,其他的参数就不需要请求了
    needParams = ['f12', 'f14', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f15', 'f16', 'f17', 'f18']
    fields = ",".join(needParams)   # 合并成fields参数

    # 输入分页相关参数限定爬取数量和范围,fid为股票种类(f3为目的),fields限定返回参数
    # 和爬取到的接口相比,去掉了cb=jQuery....参数,就可以直接返回json格式数据
    url = f'http://60.push2.eastmoney.com/api/qt/clist/get' \
          f'?pn={pageNum}' \
          f'&pz={pageSize}' \
          f'&po=1&np=1&fltt=2&invt=2' \
          f'&fid={fid}&fs=m:1+s:2' \
          f'&fields={fields}'
复制代码

(po=1&np=1&fltt=2&invt=2作用未知,但是删除将导致请求未空)

3. 数据库构建

db = DB()
db.driver.execute('use spider_test')
db.driver.execute('drop table if exists money')
sql_create_table = """ CREATE TABLE `money` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `code` varchar(64) DEFAULT NULL,
      `name` varchar(64) DEFAULT NULL,
      `zxbj` varchar(64) DEFAULT NULL,
      `zdf` varchar(64) DEFAULT NULL,
      `zde` varchar(64) DEFAULT NULL,
      `cjl` varchar(64) DEFAULT NULL,
      `cje` varchar(64) DEFAULT NULL,
      `zf` varchar(64) DEFAULT NULL,
      `high` varchar(64) DEFAULT NULL,
      `low` varchar(64) DEFAULT NULL,
      `jk` varchar(64) DEFAULT NULL,
      `zs` varchar(64) DEFAULT NULL,
      PRIMARY KEY (`id`)
    )ENGINE=InnoDB DEFAULT CHARSET=utf8; 
"""
db.driver.execute(sql_create_table)
复制代码
原则上,数据库字段名不应该出现中文字符,因此,数据库命名看着有些随意。
插入操作和作业一中大同小异,这里就不再展示了。
复制代码

4. 结果展示

当前只创建一张数据表进行实验,如有实际需求需要使用按时间对表进行划分,不能把所有时间段数据杂在一张表内(不然没有意义)。

另外,仅保存源数据信息,方便数据分析或可视化操作,数据转义(加%或加万、亿等)不应该在数据库中进行。