一个小爬虫

长安大学招生情况分析

一直对爬虫和数据分析感兴趣,最近刚刚也找到一份工作,可以好好来做这件事了。


爬虫部分

2016/10/22
从上学期想自己写一个通过模拟登录来查成绩的程序说起吧。

初衷是因为每次查成绩需要去学校的信息门户查,而信息门户里面的查成绩系统兼容性差的老火的很,只支持古老的IE6,于是每次都需要切换到兼容模式,严重的时候还得到虚拟机用XP = =。所以萌生了模拟登录信息门户,自定义IE6的请求头来查成绩。模拟登录信息门户又是一个曲折的过程,暂且不表了。总之,成功模拟登录后我再去分析查成绩的过程,WTF,信息门户上查成绩居然是调用URP综合教务系统,更令人发指的是此系统的默认用户名和密码都是学号,so…
总之前两天我就想就在想既然高考分数等信息都在教务系统上,那么为什么不去做一下分析呢

接下来就是学号的部分了

学号一开始我的想法是通过规则生成学号,这样的效果就是用了四个for循环。呵呵。。。Fail
But, 昨天, 群里发布了体测的名单,惊喜的发现了有所有人的学号(当时我就这么认为的,事实证明我太naive了),所以今天到了学校,第一件事就是想办法提取excel文件里的数据。
不得不再次感叹一下

Life is short, I use Python

随便搜索一下python xls, 出现了一大堆结果,很容易就发现了xlrd和xlwr, 在这里我只需要安装一下xlrd就好了

pip install xlrd

读取xls部分
然后将数据写到文本里面方便提取

import xlrd

file = xlrd.open_workbook("F://2009.xls")
table = file.sheet_by_index(0)
count = 0
for value in table.col_values(2):
    value += "\n"
    count += 1
    with open("2009.txt", "a") as fh:
        fh.write(value)
print(count)

生成学号部分
然后在爬虫文件里面读取,这里用到了生成器(generator),毕竟数据有点大

def gen_id():
    """This is for 2011-2015
    ***Which is 12 bit
    """
    #Before 2011 is 10 bit
    with open("2009.txt", "r") as fh:
        for line in fh:
            """
            after = ""
            after = line.replace("2013", "2011")
            after = after.replace("\n", "")
            """
            line = line.replace("\n", "")
            yield line

注释掉的部分是将学号中代表入学年份的替换,结果后来证明这个想法也太naive了
模拟登录部分

def login(username):
    result = []
    session = requests.Session()
    base_page = session.get(BASE_URP_URL, headers=HEAD)#, proxies=proxy_)
    """
    if base_page.status_code == 200:
        print("Connection OK! ")
    """
    data = {'zjh':username,'mm':username,'dllx':'dldl'}
    index = session.post(LOGIN_URL,data=data, headers=HEAD)
    """
    if index.status_code == 200:
        print("Login success. ")
    """
    image = session.get(IMG_URL)
    img_content = image.content
    user_info_index = session.get(USER_INFO_URL,headers=HEAD)
    soup = user_info_index.text#content.decode('utf-8')
    result.append(soup)
    result.append(img_content)
    return result

写得渣见谅。本来想用代理的,在网上使用代理API获取了一些可用的代理,但会报

TypeError: can’t mix str and non-str argument

所以就先搁置了
分析部分用的是BeautifulSoup + lxml
数据库
用的是MySQL, 使用了第三方pymysql模块

keys = ""
        values = ""
        for key, value in user_info.items():
            key += ", "
            keys += key
            value = "\'" + value
            value += "\'"
            value += ", "
            values += value
        try:
            cur.execute('INSERT INTO students ({0}) VALUES ({1})'.format(keys.rstrip(", "), values.rstrip(", ")))
        except pymysql.err.IntegrityError as err:
            print("已存在")
        cur.connection.commit()

刚刚才发现百度文库里有完整的学生名单,不说了,我要去重新爬了

Update 10/24
今天早上又爬了一会,但奇怪的是03,10,16级的登陆不上。所以现在的数据只有十一年的,共50422条。
数据条目总数
考虑到目前在校人数除研究生外大概2w余人,出入应该不大。


分析部分

各年份入学人数分析

年份人数
20053442
20063591
20074588
20085039
20095736
20106200(计划)
20115511
20125988
20135844
20145238
20155333

注:

  • 2010只抓到102条数据,舍弃。
  • 斜体加粗代表数据来源于网络。
    入学人数
    在这里用到了可视化数据工具Plotly,调用了其Python的API
import plotly.plotly as py
import plotly.graph_objs as go

py.sign_in('username', 'password')
trace0 = go.Bar(
    x=['2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013', '2014', '2015'],
    y=[3442, 3591, 4588, 5039, 5736, 6200, 5511, 5988, 5844, 5238, 5333],
    #text=['27% market share', '24% market share', '19% market share'],
    marker=dict(
        color='rgb(158,202,225)',
        line=dict(
            color='rgb(8,48,107)',
            width=1.5,
        )
    ),
    opacity=0.6
)

data = [trace0]
layout = go.Layout(
    title='2005-2015招生人数',
)

fig = go.Figure(data=data, layout=layout)
try:
    py.iplot(fig, filename='test')
except KeyError:
    print("Success! ")

从上可以看出,从2005年开始招生人数是逐年上升的,
特别是在2007年进步颇高。
so why?
查看学校的档案馆,发现了2006年有下面几个事件值得关注

  • 一月份学位委员会批准了多个博士点和硕士点
  • 三月份新增一个专业
  • 六月通过211,十五验收
  • 七月行政班子换届;4个专业被授予名牌专业

可以看出,学校招生人数是逐年上升的,10年之后略有下降趋势,但都保持在5000人以上。
各省份录取人数

import pymysql
from collections import OrderedDict
provinces = ('北京', '天津', '上海', '重庆', '河北', '山西', '辽宁', '吉林', '黑龙江', '江苏', '浙江', '安徽', '福建', '江西', '山东', '河南', '湖北', '湖南', '广东', '海南', '四川', '贵州', '云南', '陕西', '甘肃', '青海', '台湾', '内蒙古', '广西', '西藏', '宁夏', '新疆', '香港', '澳门')
conn = pymysql.connect(host="127.0.0.1", port=3306, user="leo", password="mm123456", db="chd", charset='utf8mb4',cursorclass=pymysql.cursors.DictCursor)
cur = conn.cursor()
result = []
tmp = OrderedDict()
tmp1 = {}
for provice in provinces:
    for i in range(2005, 2016):
        cur.execute("select count(*) from chd.students where 入学日期 like '{0}____';".format(str(i)))
        total = cur.fetchone()['count(*)']
        cur.execute("select count(*) from chd.students where 入学日期 like '{0}____' and 考区 = '{1}';".format(str(i), provice))
        people = cur.fetchone()['count(*)']
        tmp[str(i) + ": "] = [people, (people / total)]
    tmp1[provice] = tmp
    result.append(tmp1)
    tmp = OrderedDict()
    tmp1 = {}
cur.close()
conn.close()
print(result)
20052006200720082009201020112012201320142015
山东197(5.72%)197(5.72%)249(5.43%)290(5.76%)300(5.23%)322(5.38%)272(4.65%)252(4.81%)271(4.97%)
山西133(3.86%)158(4.40%)188(4.10%)194(3.85%)220(3.84%)243(4.06%)272(4.65%)248(4.73%)266(4.88%)
河北170(4.94%)152(4.23%)231(5.03%)239(4.74%)289(5.03%)298(4.98%)325(5.56)295(5.63%)313(5.74%)
河南172(5.00%)151(4.20%)249(5.43%)285(5.66%)317(5.53%)370(6.18%)405(6.93%)372(7.10%)372(6.82%)
湖北135(3.92%)131(3.65%)139(3.03%)142(2.82%)162(2.82%)177(2.96%)158(2.70%)152(2.94%)152(2.82%)
湖南104(3.02%)111(3.09%)140(3.05%)152(3.02%)168(2.93%)174(2.91%)167(2.86%)154(2.94%)153(2.81%)
广东24(0.70%)25(0.70%)28(0.61%)26(0.52%)24(0.42%)55(0.92%)62(1.06%)66(1.26%)94(1.72%)
广西62(1.80%)56(1.56%)85(1.85%)83(1.65%)92(1.60%)117(1.95%)140(2.40%)136(2.60%)142(2.60%)
黑龙江66(1.92%)72(2.01%)75(1.63%)83(1.65%)87(1.52%)98(1.64%)75(1.28%)69(1.32%)68(1.25%)
辽宁71(2.06%)68(1.89%)72(1.57%)83(1.65%)92(1.60%)101(1.69%)76(1.30%)62(1.83%)62(1.14%)
浙江121(3.51%)116(3.23%)120(2.62%)139(2.76%)158(2.75%)157(2.62%)136(2.33%)114(2.18%)127(2.33%)
安徽105(3.05%)105(2.92%)172(3.75%)193(3.83%)213(3.71%)225(3.76%)245(4.19%)238(4.54%)253(4.64%)
江苏123(3.57%)116(3.23%)130(2.83%)134(2.66%)146(2.55%)144(2.40%)134(2.29%)128(2.44%)133(2.44%)
福建68(1.98%)61(1.70%)77(1.68%)85(1.69%)101(1.76%)103(1.72%)118(2.02%)103(1.97%)104(1.91)
甘肃77(2.24%)90(2.51%)115(2.51%)148(2.94%)203(3.52%)202(3.37%)239(4.09%)226(4.31%)228(4.18%)
江西66(1.92%)66(1.84%)85(1.85%)87(1.73%)107(1.87%)118(1.97%)112(1.92%)97(1.85)147(2.70%)
云南24(0.70%)24(0.67%)90(1.96%)83(1.65%)98(1.71%)101(1.69%)117(2.00%)122(2.33%)129(2.37%)
贵州28(0.81%)48(1.34%)81(1.77%)98(1.94%)124(2.16%)132(2.20%)145(2.48%)138(2.63%)158(2.90%)
四川93(2.70%)76(2.12%)97(2.11%)117(2.32%)116(2.02%)118(1.97%)125(2.14%)121(2.31%)153(2.81%)
青海55(1.60%)60(1.67%)69(1.50%)85(1.69%)96(1.67%)109(1.82%)95(1.63%)65(1.24%)52(1.00%)
陕西1106(32.13%)1168(32.53%)1429(31.15%)1575(31.26%)1724(30.06%)1716(28.66%)1557(26.64%)1358(25.93%)1321(24.23%)
吉林73(2.12%)76(2.12%)89(1.94%)87(1.73%)103(1.80%)101(1.69%)91(1.56%)80(1.53%)93(1.71%)
宁夏52(1.51%)64(1.78%)73(1.59%)85(1.69%)115(2.00%)124(2.07%)109(1.87%)72(1.37%)83(1.52%)
海南8(0.23%)14(0.39%)14(0.31%)25(0.50%)39(0.68%)50(0.84%)41(0.70%)34(0.65%)37(0.68%)
西藏9(0.26%)19(0.53%)20(0.44%)27(0.54%)31(0.54%)14(0.23%)13(0.25%)13(0.24%)
内蒙古78(2.27%)79(2.20%)104(2.27%)103(2.04%)120(2.09%)126(2.10%)120(2.05%)107(2.04%)102(1.87%)
新疆80(2.32%)113(3.15%)155(3.38%)174(3.45%)244(4.25%)248(4.14%)244(4.18%)190(3.63%)200(3.67%)
北京33(0.96%)33(0.92%)33(0.72%)37(0.73%)44(0.77%)40(0.67%)35(0.60%)33(0.63%)25(0.46%)
天津42(1.22%)60(1.67%)67(1.46%)70(1.39%)97(1.69%)95(1.59%)70(1.20%)73(1.39%)63(1.16%)
上海0(0.00%)3(0.08%)2(0.04%)1(0.02%)0(0.00%)0(0.00%)10(0.17%)17(0.29%)14(0.27%)
重庆67(1.95%)70(1.95%)91(1.98%)96(1.91%)103(1.80%)99(1.65%)97(1.66%)88(1.68%)114(2.09%)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值