基于python实现的“千锋教育数据可视化大屏”
一、开发环境
开发工具
- IntelliJ IDEA 2023.2.1
- Visual Studio Code
- MongoDB Compass
- Google Chrome
开发环境 (技术)
- python 3.11.4
- MongoDB 7.0.1
- HTML
- JS
- CSS
所用到主要的python库
- requests
- pymongo
- pandas
- pyecharts
二、整体效果
三、目录详情
四、启动教程
-
安装依赖库
-
pymongo
pip install pymongo
-
pandas
pip install pandas
-
pyecharts
pip install pyecharts
-
-
启动“启动程序.py”
控制台出现以下界面,说明启动成功!
五、爬取到的数据(MongoDB数据库)
-
数据集
-
学生数据
六、代码部分
-
config.py
# 数据库服务器 MONGO_URL = 'localhost' # 数据库 MONGO_DB = 'qianfeng' # 数据库表 MONGO_TABLE = 'student'
-
千锋教育数据爬虫.py
import json import random import pymongo import requests import logging as log from src.前锋教育可视化.config import * '''' 【第一部分】用于初始化对象 ''' # 请求url BasicsUrl = 'http://www.qfedu.com/student/employment/' # 日志级别:DEBUG # 输出文件:default.log fm = "%(asctime)s [%(funcName)s:%(lineno)d] %(levelname)s [%(name)s] %(message)s" log.basicConfig(level=log.DEBUG,format=fm,filename="default.log",encoding="UTF-8") # log.basicConfig(level=log.DEBUG, format=fm, encoding="UTF-8") log.debug("程序初始化中......") # 创建MongoDB连接对象 client = pymongo.MongoClient(MONGO_URL) db = client[MONGO_DB] # 创建浏览器对象 # browser = webdriver.Chrome() # 城市参照字典(为了避免多次去请求,已将响应数据写成字典) contrast = {'盐城市': '江苏', '宿州市': '安徽', '岳阳市': '湖南', '邵阳市': '湖南', '乌兰察布市': '内蒙古自治区', '新乡市': '河南', '呼伦贝尔市': '内蒙古自治区', '长沙市': '湖南', '广州市': '广东', '宁德市': '福建', '阳江市': '广东', '毕节地区': '贵州', '无锡市': '江苏', '东营市': '山东', '仙桃市': '湖北', '太原市': '山西', '濮阳市': '河南', '驻马店市': '河南', '丹东市': '辽宁', '许昌市': '河南', '庆阳市': '甘肃', '商洛市': '陕西', '惠州市': '广东', '朝阳市': '辽宁', '渭南市': '陕西', '莆田市': '福建', '淮南市': '安徽', '海口市': '海南', '巴中市': '四川', '台州市': '浙江', '辽阳市': '辽宁', '哈尔滨市': '黑龙江', '忻州市': '山西', '沈阳市': '辽宁', '泰安市': '山东', '南阳市': '河南', '龙岩市': '福建', '舟山市': '浙江', '保山市': '云南', '珠海市': '广东', '随州市': '湖北', '临沂市': '山东', '攀枝花市': '四川', '天门市': '湖北', '西安市': '陕西', '泰州市': '江苏', '阜新市': '辽宁', '达州市': '四川', '牡丹江市': '黑龙江', '锡林郭勒盟': '内蒙古自治区', '吕梁市': '山西', '湛江市': '广东', '南京市': '江苏', '资阳市': '四川', '济南市': '山东', '乌鲁木齐市': '新疆维吾尔自治区', '江门市': '广东', '凉山彝族自治州': '四川', '玉溪市': '云南', '通辽市': '内蒙古自治区', '广元市': '四川', '南通市': '江苏', '扬州市': '江苏', '漯河市': '河南', '潮州市': '广东', '东莞市': '广东', '池州市': '安徽', '酒泉市': '甘肃', '玉林市': '广西壮族自治区', '焦作市': '河南', '柳州市': '广西壮族自治区', '六盘水市': '贵州', '湘潭市': '湖南', '佳木斯市': '黑龙江', '克拉玛依市': '新疆维吾尔自治区', '淄博市': '山东', '常德市': '湖南', '西宁市': '青海', '北海市': '广西壮族自治区', '湘西土家族苗族自治州': '湖南', '蚌埠市': '安徽', '绥化市': '黑龙江', '天水市': '甘肃', '福州市': '福建', '十堰市': '湖北', '日照市': '山东', '佛山市': '广东', '沧州市': '河北', '天津': '天津', '连云港市': '江苏', '德阳市': '四川', '绍兴市': '浙江', '德州市': '山东', '云浮市': '广东', '承德市': '河北', '宜昌市': '湖北', '济宁市': '山东', '泉州市': '福建', '内江市': '四川', '银川市': '宁夏回族自治区', '上饶市': '江西', '松原市': '吉林', '唐山市': '河北', '重庆': '重庆', '固原市': '宁夏回族自治区', '芜湖市': '安徽', '保定市': '河北', '运城市': '山西', '宿迁市': '江苏', '绵阳市': '四川', '周口市': '河南', '徐州市': '江苏', '青岛市': '山东', '厦门市': '福建', '汉中市': '陕西', '邢台市': '河北', '三亚市': '海南', '河源市': '广东', '嘉兴市': '浙江', '潍坊市': '山东', '大庆市': '黑龙江', '济源市': '河南', '金华市': '浙江', '襄樊市': '湖北', '枣庄市': '山东', '桂林市': '广西壮族自治区', '张家界市': '湖南', '晋城市': '山西', '三门峡市': '河南', '萍乡市': '江西', '南充市': '四川', '平顶山市': '河南', '清远市': '广东', '南昌市': '江西', '泸州市': '四川', '郴州市': '湖南', '博尔塔拉蒙古自治州': '新疆维吾尔自治区', '湖州市': '浙江', '镇江市': '江苏', '贵阳市': '贵州', '包头市': '内蒙古自治区', '南宁市': '广西壮族自治区', '马鞍山市': '安徽', '武威市': '甘肃', '北京': '北京', '崇左市': '广西壮族自治区', '邯郸市': '河北', '梧州市': '广西壮族自治区', '荆州市': '湖北', '吴忠市': '宁夏回族自治区', '株洲市': '湖南', '晋中市': '山西', '亳州市': '安徽', '盘锦市': '辽宁', '长治市': '山西', '成都市': '四川', '石家庄市': '河北', '黄冈市': '湖北', '曲靖市': '云南', '孝感市': '湖北', '吐鲁番地区': '新疆维吾尔自治区', '榆林市': '陕西', '大理白族自治州': '云南', '温州市': '浙江', '上海': '上海', '大连市': '辽宁', '肇庆市': '广东', '金昌市': '甘肃', '景德镇市': '江西', '汕头市': '广东', '滁州市': '安徽', '黑河市': '黑龙江', '吉安市': '江西', '海南藏族自治州': '青海', '丽水市': '浙江', '锦州市': '辽宁', '临汾市': '山西', '廊坊市': '河北', '永州市': '湖南', '威海市': '山东', '杭州市': '浙江', '延安市': '陕西', '六安市': '安徽', '衡阳市': '湖南', '中山市': '广东', '阜阳市': '安徽', '宁波市': '浙江', '阿克苏地区': '新疆维吾尔自治区', '常州市': '江苏', '滨州市': '山东', '开封市': '河南', '信阳市': '河南', '赣州市': '江西', '遵义市': '贵州', '鄂尔多斯市': '内蒙古自治区', '长春市': '吉林', '鞍山市': '辽宁', '宣城市': '安徽', '秦皇岛市': '河北', '宜春市': '江西', '荆门市': '湖北', '鹤壁市': '河南', '商丘市': '河南', '眉山市': '四川', '苏州市': '江苏', '怀化市': '湖南', '自贡市': '四川', '呼和浩特市': '内蒙古自治区', '吉林市': '吉林', '洛阳市': '河南', '合肥市': '安徽', '拉萨市': '西藏自治区', '大同市': '山西', '衢州市': '浙江', '河池市': '广西壮族自治区', '衡水市': '河北', '咸宁市': '湖北', '昆明市': '云南', '咸阳市': '陕西', '宜宾市': '四川', '葫芦岛市': '辽宁', '黔南布依族苗族自治州': '贵州', '新余市': '江西', '赤峰市': '内蒙古自治区', '张家口市': '河北', '聊城市': '山东', '淮安市': '江苏', '营口市': '辽宁', '朔州市': '山西', '烟台市': '山东', '宝鸡市': '陕西', '淮北市': '安徽', '遂宁市': '四川', '武汉市': '湖北', '安阳市': '河南', '昭通市': '云南', '贵港市': '广西壮族自治区', '黄石市': '湖北', '九江市': '江西', '深圳市': '广东', '梅州市': '广东', '阿勒泰地区': '新疆维吾尔自治区', '兰州市': '甘肃', '安庆市': '安徽', '郑州市': '河南'} '''' 【第二部分】用于定义一些函数 ''' # 请求的方法 def httpGet(url): headers_list = [ { 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G955U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 10; SM-G981B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.162 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (iPad; CPU OS 13_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/87.0.4280.77 Mobile/15E148 Safari/604.1' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.109 Safari/537.36 CrKey/1.54.248666' }, { 'user-agent': 'Mozilla/5.0 (X11; Linux aarch64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.188 Safari/537.36 CrKey/1.54.250320' }, { 'user-agent': 'Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+' }, { 'user-agent': 'Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+' }, { 'user-agent': 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' }, { 'user-agent': 'Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' }, { 'user-agent': 'Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true' }, { 'user-agent': 'Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14263' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0.1; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)' }, { 'user-agent': 'Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 11; Pixel 3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Mobile Safari/537.36' }, { 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1' }, { 'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1' }, { 'user-agent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1' }, ] proxies = { 'http': '127.0.0.1:1212', 'https': '127.0.0.1:1212' } headers = random.choice(headers_list) return requests.get(url=url, headers=headers, timeout=20); # 请求接口,并将数据保存到MongoDB def insertDB(star, end): for i in range(star, end + 1): log.debug(f"已获取{i}年学生就业数据") data = httpGet(f'http://jx.1000phone.net/teacher.php/Api/studentJobData_year?date={i}') res = json.loads(data.text) # 构建info元组 jobInfo = { "year": i, "topSalary": res['topSalary'], "avgSalary": res['avgSalary'], "goodSalaryRate": res['goodSalaryRate'], "jobCount": res['jobCount'], "jobRate": res['jobRate'], } # 将数据保存到MongoDB if db["jobInfo"].insert_one(jobInfo): log.debug(f"{i}年就业统计信息已保存到MongoDB") # 保存学生信息 if db['student'].insert_many(res['student']): log.debug(f"{i}年学生信息已保存") # 爬取取视频信息 def getVieoData(): for i in range(1, 13): subjectData = httpGet(f"https://video.qfedu.com/library/api/subjectstage/list/{i}").text subjectList = json.loads(subjectData)["data"][0]["subjectStageCourseEntities"] dbName = json.loads(subjectData)["data"][0]["stageName"] if db[f"{dbName}"].insert_many(subjectList): log.debug(f"{dbName}课程已导入MongoDB") # 通过地址获取省份的函数 def getGeocodes(city): contrast = {} for i in city: str = "市辖区省直辖县级行政单位省直辖行政单位" if (i in str): continue else: data = requests.get( f"https://restapi.amap.com/v3/geocode/geo?address={i}&output=json&key=c6684350b2db997c28d33309e5589e58").text res = json.loads(data) if res["status"] != "0": geocodes = res["geocodes"][0]["province"] contrast[f"{i}"] = geocodes return contrast # 格式化地理信息 def formatAddress(): collection = db['student'] # 定义聚合查询的管道 pipeline = [ { '$group': { '_id': '$city', # 指定分组的字段 'count': {'$sum': 1} } } ] res = collection.aggregate(pipeline) city = [] for result in res: if result["_id"] != "其他" and result["_id"] != "县": city.append(result["_id"]) newRes = getGeocodes(city) print(newRes) # 菜单控制器 def menuController(): print('''' ======================================= || 千锋教育数据爬取系统 || ======================================= ||请输入你的操作: || || 1.爬取就业信息 2.爬取视频信息 || || 3.清除所有数据 4.获取就业和课程数据|| || 3.清除所有数据 4.退出 || ======================================= ''') while True: flag = int(input("请输入你菜单代码:")) if flag == 1: # 爬取就业信息的代码 insertDB(2017, 2024) log.debug("=======就业信息爬取完毕=======") menuController() elif (flag == 2): # 爬取视频信息部分 getVieoData() log.debug("=======视频爬取完毕=======") menuController() elif (flag == 3): log.debug("=======地理信息格式化中=======") formatAddress() menuController() else: log.debug("=======即将退出=======") break '''' 【第三部分】主函数部分 ''' def main(): # 开始提示 log.debug("程序开始") # 调用菜单控制器 menuController() # 结束提示 log.debug("程序执行结束") ''''【第四部分】运行部分 ''' if __name__ == '__main__': main()
-
数据生成.py
import pandas import pymongo from src.前锋教育可视化.config import * # 城市参照字典 contrast = {'金昌市': '甘肃省', '宜宾市': '四川省', '柳州市': '广西壮族自治区', '郴州市': '湖南省', '西宁市': '青海省', '丹东市': '辽宁省', '桂林市': '广西壮族自治区', '潍坊市': '山东省', '遵义市': '贵州省', '克拉玛依市': '新疆维吾尔自治区', '日照市': '山东省', '阿克苏地区': '新疆维吾尔自治区', '六盘水市': '贵州省', '梅州市': '广东省', '商丘市': '河南省', '天门市': '湖北省', '温州市': '浙江省', '阿勒泰地区': '新疆维吾尔自治区', '临沂市': '山东省', '池州市': '安徽省', '安庆市': '安徽省', '亳州市': '安徽省', '酒泉市': '甘肃省', '舟山市': '浙江省', '深圳市': '广东省', '佳木斯市': '黑龙江省', '上海': '上海市', '渭南市': '陕西省', '安阳市': '河南省', '保定市': '河北省', '衡水市': '河北省', '沧州市': '河北省', '金华市': '浙江省', '东营市': '山东省', '宜昌市': '湖北省', '泉州市': '福建省', '张家界市': '湖南省', '吴忠市': '宁夏回族自治区', '吉林市': '吉林省', '银川市': '宁夏回族自治区', '保山市': '云南省', '绍兴市': '浙江省', '河池市': '广西壮族自治区', '郑州市': '河南省', '马鞍山市': '安徽省', '龙岩市': '福建省', '河源市': '广东省', '天水市': '甘肃省', '宣城市': '安徽省', '南充市': '四川省', '孝感市': '湖北省', '晋中市': '山西省', '怀化市': '湖南省', '黑河市': '黑龙江省', '常德市': '湖南省', '大连市': '辽宁省', '佛山市': '广东省', '廊坊市': '河北省', '惠州市': '广东省', '常州市': '江苏省', '岳阳市': '湖南省', '许昌市': '河南省', '乌鲁木齐市': '新疆维吾尔自治区', '运城市': '山西省', '曲靖市': '云南省', '济宁市': '山东省', '松原市': '吉林省', '秦皇岛市': '河北省', '太原市': '山西省', '北京': '北京市', '北海市': '广西壮族自治区', '玉林市': '广西壮族自治区', '辽阳市': '辽宁省', '遂宁市': '四川省', '乌兰察布市': '内蒙古自治区', '枣庄市': '山东省', '萍乡市': '江西省', '淮南市': '安徽省', '南通市': '江苏省', '鹤壁市': '河南省', '宁德市': '福建省', '黄石市': '湖北省', '西安市': '陕西省', '威海市': '山东省', '焦作市': '河南省', '黔南布依族苗族自治州': '贵州省', '黄冈市': '湖北省', '贵阳市': '贵州省', '商洛市': '陕西省', '成都市': '四川省', '扬州市': '江苏省', '锦州市': '辽宁省', '济源市': '河南省', '锡林郭勒盟': '内蒙古自治区', '淮北市': '安徽省', '濮阳市': '河南省', '随州市': '湖北省', '莆田市': '福建省', '攀枝花市': '四川省', '固原市': '宁夏回族自治区', '邯郸市': '河北省', '湘潭市': '湖南省', '江门市': '广东省', '株洲市': '湖南省', '芜湖市': '安徽省', '资阳市': '四川省', '巴中市': '四川省', '玉溪市': '云南省', '泸州市': '四川省', '景德镇市': '江西省', '汉中市': '陕西省', '呼伦贝尔市': '内蒙古自治区', '三门峡市': '河南省', '鞍山市': '辽宁省', '张家口市': '河北省', '驻马店市': '河南省', '新乡市': '河南省', '福州市': '福建省', '梧州市': '广西壮族自治区', '阜阳市': '安徽省', '宿迁市': '江苏省', '邵阳市': '湖南省', '漯河市': '河南省', '荆门市': '湖北省', '台州市': '浙江省', '淮安市': '江苏省', '朝阳市': '辽宁省', '荆州市': '湖北省', '汕头市': '广东省', '十堰市': '湖北省', '石家庄市': '河北省', '阳江市': '广东省', '济南市': '山东省', '沈阳市': '辽宁省', '襄樊市': '湖北省', '镇江市': '江苏省', '烟台市': '山东省', '宿州市': '安徽省', '哈尔滨市': '黑龙江省', '长春市': '吉林省', '内江市': '四川省', '咸宁市': '湖北省', '聊城市': '山东省', '贵港市': '广西壮族自治区', '云浮市': '广东省', '清远市': '广东省', '牡丹江市': '黑龙江省', '仙桃市': '湖北省', '包头市': '内蒙古自治区', '绥化市': '黑龙江省', '武威市': '甘肃省', '广州市': '广东省', '营口市': '辽宁省', '崇左市': '广西壮族自治区', '衡阳市': '湖南省', '上饶市': '江西省', '珠海市': '广东省', '兰州市': '甘肃省', '临汾市': '山西省', '长沙市': '湖南省', '苏州市': '江苏省', '周口市': '河南省', '盘锦市': '辽宁省', '平顶山市': '河南省', '唐山市': '河北省', '南昌市': '江西省', '衢州市': '浙江省', '德阳市': '四川省', '咸阳市': '陕西省', '九江市': '江西省', '吐鲁番地区': '新疆维吾尔自治区', '泰州市': '江苏省', '眉山市': '四川省', '吉安市': '江西省', '海口市': '海南省', '蚌埠市': '安徽省', '天津': '天津市', '洛阳市': '河南省', '鄂尔多斯市': '内蒙古自治区', '赣州市': '江西省', '南京市': '江苏省', '六安市': '安徽省', '嘉兴市': '浙江省', '赤峰市': '内蒙古自治区', '昭通市': '云南省', '青岛市': '山东省', '海南藏族自治州': '青海省', '三亚市': '海南省', '新余市': '江西省', '绵阳市': '四川省', '大理白族自治州': '云南省', '淄博市': '山东省', '宜春市': '江西省', '广元市': '四川省', '德州市': '山东省', '榆林市': '陕西省', '阜新市': '辽宁省', '承德市': '河北省', '湘西土家族苗族自治州': '湖南省', '邢台市': '河北省', '潮州市': '广东省', '延安市': '陕西省', '丽水市': '浙江省', '拉萨市': '西藏自治区', '开封市': '河南省', '朔州市': '山西省', '自贡市': '四川省', '徐州市': '江苏省', '杭州市': '浙江省', '毕节地区': '贵州省', '肇庆市': '广东省', '宁波市': '浙江省', '东莞市': '广东省', '晋城市': '山西省', '南宁市': '广西壮族自治区', '合肥市': '安徽省', '宝鸡市': '陕西省', '昆明市': '云南省', '重庆': '重庆市', '永州市': '湖南省', '湖州市': '浙江省', '大庆市': '黑龙江省', '滨州市': '山东省', '信阳市': '河南省', '忻州市': '山西省', '大同市': '山西省', '吕梁市': '山西省', '武汉市': '湖北省', '滁州市': '安徽省', '博尔塔拉蒙古自治州': '新疆维吾尔自治区', '长治市': '山西省', '南阳市': '河南省', '凉山彝族自治州': '四川省', '湛江市': '广东省', '达州市': '四川省', '葫芦岛市': '辽宁省', '盐城市': '江苏省', '连云港市': '江苏省', '无锡市': '江苏省', '呼和浩特市': '内蒙古自治区', '通辽市': '内蒙古自治区', '厦门市': '福建省', '中山市': '广东省', '泰安市': '山东省', '庆阳市': '甘肃省'} # 创建MongoDB连接对象 client = pymongo.MongoClient(MONGO_URL) db = client[MONGO_DB] # 每个专业课程的数量 def subjectCount(): list = [] tables = ["Java基础", "PHP基础", "Python基础", "UI基础", "Unity 3d基础", "go基础", "linux云计算基础", "web前端基础", "大数据基础", "物联网基础", "网络安全基础", "网络营销基础"] for t in tables: collection = db[t] count = collection.count_documents({}) list.append([t, count]) return list # 每个专业的播放量 def subjectStudyNum(): list = [] tables = ["Java基础", "PHP基础", "Python基础", "UI基础", "Unity 3d基础", "go基础", "linux云计算基础", "web前端基础", "大数据基础", "物联网基础", "网络安全基础", "网络营销基础"] for t in tables: count = 0 collection = db[t] items = collection.find({}, {"studyNum": 1}) for item in items: count += item["studyNum"] list.append([t, count]) return list # 各科学习人数占比 # java的学习人数 # 每个年份的学生人数 def yearStudent(): data = [] collection = db['student'] pipeline = [ {"$addFields": {"date": {"$toDate": "$date"}}}, {"$group": {"_id": {"year": {"$year": "$date"}}, "count": {"$sum": 1}}}, { "$sort": {"_id": 1} } ] # 执行聚合查询 results = list(collection.aggregate(pipeline, allowDiskUse=True)) # 打印结果 for result in results: data.append([result['_id']['year'], result['count']]) return data # 学历占比 def educationDuty(): data = [] collection = db['student'] # 定义聚合查询的管道 pipeline = [ { '$group': { '_id': '$education', # 指定分组的字段 'count': {'$sum': 1} } }, { "$sort": {"count": 1} } ] res = collection.aggregate(pipeline) for i in res: data.append([i["_id"], i["count"]]) return data # 生成省份分布的数据 def mapCount(): collection = db['student'] # 定义聚合查询的管道 pipeline = [ { '$group': { '_id': '$city', # 指定分组的字段 'count': {'$sum': 1} } } ] res = collection.aggregate(pipeline) countList = [] for result in res: if result["_id"] in contrast: countList.append([contrast[result["_id"]], result["count"]]) column_names = ['address', 'num'] table = pandas.DataFrame(countList, columns=column_names) grouped = table.groupby("address").sum() v1 = table.groupby("address").groups.keys() v2 = grouped.iloc[:, 0].tolist() # 使用zip函数将两个列表组合为元组的列表,然后使用列表推导式转换为二维列表 combined_list = [list(item) for item in zip(v1, v2)] return combined_list
-
图形生成.py
from pyecharts import options as opts from pyecharts.charts import Bar, Pie, Radar, Map from pyecharts.commons.utils import JsCode from pyecharts.charts import Line from src.前锋教育可视化.数据生成 import * ''' 生成对应的图表 ''' # 每个专业课程的数量 def getSubjectCount(): list = subjectCount() res = pandas.DataFrame(list) c = ( Bar(init_opts=opts.InitOpts(width="450px", height="220px")) .add_xaxis(res.iloc[:, 0].tolist()) .add_yaxis("数量", res.iloc[:, 1].tolist()) .set_global_opts( title_opts=opts.TitleOpts(title="各科课程数量",title_textstyle_opts=opts.TextStyleOpts(color="#6495ed")), datazoom_opts=opts.DataZoomOpts(), legend_opts=opts.LegendOpts(textstyle_opts=opts.TextStyleOpts(color="#00E7F8")) ) .render("各科课程数量.html") ) # 每个专业的播放量 def getSubjectStudyNum(): data = subjectStudyNum() res = pandas.DataFrame(data) c = ( Bar(init_opts=opts.InitOpts(width="450px", height="220px")) .add_xaxis(res.iloc[:, 0].tolist()) .add_yaxis("数量", res.iloc[:, 1].tolist(), category_gap="60%") .set_series_opts( itemstyle_opts={ "normal": { "color": JsCode( """new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(0, 244, 255, 1)' }, { offset: 1, color: 'rgba(0, 77, 167, 1)' }], false)""" ), "barBorderRadius": [30, 30, 30, 30], "shadowColor": "rgb(0, 160, 221)", } } ) .set_global_opts(title_opts=opts.TitleOpts(title="各科IT课程播放量", title_textstyle_opts=opts.TextStyleOpts(color="#6495ed")), legend_opts=opts.LegendOpts(textstyle_opts=opts.TextStyleOpts(color="#00E7F8"))) .render("各科课程播放量.html") ) # 各科学习人数占比 def getStudySubject(): data = subjectStudyNum() res = pandas.DataFrame(data) label = res.iloc[:, 0].tolist() values = res.iloc[:, 1].tolist() c = ( Pie(init_opts=opts.InitOpts(width="450px", height="220px")) .add( "", [list(z) for z in zip(label, values)], radius=["30%", "75%"], center=["50%", "50%"], rosetype="radius", ) .set_global_opts( legend_opts=opts.LegendOpts(is_show=False) ) .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}%")) # 值得一提的是,{d}%为百分比 .render("各科学习人数占比.html") ) # java的学习人数 # 每个年份的学生人数 def getYearStudent(): data = yearStudent() res = pandas.DataFrame(data) x_data = ["2017", "2018", "2019", "2020", "2021", "2022", "2023", "2024"] y_data = [7639, 10031, 14885, 12661, 13756, 13211, 10967, 1226] background_color_js = ( "new echarts.graphic.LinearGradient(0, 0, 0, 1, " "[{offset: 0, color: '#c86589'}, {offset: 1, color: '#06a7ff'}], false)" ) area_color_js = ( "new echarts.graphic.LinearGradient(0, 0, 0, 1, " "[{offset: 0, color: '#eb64fb'}, {offset: 1, color: '#3fbbff0d'}], false)" ) c = ( Line(init_opts=opts.InitOpts(bg_color=JsCode(background_color_js), width="450px", height="220px")) .add_xaxis(xaxis_data=x_data) .add_yaxis( series_name="总量", y_axis=y_data, is_smooth=True, is_symbol_show=True, symbol="circle", symbol_size=6, linestyle_opts=opts.LineStyleOpts(color="#fff"), label_opts=opts.LabelOpts(is_show=True, position="top", color="white"), itemstyle_opts=opts.ItemStyleOpts( color="red", border_color="#fff", border_width=3 ), tooltip_opts=opts.TooltipOpts(is_show=False), areastyle_opts=opts.AreaStyleOpts(color=JsCode(area_color_js), opacity=1), ) .set_global_opts( title_opts=opts.TitleOpts( title="学员概况", pos_bottom="0%", pos_left="center", title_textstyle_opts=opts.TextStyleOpts(color="#fff", font_size=16), ), xaxis_opts=opts.AxisOpts( type_="category", boundary_gap=False, axislabel_opts=opts.LabelOpts(margin=30, color="#ffffff63"), axisline_opts=opts.AxisLineOpts(is_show=False), axistick_opts=opts.AxisTickOpts( is_show=True, length=25, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), ), splitline_opts=opts.SplitLineOpts( is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") ), ), yaxis_opts=opts.AxisOpts( type_="value", position="right", axislabel_opts=opts.LabelOpts(margin=20, color="#ffffff63"), axisline_opts=opts.AxisLineOpts( linestyle_opts=opts.LineStyleOpts(width=2, color="#fff") ), axistick_opts=opts.AxisTickOpts( is_show=True, length=15, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f"), ), splitline_opts=opts.SplitLineOpts( is_show=True, linestyle_opts=opts.LineStyleOpts(color="#ffffff1f") ), ), legend_opts=opts.LegendOpts(is_show=False), ) .render("每年学生情况.html") ) # 学历占比 def getEducationDuty(): data = educationDuty() res = pandas.DataFrame(data) v1 = [res.iloc[:, 1].tolist()] c = ( Radar(init_opts=opts.InitOpts(width="450px", height="220px")) .add_schema( schema=[ opts.RadarIndicatorItem(name='博士', max_=100), opts.RadarIndicatorItem(name='硕士', max_=10000), opts.RadarIndicatorItem(name='高中以下', max_=10000), opts.RadarIndicatorItem(name='None', max_=3000), opts.RadarIndicatorItem(name='高中', max_=5000), opts.RadarIndicatorItem(name='专科', max_=47720), opts.RadarIndicatorItem(name='本科', max_=50000), ] ) .add( '学历', v1, color='blue', # 通过颜色属性 将其填充 areastyle_opts=opts.AreaStyleOpts( opacity=0.5, color='blue' ), ) .set_global_opts( legend_opts=opts.LegendOpts(is_show=False) ) .set_series_opts(label_opts=opts.LabelOpts(is_show=False)) .render("学历雷达图.html") ) # 生成省份分布的数据 def chinaMap(): data = mapCount() ( Map(init_opts=opts.InitOpts(width="920px", height="640px")) .add( series_name="学员", data_pair=data, maptype="china", # 是否默认选中,默认为True # is_selected=True, # 是否启用鼠标滚轮缩放和拖动平移,默认为True is_roam=True, # 是否显示图形标记,默认为True is_map_symbol_show=False, # 图元样式配置 itemstyle_opts={ # 常规显示 "normal": {"areaColor": "white", "borderColor": "red"}, # 强调颜色 "emphasis": {"areaColor": "pink"} } ) # 全局配置项 .set_global_opts( # 设置标题 title_opts=opts.TitleOpts(title="学员工作分布", title_textstyle_opts=opts.TextStyleOpts(color="#6495ed")), legend_opts=opts.LegendOpts(textstyle_opts=opts.TextStyleOpts(color="#00E7F8")), # 设置标准显示 visualmap_opts=opts.VisualMapOpts(max_=20000, is_piecewise=False) ) # 系列配置项 .set_series_opts( # 标签名称显示,默认为True label_opts=opts.LabelOpts(is_show=True, color="blue", ) ) # 生成本地html文件 .render("中国地图.html") ) # 各省薪资分布 # 最高薪资 # 过万薪资占比 # 总人数 ''' 函数执行部分 ''' getSubjectStudyNum() getStudySubject() getYearStudent() getEducationDuty() chinaMap() getSubjectCount()
-
启动程序.py
import webbrowser def main(): url = 'index.html' print(''' ========== 项目启动成功 ========== MongoDB的配置,请查看:config.py 项目爬取和存储过程,请查看:前锋教育数据爬取.py 数据处理过程,请查看:数据生成.py 可视化图形生成,请查看:图形生成.py 启动入口:启动程序.py ''') webbrowser.open(url) if __name__ == '__main__': main()