老菜鸟学PYthon - 高考志愿填报数据的实时采集

一直想学习Python,又一直懒,直到今年高考志愿填报开始,在跟进学习的过程中发现了很多高分却报漏未被录取或没有报上的情况。(自家小子今年下半年开始高三生涯)

学习目的:2022年7月开始的高考志愿填报时,抓取院校信息、专业信息、每小时更新的志愿填报信息,综合分析意向学校的意向专业的录取分数变化情况。

背景说明:我所在内蒙古是全国唯一一个实时网报、实时排名的报考模式。

数据来源:以下学习过程中所使用的数据均为2021年内蒙古志愿填报提前批数据。


开始下载安装PYthon3.5.2、mysql5.6,而python的学习也从网上搜到的两段代码开始......

import json

prices = {
	'ACME': 45.23,
	'AAPL': 612.78,
	'IBM': 205.55,
	'HPQ': 37.20,
	'FB': 10.75
}

with open('price.json', 'w') as f:
	json.dump(prices, f)
	f.close()

上面这段,是把数据写入json文件。

下面这段,是从json文件读取数据。

import json

with open('price.json', 'r') as f:
	a = json.load(f)  # 此时a是一个字典对象
	print(a)
	print(a['ACME'])
	f.close()

有了上面两段代码的例子打底,开干。


数据来源 → 内蒙古教育招生考试中心 ,地址:

https://www.nm.zsks.cn/21gkwb/gktj_21_11_61_19/tj/tjyx.html?path=Bicon-default.png?t=L892https://www.nm.zsks.cn/21gkwb/gktj_21_11_61_19/tj/tjyx.html?path=B

院校名称超链接为学校在内蒙古所招生专业及人数,已报人数超链接为已报该学校的考生分数及考生所报志愿。

F12 → 网络 → ctrl+r 后,发现数据来源是

https://www.nm.zsks.cn/21gkwb/gktj_21_11_61_19/data/tjyx.jsonicon-default.png?t=L892https://www.nm.zsks.cn/21gkwb/gktj_21_11_61_19/data/tjyx.json下载文件到本地,开始折腾。


import json
import re
with open('tjyx.json','r',encoding='UTF-8') as f:
      aa = json.load(f)
      i=0
      while i< len(aa):
            bb=aa[i]
            print (bb['yxmc'])
            i +=1
      f.close()

循环读取json文件内容实现。↑

import pymysql
import time

#连接数据库参数
conn = pymysql.connect(
    host='localhost',
    port=3306,
    user='root',
    password='168168',
    database='2021.08.10',
    charset='utf8'
)

# 获取一个光标
cursor = conn.cursor()

# 获取当前时间 2020011011
atime=time.strftime("A%Y%m%d%H", time.localtime())

# 判断 atime 表是否存在
sql1 = 'DROP TABLE IF EXISTS {}'
sql2 = sql1.format(atime)
cursor.execute(sql2)

# 创建 atime 数据表

# 涉及写操作要注意提交
conn.commit()

# 关闭连接
cursor.close()
conn.close() 

数据库连接实现,实时数据表名实现。同时根据json创建数据表并调整数据结构。↑

# 创建 atime 数据表
sql3 = 'CREATE TABLE {} (path varchar(10),yxmc varchar(20),zf int(1),syjh int(1),lqzdf int(1),pcmc varchar(20),tdzdf1 int(3),ykb int(1),jhs int(3),yxdh varchar(10),klmc varchar(10),qdrs int(1),zt int(1),kldm varchar(10),ycdrs int(1),stdbl varchar(10),tj_zf int(1),xznx int(1),ybrs int(3),tdbl int(1),tdzdf int(3))'
sql = sql3.format(atime)
cursor.execute(sql)
print ("数据表 "+atime+" 创建完毕")

创建数据表实现。↑


# 定义json数据路径
adata=json.loads(requests.get("https://www.nm.zsks.cn/21gkwb/gktj_21_11_61_19/data/tjyx.json").text)

修改了json的获取方式,直接自url获取,规避了下载到本地再读取的xx行为。↑

# 自json提取院校数据
i=0
while i< len(adata):
      bdata = adata[i]
      sql1 = "INSERT INTO {} (path,yxmc,zf,syjh,lqzdf,pcmc,tdzdf1,ykb,jhs,yxdh,klmc,qdrs,zt,kldm,ycdrs,stdbl,tj_zf,xznx,ybrs,tdbl,tdzdf) VALUES ('{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}','{}')"
      sql = sql1.format(atime,bdata['path'],bdata['yxmc'],bdata['zf'],bdata['syjh'],bdata['lqzdf'],bdata['pcmc'],bdata['tdzdf1'],bdata['ykb'],bdata['jhs'],bdata['yxdh'],bdata['klmc'],bdata['qdrs'],bdata['zt'],bdata['kldm'],bdata['ycdrs'],bdata['stdbl'],bdata['tj_zf'],bdata['xznx'],bdata['ybrs'],bdata['tdbl'],bdata['tdzdf'])
      cursor.execute(sql)
      i +=1
print ("共提取 " + str(i) + " 条院校数据,并写入 " + atime +" 数据表。")

院校数据提取并写入mysql实现。↑

而后照方抓药,实现了专业数据的提取及写入数据库。不同的是专业数据来源于

https://www.nm.zsks.cn/21gkwb/gktj_21_11_61_19/data/tjzy.jsonicon-default.png?t=L892https://www.nm.zsks.cn/21gkwb/gktj_21_11_61_19/data/tjzy.json期间遇到的问题:院校数据的zszc变量部分学校为空,提取并写入数据库时遇到就会卡壳报错;专业数据的bxdd、xf、bz 三个变量也存在上述情况。这个问题困扰了我几天,在网友的指点下,成功解决。

Python 字典(Dictionary) get()方法icon-default.png?t=L892https://www.runoob.com/python/att-dictionary-get.html

修改代码后的运行结果如下:

 下一步按这个方法完善好院校数据、专业数据的抓取,并开始已报志愿数据的抓取。


经历了无人报考院校采集报错问题,就python这个莫名其妙的错误提示,哎

最后还是按数据比对,才发现无人填报院校报错

 

 因为无人填报,所以json文件不存在,遇到这个坑python直接就over了。

磕磕绊绊,数据采集的目标达成。


学习成果展示

01 - 所有抓取到的数据(包含院校、专业、志愿填报)

02 - 院校数据

 03 - 专业数据

 04 - 志愿填报数据 这里以294为例 共619人填报

有人知道院校代码294是哪所学校吗?

※※※至此,最初制定的数据采集目标已经实现。接下来会是两个方面:

1、采集到库里的数据的实时可视化;

2、采集功能的优化,毕竟现在只能算是勉强能用,离好用还很远。


问题来了,随机性在读取json文件时出现无响应,PYthon报错并中止运行。

 反复学习、测试,总算是解决了数据抓取超时的问题。解决此问题后的运行效果

 经多次测试,遇到json读取异常后重试读取都能顺利执行

具体解决方式如下

class Http():
     
    def get_html(self,url,path):
        try:
            return self.__request(url)
        except:            
            secends = random.randint(1, 3)
            print(path+'数据读取异常,'+ str(secends) + '秒后重试')
            time.sleep(secends)   # 暂停1~3秒,然后再尝试一次
            try:
                print('重试数据读取......')
                return self.__request(url)
            except:
                print(path+'数据读取再次异常,'+ str(secends) + '秒后跳过')
                time.sleep(secends)   # 暂停1~3秒,然后跳过
                return ''
 
                
    def __request(self, url):
        response = requests.get(url, timeout=(5, 15)) 
        response.encoding ='utf-8'
        return response.text

通过以上方式,实现了python抓取数据无响应后重新抓取的功能。

后续思路:如重复抓取依然失败,可加入循环实现多次抓取,不过目前看无此必要。

至此,数据采集部分告一段落,下一步开始构思数据匹配。


版权声明:本文为weixin_43975834原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。