前言

该篇是之前遗漏的大三上的Python课程设计。刚好今天有空就补发了一篇文章。全部的代码在最后附录中。爬虫类的代码直接全部放到一起了,读者可以自行研究。百度网盘可以私聊我进行获取。

一、课程设计项目说明

该课程设计项目亮点:

1、使用Python获取NBA每一年的比赛季后赛常规赛等部分项目中需要的比赛统计数据并输出成csv格式的文件。

二、课程设计项目功能

首先可通过Python获取的任意年度的球队数据,保存在本地文件夹后,更改名为“nwz”的代码中的路径folder为数据文件路径,即可导入球队各类数据而后进行特征向量、逻辑回归、球队的EloScore计算等机器学习,最终将预测的比赛结果输出到特定路径下的格式为.csv的文件查看比赛预测结果。

三、项目所需数据文件

本项目中一共需要5张数据表,分别是Team Per Ganme Stats(各球队每场比赛数据统计)、Opponent Per Game Stats(对手平均平常比赛的数据统计)、Miscellaneous Stats(各球队综合统计数据表)、2015-2016 NBA Schedule and Results(2015-16赛季比赛安排与结果)、2016-2017 NBA Schedule and Results(2016-2015赛季比赛安排)。

四、项目原理介绍

1、比赛数据介绍

本项目中,采用来自某网站的数据。可以获取到任意球队、任意球员的各类比赛统计数据,如得分、投篮次数、犯规次数等等。

我们主要使用2015-16赛季中的数据,分别是:
Team Per Ganme Stats表格:每支队伍平均每场比赛的表现统计;
Opponent Per Game Stats表格:所遇到的对手平均每场比赛的统计信息,所包含的统计数据与 Team Per Game Stats 中的一致,只是代表的是该球队对应的对手的统计信息;
Miscellaneous Stats:综合统计数据。

Team Per Game Stats表格、Opponent Per Game Stats表格、Miscellaneous Stats表格(在NBA网站中叫做“Advanced Stats”)中的数据字段含义如下图所示。


除了上述的三张表外,还需要另外两张表数据,分别是:
2015-2016 NBA Schedule and Results:2015-2016 年的 NBA 常规赛及季后赛的每场比赛的比赛数据;2016-2017 NBA Schedule and Results 中 2016-2017 年的 NBA 的常规赛比赛安排数据。

在获取到数据之后,需要对表格的字段做出更改如下图所示。
表格数据字段含义说明:Vteam: 客场作战队伍。Hteam: 主场作战队伍

故综上所述一共需要5张NBA数据表。如下图所示。

2、数据分析原理

在获取到五个表格数据之后,将利用每支队伍过去的比赛情况和 Elo 等级分来分析每支比赛队伍的胜利概率。

分析与评价每支队伍过去的比赛表现时,将使用到上述五张表中的三张表,分别是 Team Per Game Stats、Opponent Per Game Stats 和 Miscellaneous Stats(后文中将简称为 T、O 和 M 表)。

这三个表格的数据,作为代表比赛中某支队伍的比赛特征。代码将实现针对每场比赛,预测哪支队伍最终获胜,但这并不是给出绝对的胜败情况,而是预判胜利的队伍有多大的获胜概率。

因此将建立一个代表比赛的特征向量。由两支队伍的以往比赛统计情况(T、O 和M表)和两个队伍各自的 Elo 等级分构成。

3、Elo Score等级分制度

Elo 机制现在广泛运用于网络游戏或竞技类运动中,根据Elo等级分制度对各个选手(玩家)进行登记划分。如王者荣耀、篮球、足球比赛等等。Elo Score等级分制度本身是国际象棋中基于统计学的一个评估棋手水平能力的方法。

通过Elo制度来计算选手(玩家)的胜率期望值的原理过程如下:

假设A与B当前的等级制度分为与,那么A对B的胜率期望值为:


B对A的胜率期望值为:


如果A在比赛中真实得分与他的胜率期望值不同,那么A的等级分要根据以下公式进行调整:


另外在国际象棋中,根据等级分的不同 K 值也会做相应的调整:大于等于2400,K=16,2100-2400 分,K=24,小于等于2100,K=32。

在项目中,将会用以表示某场比赛数据的特征向量为:

[A队 Elo score,A队的 T,O和M 表统计数据,B队 Elo score, B队的 T,O和M 表统计数据]。

4、机器学习

对于全部队伍,在最开始没有Elo分数时,赋予初始值init_elo=1600。然后根据数据计算每支球队Elo等级分。代码如下图所示:


而后根据数据表中的数据,及每支队伍的Elo计算结果,建立对应的2015-2016年常规赛和季后赛中每场比赛的数据集。因为NBA中有主客场制度,所以在比赛时,认为主场作战的队伍更加有优势,因此会在代码中加上100的等级分。


而后在main函数调用上述函数方法,且使用sklearn的Logistic Regression方法建立回归模型。

Logistic Regression(逻辑回归)方法:
逻辑回归:一种用于解决二分类(0 or 1)问题的机器学习方法,用于估计某种事物的可能性。比如某用户购买某商品的可能性等。简单的来说,就是学习我们设计好的向量数据,从中得到一个概率模型,然后输入其他数据,就能根据训练出来的模型得到其结果。

接着使用通过10折交叉验证计算训练正确率。
10折交叉验证(10-fold cross validation):

常用的测试方法。将数据集分成十分,轮流将其中9份作为训练数据,1份作为测试数据,进行试验。每次试验都会得出相应的正确率(或差错率)。10次的结果的正确率(或差错率)的平均值作为对算法精度的估计,一般还需要进行多次10折交叉验证(例如10次10折交叉验证),再求其均值,作为对算法准确性的估计。

最后使用训练好的模型在2016-2017年的常规赛数据中进行预测。导入16-17数据,就可以利用模型对一场新的比赛进行胜负的判断,并且返回胜率的概率。

五、项目实施

在原网站的教程中,需要将网页的数据复制下来到txt文本上然后更改后缀名为.csv格式,比较繁琐。

在课程设计中,我更新为以爬虫获取数据,这里以爬取Team Per Game表代码为例,更改爬虫代码中的url代码部分,运行即可爬取对应赛季的Team Per Ganme Stats(各球队每场比赛数据统计)、Opponent Per Game Stats(对手平均平常比赛的数据统计)表格。而后将会自动将爬取的表格输出为.csv文件在爬虫代码的同路径下。

在“NBA-nwz.py”代码中,设置好全部数据文件的folder路径。如下图所示。(图片中的py文件名为test.py)然后运行代码,即可获得预测结果导出了。


在导出的文件prediction of 2016-2017中可以看到如下预测数据。

六、项目总结

1、实验过程问题总结

在写代码的时候,有一个包一直下载不了,各种报错,根据网上的方法找了一个小时左右,试了很多种方法才解决掉。在这里记录一下。起因就是这个parsel包import不了,一直会报同一个错误:
CondaHTTPError:HTTP 000 CONNECTION FAILED for url
https://mirrors.tuna.tsinghua.edu.cn/anaconda/.
应该是最开始自己安装python环境的时候使用的anaconda没有配置好,或者说这个源不起作用了,于是首先尝试了第一种方法找到.condarc文件,更改里面的channels通道地址。但是当我根据网上的指导教程换国科大、阿里等信号源后依然出现错误。

后面找到了一篇文章,说是需要将https://改为 http即可,刚看到的时候以为不是这个问题,后面实在是没办法了,被这个问题搞得头大,一个多小时了卡着,只好死马当活马医,更改了一下https为http,并配入了清华源的最新配置channels,没想到解决了!

可以通过cmd命令 conda info查看自己的channels路径配置。


也可以通过在.condarc文件直接更改即可。进行如下配置即可轻松拥有速度较快的安装包速度了!

2、项目展望

总的来说,项目还是有一些小不足和继续优化的,例如在5张表中,爬下来就可以立即使用的只有三张表,分别是 Team Per Game Stats、Opponent Per Game Stats 和 Miscellaneous Stats。另外爬下来的表格需要进行字段处理,去掉不需要的字段,并且更改字段名等才能使用。而Python中是可以做到自动化处理数据字段的。这一点没有较好的实现。

除此之外,还可以使用Python可视化来做到更好的展示出比赛中两个队哪个胜率更高,
这一点我曾尝试过,但是由于效果并不是很完美,就没有放到设计项目中来。

以及在10折交叉验证中,可以看出正确率接近70%左右,感觉还可以在机器学习及数据处理(选用数据)方面再下一些功夫,达到更高的正确率。


因为机器学习是我自己课余时间学习过一点点的小教程,所以了解接触并不是很深,做的并不是特别完善,有机会可以多更改,进一步完善优化。

附录:全部代码

进行预测的代码:

import pandas as pd
import math
import numpy as np
import csv
from sklearn import linear_model
from sklearn.model_selection import cross_val_scoreinit_elo = 1600 # 初始化elo值
team_elos = {}
folder = 'D:\pydzy\py-n'  # 文件路径def PruneData(M_stat, O_stat, T_stat):#这个函数要完成的任务在于将原始读入的诸多队伍的数据经过修剪,使其变为一个以team为索引的排列的特征数据#丢弃与球队实力无关的统计量pruneM = M_stat.drop(['Rk', 'Arena'],axis = 1)pruneO = O_stat.drop(['Rk','G','MP'],axis = 1)pruneT = T_stat.drop(['Rk','G','MP'],axis = 1)#将多个数据通过相同的index:team合并为一个数据mergeMO = pd.merge(pruneM, pruneO, how = 'left', on = 'Team')newstat = pd.merge(mergeMO, pruneT,  how = 'left', on = 'Team')#将team作为index的数据返回return newstat.set_index('Team', drop = True, append = False)def GetElo(team):# 初始化每个球队的elo等级分try:return team_elos[team]except:team_elos[team] = init_eloreturn team_elos[team]def CalcElo(winteam, loseteam):# winteam, loseteam的输入应为字符串# 给出当前两个队伍的elo分数R1 = GetElo(winteam)R2 = GetElo(loseteam)# 计算比赛后的等级分,参考elo计算公式E1 = 1/(1 + math.pow(10,(R2 - R1)/400))E2 = 1/(1 + math.pow(10,(R1 - R2)/400))if R1>=2400:K=16elif R1<=2100:K=32else:K=24R1new = round(R1 + K*(1 - E1))R2new = round(R2 + K*(0 - E2))return R1new, R2newdef GenerateTrainData(stat, trainresult):#将输入构造为[[team1特征,team2特征],...[]...]X = []y = []for index, rows in trainresult.iterrows():winteam = rows['WTeam']loseteam = rows['LTeam']#获取最初的elo或是每个队伍最初的elo值winelo = GetElo(winteam)loseelo = GetElo(loseteam)# 给主场比赛的队伍加上100的elo值if rows['WLoc'] == 'H':winelo = winelo+100else:loseelo = loseelo+100# 把elo当为评价每个队伍的第一个特征值fea_win = [winelo]fea_lose = [loseelo]# 添加我们从basketball reference.com获得的每个队伍的统计信息for key, value in stat.loc[winteam].iteritems():fea_win.append(value)for key, value in stat.loc[loseteam].iteritems():fea_lose.append(value)# 将两支队伍的特征值随机的分配在每场比赛数据的左右两侧# 并将对应的0/1赋给y值        if np.random.random() > 0.5:X.append(fea_win+fea_lose)y.append(0)else:X.append(fea_lose+fea_win)y.append(1)# 更新team elo分数win_new_score, lose_new_score = CalcElo(winteam, loseteam)team_elos[winteam] = win_new_scoreteam_elos[loseteam] = lose_new_score# nan_to_num(x)是使用0代替数组x中的nan元素,使用有限的数字代替inf元素return np.nan_to_num(X),ydef GeneratePredictData(stat,info):X=[]#遍历所有的待预测数据,将数据变换为特征形式for index, rows in stat.iterrows():#首先将elo作为第一个特征team1 = rows['Vteam']team2 = rows['Hteam']elo_team1 = GetElo(team1)elo_team2 = GetElo(team2)fea1 = [elo_team1]fea2 = [elo_team2+100]#球队统计信息作为剩余特征for key, value in info.loc[team1].iteritems():fea1.append(value)for key, value in info.loc[team2].iteritems():fea2.append(value)#两队特征拼接X.append(fea1 + fea2)#nan_to_num的作用:1将列表变换为array,2.去除X中的非数字,保证训练器读入不出问题return np.nan_to_num(X)if __name__ == '__main__':# 设置导入数据表格文件的地址并读入数据M_stat = pd.read_csv(folder + '/15-16Miscellaneous_Stat.csv')O_stat = pd.read_csv(folder + '/15-16Opponent_Per_Game_Stat.csv')T_stat = pd.read_csv(folder + '/15-16Team_Per_Game_Stat.csv')team_result = pd.read_csv(folder + '/2015-2016_result.csv')teamstat = PruneData(M_stat, O_stat, T_stat)X,y = GenerateTrainData(teamstat, team_result)# 训练网格模型limodel = linear_model.LogisticRegression()limodel.fit(X,y)# 10折交叉验证print(cross_val_score(model, X, y, cv=10, scoring='accuracy', n_jobs=-1).mean())# 预测pre_data = pd.read_csv(folder + '/16-17Schedule.csv')pre_X = GeneratePredictData(pre_data, teamstat)pre_y = limodel.predict_proba(pre_X)predictlist = []for index, rows in pre_data.iterrows():reslt = [rows['Vteam'], pre_y[index][0], rows['Hteam'], pre_y[index][1]]predictlist.append(reslt)# 将预测结果输出保存为csv文件with open(folder+'/prediction of 2016-2017.csv', 'w',newline='') as f:writers = csv.writer(f)writers.writerow(['Visit Team', 'corresponding probability of winning', 'Home Team', 'corresponding probability of winning'])writers.writerows(predictlist)

爬虫代码:

import requests
import re
import csv
from parsel import Selectorclass NBASpider:def __init__(self):self.url = "https://www.basketball-reference.com/leagues/NBA_2021.html"self.schedule_url = "https://www.basketball-reference.com/leagues/NBA_2016_games-{}.html"self.advanced_team_url = "https://www.basketball-reference.com/leagues/NBA_2016.html"self.headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 ""Safari/537.36"}# 发送请求,获取数据def send(self, url):response = requests.get(url, headers=self.headers, timeout=30)response.encoding = 'utf-8'return response.text# 解析htmldef parse(self, html):team_heads, team_datas = self.get_team_info(html)opponent_heads, opponent_datas = self.get_opponent_info(html)return team_heads, team_datas, opponent_heads, opponent_datasdef get_team_info(self, html):"""通过正则从获取到的html页面数据中team表的表头和各行数据:param html 爬取到的页面数据:return: team_heads表头team_datas 列表内容"""# 1. 正则匹配数据所在的tableteam_table = re.search('<table.*?id="per_game-team".*?>(.*?)</table>', html, re.S).group(1)# 2. 正则从table中匹配出表头team_head = re.search('<thead>(.*?)</thead>', team_table, re.S).group(1)team_heads = re.findall('<th.*?>(.*?)</th>', team_head, re.S)# 3. 正则从table中匹配出表的各行数据team_datas = self.get_datas(team_table)return team_heads, team_datas# 解析opponent数据def get_opponent_info(self, html):"""通过正则从获取到的html页面数据中opponent表的表头和各行数据:param html 爬取到的页面数据:return:"""# 1. 正则匹配数据所在的tableopponent_table = re.search('<table.*?id="per_game-opponent".*?>(.*?)</table>', html, re.S).group(1)# 2. 正则从table中匹配出表头opponent_head = re.search('<thead>(.*?)</thead>', opponent_table, re.S).group(1)opponent_heads = re.findall('<th.*?>(.*?)</th>', opponent_head, re.S)# 3. 正则从table中匹配出表的各行数据opponent_datas = self.get_datas(opponent_table)return opponent_heads, opponent_datas# 获取表格body数据def get_datas(self, table_html):"""从tboday数据中解析出实际数据(去掉页面标签):param table_html 解析出来的table数据:return:"""tboday = re.search('<tbody>(.*?)</tbody>', table_html, re.S).group(1)contents = re.findall('<tr.*?>(.*?)</tr>', tboday, re.S)for oc in contents:rk = re.findall('<th.*?>(.*?)</th>', oc)datas = re.findall('<td.*?>(.*?)</td>', oc, re.S)datas[0] = re.search('<a.*?>(.*?)</a>', datas[0]).group(1)datas.insert(0, rk[0])# yield 声明这个方法是一个生成器, 返回的值是datasyield datasdef get_schedule_datas(self, table_html):"""从tboday数据中解析出实际数据(去掉页面标签):param table_html 解析出来的table数据:return:"""tboday = re.search('<tbody>(.*?)</tbody>', table_html, re.S).group(1)contents = re.findall('<tr.*?>(.*?)</tr>', tboday, re.S)for oc in contents:rk = re.findall('<th.*?><a.*?>(.*?)</a></th>', oc)datas = re.findall('<td.*?>(.*?)</td>', oc, re.S)if datas and len(datas) > 0:datas[1] = re.search('<a.*?>(.*?)</a>', datas[1]).group(1)datas[3] = re.search('<a.*?>(.*?)</a>', datas[3]).group(1)datas[5] = re.search('<a.*?>(.*?)</a>', datas[5]).group(1)datas.insert(0, rk[0])# yield 声明这个方法是一个生成器, 返回的值是datasyield datasdef get_advanced_team_datas(self, table):trs = table.xpath('./tbody/tr')for tr in trs:rk = tr.xpath('./th/text()').get()datas = tr.xpath('./td[@data-stat!="DUMMY"]/text()').getall()datas[0] = tr.xpath('./td/a/text()').get()datas.insert(0, rk)yield datasdef parse_schedule_info(self, html):"""通过正则从获取到的html页面数据中的表头和各行数据:param html 爬取到的页面数据:return: heads表头datas 列表内容"""# 1. 正则匹配数据所在的tabletable = re.search('<table.*?id="schedule" data-cols-to-freeze=",1">(.*?)</table>', html, re.S).group(1)table = table + "</tbody>"# 2. 正则从table中匹配出表头head = re.search('<thead>(.*?)</thead>', table, re.S).group(1)heads = re.findall('<th.*?>(.*?)</th>', head, re.S)# 3. 正则从table中匹配出表的各行数据datas = self.get_schedule_datas(table)return heads, datasdef parse_advanced_team(self, html):"""通过xpath从获取到的html页面数据中表头和各行数据:param html 爬取到的页面数据:return: heads表头datas 列表内容"""selector = Selector(text=html)# 1. 获取对应的tabletable = selector.xpath('//table[@id="advanced-team"]')# 2. 从table中匹配出表头res = table.xpath('./thead/tr')[1].xpath('./th/text()').getall()heads = []for i, head in enumerate(res):if '\xa0' in head:continueheads.append(head)# 3. 匹配出表的各行数据table_data = self.get_advanced_team_datas(table)return heads, table_data# 存储成csv文件def save_csv(self, title, heads, rows):f = open(title + '.csv', mode='w', encoding='utf-8', newline='')csv_writer = csv.writer(f)csv_writer.writerow(heads)for row in rows:csv_writer.writerow(row)f.close()def crawl_team_opponent(self):# 1. 发送请求res = self.send(self.url)# 2. 解析数据team_heads, team_datas, opponent_heads, opponent_datas = self.parse(res)# 3. 保存数据为csvself.save_csv("team", team_heads, team_datas)self.save_csv("opponent", opponent_heads, opponent_datas)def crawl_schedule(self):months = ["october", "november", "december", "january", "february", "march", "april", "may", "june"]for month in months:html = self.send(self.schedule_url.format(month))# print(html)heads, datas = self.parse_schedule_info(html)# 3. 保存数据为csvself.save_csv("schedule_"+month, heads, datas)def crawl_advanced_team(self):# 1. 发送请求res = self.send(self.advanced_team_url)# 2. 解析数据heads, datas = self.parse_advanced_team(res)# 3. 保存数据为csvself.save_csv("advanced_team", heads, datas)def crawl(self):# 1. 爬取各队伍信息# self.crawl_team_opponent()# 2. 爬取计划表# self.crawl_schedule()# 3. 爬取Advanced Team表self.crawl_advanced_team()if __name__ == '__main__':# 运行爬虫spider = NBASpider()spider.crawl()

Python课程设计大作业:获取比赛数据并进行机器学习智能预测NBA的比赛结果相关推荐

  1. 北京交通大学Python课程设计大作业(四)——典籍词频统计

    北京交通大学Python课程设计大作业(四)--典籍词频统计 文章目录 北京交通大学Python课程设计大作业(四)--典籍词频统计 一.词频统计任务介绍 二.典籍词频统计python源代码如下 三. ...

  2. Java课程设计大作业学生管理系统的设计与开发(Java+Mysql)

    文章目录 项目目标 项目截图展示 项目Java源程序 项目数据库文件信息 项目结构图设计 系统功能结构图: 软件架构设计 项目目标     这篇文章是Java语言得课程设计大作业记录.     项目由 ...

  3. 华南理工大学计算机操作系统课程设计大作业银行家死锁避免算法模拟,2016春操作系统大作业银行家死锁避免算法模拟.doc...

    文档介绍: 2016春操作系统大作业银行家死锁避免算法模拟20160501华南理工大学"计算机操作系统"课程设计大作业计算机科学与技术专业:春2015班级:号:2015047420 ...

  4. android大作业闹钟的功能,定时闹钟课程设计大作业.doc

    定时闹钟课程设计大作业 微型计算机控制 技术大作业 设计题目: 定时闹钟课程设计 院 系:计算机科学与信息工程学院 学生姓名: 曹紫莹 学 号: 201103010036 专业班级: 计算机科学与技术 ...

  5. 打怪游戏Java课程设计_java 课程设计大作业 写的一个RPG游戏(代码+文档)

    [实例简介] java 课程设计大作业 写的一个RPG游戏(代码+文档) java 课程设计大作业 写的一个RPG游戏(代码+文档) [实例截图] [核心代码] Rebellion-master ├─ ...

  6. Android课程设计大作业-音乐播放器

    Android课程设计大作业-音乐播放器 一.**主要实现界面效果** 1)登录界面 2)音乐列表界面 3)音乐播放界面 二.**系统设计** 1)使用Service播放音乐 2) 前台界面(Acti ...

  7. 简易抽奖系统(Java课程设计/大作业)

    简易抽奖系统(Java课程设计/大作业) package 简易抽奖系统; import java.awt.*; import java.awt.event.ActionEvent; import ja ...

  8. 网页课程设计大作业——华山旅游网

    目录 1 设计简介及设计方案论述 1.1 背景和意义 1.2 主要技术 1.3 拟解决的关键问题 1.4 安装和使用 详细代码和完整设计报告我都进行了上传,有需要的可以自取,有什么问题可以私信我,在线 ...

  9. javaweb基于JSP+Servlet开发大数据与应用专业企业门户网站源码 课程设计 大作业

    基于JSP+Servlet开发大数据与应用专业企业门户网站:(大作业/课程设计) 开发环境: Windows操作系统 开发工具: Eclipse+Jdk+Tomcat+MYSQL数据库 运行效果图: ...

最新文章

  1. 【Henu ACM Round#15 A】 A and B and Chess
  2. 谷歌开源张量网络库TensorNetwork,GPU处理提升100倍!
  3. 什么,PyTorch还能开发新药?哈佛推出这款工具包,10行代码训练“药神”模型...
  4. mysql之外键约束
  5. javascript中清空数组的两种方式
  6. 一个小小指针,竟把Linux内核攻陷了!
  7. HDU3208(区间指数和)
  8. Java BigDecimal longValueExact()方法与示例
  9. bbb u-boot 验证 emmc
  10. 计算机专业能不能转音乐系,中国音乐学院可以转专业吗,中国音乐学院新生转专业政策...
  11. java中的10的算法,Java中10个常用的排序算法
  12. django传递URL到某个app的urls.py文件中
  13. 华东电脑申威服务器_华东电脑(600850):申威服务器首批量产下线 国产化业务落地里程碑事件[配资公司会议室]...
  14. mysql选择产品和功能_mysql - 产品属性选择
  15. (转)Android权限列表permission说明 (一)
  16. 关于Android中为什么主线程不会因为Looper.loop()里的死循环卡死?引发的思考,事实可能不是一个 epoll 那么 简单。...
  17. 现在手机屏幕为什么都这么大?
  18. DBSCAN聚类算法实用案例
  19. 5G组网-SANSA
  20. python学习第二天——编写名片

热门文章

  1. TI 生态大宇宙 - 波卡 Polkadot
  2. Cisco服务器http显示内容,IOS HTTP服务器的AAA控制
  3. 计算机网络-自顶向下方法-笔记【第2章-应用层】
  4. 2021 京东 校招面试
  5. 关于未来计算机的参考文献,近几年计算机毕业参考文献 哪里有计算机毕业参考文献...
  6. 【电商专享】聚划算活动海量商品一键报名,省时省力!
  7. 松滋历史(2)--高成县为什么这么高光?
  8. 知乎 API v4 整理
  9. 淘宝虚拟物品自动发货---DiPiPi网店自动发货助手免费版
  10. bootstraptable treeGrid 懒加载_为 Vue 的惰性加载加一个进度条