# 1 前言
?? 這兩年開始畢業(yè)設(shè)計(jì)和畢業(yè)答辯的要求和難度不斷提升,傳統(tǒng)的畢設(shè)題目缺少創(chuàng)新和亮點(diǎn),往往達(dá)不到畢業(yè)答辯的要求,這兩年不斷有學(xué)弟學(xué)妹告訴學(xué)長自己做的項(xiàng)目系統(tǒng)達(dá)不到老師的要求。
為了大家能夠順利以及最少的精力通過畢設(shè),學(xué)長分享優(yōu)質(zhì)畢業(yè)設(shè)計(jì)項(xiàng)目,今天要分享的是
?? 基于大數(shù)據(jù)招聘崗位數(shù)據(jù)分析與可視化系統(tǒng)
??學(xué)長這里給一個題目綜合評分(每項(xiàng)滿分5分)
- 難度系數(shù):3分
- 工作量:3分
- 創(chuàng)新點(diǎn):5分
1 課題背景
隨著科技的飛速發(fā)展,數(shù)據(jù)呈現(xiàn)爆發(fā)式的增長,任何人都擺脫不了與數(shù)據(jù)打交道,社會對于“數(shù)據(jù)”方面的人才需求也在不斷增大。因此了解當(dāng)下企業(yè)究竟需要招聘什么樣的人才?需要什么樣的技能?不管是對于在校生,還是對于求職者來說,都顯得很有必要。
本文基于這個問題,針對 boss 直聘網(wǎng)站,使用 Scrapy 框架爬取了全國熱門城市大數(shù)據(jù)、數(shù)據(jù)分析、數(shù)據(jù)挖掘、機(jī)器學(xué)習(xí)、人工智能等相關(guān)崗位的招聘信息。分析比較了不同崗位的薪資、學(xué)歷要求;分析比較了不同區(qū)域、行業(yè)對相關(guān)人才的需求情況;分析比較了不同崗位的知識、技能要求等。
2 實(shí)現(xiàn)效果
崗位情況分析可視化
3 項(xiàng)目實(shí)現(xiàn)
3.1 概述
該項(xiàng)目一共分為三個子任務(wù)完成,數(shù)據(jù)采集—數(shù)據(jù)預(yù)處理—數(shù)據(jù)分析/可視化。
項(xiàng)目流程圖
項(xiàng)目架構(gòu)圖
3.2 數(shù)據(jù)采集
Scrapy 爬蟲介紹
Scrapy是基于Twisted的爬蟲框架,它可以從各種數(shù)據(jù)源中抓取數(shù)據(jù)。其架構(gòu)清晰,模塊之間的耦合度低,擴(kuò)展性極強(qiáng),爬取效率高,可以靈活完成各種需求。能夠方便地用來處理絕大多數(shù)反爬網(wǎng)站,是目前Python中應(yīng)用最廣泛的爬蟲框架。Scrapy框架主要由五大組件組成,它們分別是調(diào)度器(Scheduler)、下載器(Downloader)、爬蟲(Spider)和實(shí)體管道(Item Pipeline)、Scrapy引擎(Scrapy Engine)。各個組件的作用如下:
-
調(diào)度器(Scheduler):說白了把它假設(shè)成為一個URL(抓取網(wǎng)頁的網(wǎng)址或者說是鏈接)的優(yōu)先隊(duì)列,由它來決定下一個要抓取的網(wǎng)址是 什么,同時(shí)去除重復(fù)的網(wǎng)址(不做無用功)。用戶可以自己的需求定制調(diào)度器。
-
下載器(Downloader):是所有組件中負(fù)擔(dān)最大的,它用于高速地下載網(wǎng)絡(luò)上的資源。Scrapy的下載器代碼不會太復(fù)雜,但效率高,主要的原因是Scrapy下載器是建立在twisted這個高效的異步模型上的(其實(shí)整個框架都在建立在這個模型上的)。
-
爬蟲(Spider):是用戶最關(guān)心的部份。用戶定制自己的爬蟲(通過定制正則表達(dá)式等語法),用于從特定的網(wǎng)頁中提取自己需要的信息,即所謂的實(shí)體(Item)。 用戶也可以從中提取出鏈接,讓Scrapy繼續(xù)抓取下一個頁面。
-
實(shí)體管道(Item Pipeline):用于處理爬蟲(spider)提取的實(shí)體。主要的功能是持久化實(shí)體、驗(yàn)證實(shí)體的有效性、清除不需要的信息。
-
Scrapy引擎(Scrapy Engine):Scrapy引擎是整個框架的核心.它用來控制調(diào)試器、下載器、爬蟲。實(shí)際上,引擎相當(dāng)于計(jì)算機(jī)的CPU,它控制著整個流程。
Scrapy 官網(wǎng)架構(gòu)圖
爬取 Boss直聘熱門城市崗位數(shù)據(jù),并將數(shù)據(jù)以 CSV 文件格式進(jìn)行保存。如下圖所示:
編寫爬蟲程序
創(chuàng)建和配置好 Scrapy 項(xiàng)目以后,我們就可以編寫 Scrapy 爬蟲程序了。
import scrapy
import json
import logging
import random
from bosszp.items import BosszpItem
class BossSpider(scrapy.Spider):
name = 'boss'
allowed_domains = ['zhipin.com']
start_urls = ['https://www.zhipin.com/wapi/zpCommon/data/cityGroup.json'] # 熱門城市列表url
# 設(shè)置多個 cookie,建議數(shù)量為 頁數(shù)/2 + 1 個cookie.至少 設(shè)置 4 個
# 只需復(fù)制 __zp_stoken__ 部分即可
cookies = [ '__zp_stoken__=f330bOEgsRnsAIS5Bb2FXe250elQKNzAgMBcQZ1hvWyBjUFE1DCpKLWBtBn99Nwd%2BPHtlVRgdOi1vDEAkOz9sag50aRNRfhs6TQ9kWmNYc0cFI3kYKg5fAGVPPX0WO2JCOipvRlwbP1YFBQlHOQ%3D%3D', '__zp_stoken__=f330bOEgsRnsAIUsENEIbe250elRsb2U4Bg0QZ1hvW19mPEdeeSpKLWBtN3Y9QCN%2BPHtlVRgdOilvfTYkSTMiaFN0X3NRAGMjOgENX2krc0cFI3kYKiooQGx%2BPX0WO2I3OipvRlwbP1YFBQlHOQ%3D%3D', '__zp_stoken__=f330bOEgsRnsAITsLNnJIe250elRJMH95DBAQZ1hvW1J1ewdmDCpKLWBtBHZtagV%2BPHtlVRgdOil1LjkkR1MeRAgdY3tXbxVORWVuTxQlc0cFI3kYKgwCEGxNPX0WO2JCOipvRlwbP1YFBQlHOQ%3D%3D'
]
# 設(shè)置多個請求頭
user_agents = [
'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_0_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.1 Safari/605.1.15',
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0',
'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
'Opera/9.80 (Windows NT 6.1; U; en) Presto/2.8.131 Version/11.11',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon 2.0)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; The World)',
'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)',
]
page_no = 1 # 初始化分頁
def random_header(self):
"""
隨機(jī)生成請求頭
:return: headers
"""
headers = {'Referer': 'https://www.zhipin.com/c101020100/?ka=sel-city-101020100'}
headers['cookie'] = random.choice(self.cookies)
headers['user-agent'] = random.choice(self.user_agents)
return headers
def parse(self, response):
"""
解析首頁熱門城市列表,選擇熱門城市進(jìn)行爬取
:param response: 熱門城市字典數(shù)據(jù)
:return:
"""
# 獲取服務(wù)器返回的內(nèi)容
city_group = json.loads(response.body.decode())
# 獲取熱門城市列表
hot_city_list = city_group['zpData']['hotCityList']
# 初始化空列表,存儲打印信息
# city_lst = []
# for index,item in enumerate(hot_city_list):
# city_lst.apend({index+1: item['name']})
# 列表推導(dǎo)式:
hot_city_names = [{index + 1: item['name']} for index, item in enumerate(hot_city_list)]
print("--->", hot_city_names)
# 從鍵盤獲取城市編號
city_no = int(input('請從上述城市列表中,選擇編號開始爬?。?))
# 拼接url https://www.zhipin.com/job_detail/?query=&city=101040100&industry=&position=
# 獲取城市編碼code
city_code = hot_city_list[city_no - 1]['code']
# 拼接查詢接口
city_url = 'https://www.zhipin.com/job_detail/?query=&city={}&industry=&position='.format(city_code)
logging.info("<<<<<<<<<<<<<正在爬取第_{}_頁崗位數(shù)據(jù)>>>>>>>>>>>>>".format(self.page_no))
yield scrapy.Request(url=city_url, headers=self.random_header(), callback=self.parse_city)
def parse_city(self, response):
"""
解析崗位頁數(shù)據(jù)
:param response: 崗位頁響應(yīng)數(shù)據(jù)
:return:
"""
if response.status != 200:
logging.warning("<<<<<<<<<<<<<獲取城市招聘信息失敗,ip已被封禁。請稍后重試>>>>>>>>>>>>>")
return
li_elements = response.xpath('//div[@class="job-list"]/ul/li') # 定位到所有的li標(biāo)簽
next_url = response.xpath('//div[@class="page"]/a[last()]/@href').get() # 獲取下一頁
for li in li_elements:
job_name = li.xpath('./div/div[1]//div[@class="job-title"]/span[1]/a/text()').get()
job_area = li.xpath('./div/div[1]//div[@class="job-title"]/span[2]/span[1]/text()').get()
job_salary = li.xpath('./div/div[1]//span[@class="red"]/text()').get()
com_name = li.xpath('./div/div[1]/div[2]//div[@class="company-text"]/h3/a/text()').get()
com_type = li.xpath('./div/div[1]/div[2]/div[1]/p/a/text()').get()
com_size = li.xpath('./div/div[1]/div[2]/div[1]/p/text()[2]').get()
finance_stage = li.xpath('./div/div[1]/div[2]/div[1]/p/text()[1]').get()
work_year = li.xpath('./div/div[1]/div[1]/div[1]/div[2]/p/text()[1]').get()
education = li.xpath('./div/div[1]/div[1]/div[1]/div[2]/p/text()[2]').get()
job_benefits = li.xpath('./div/div[2]/div[2]/text()').get()
item = BosszpItem(job_name=job_name, job_area=job_area, job_salary=job_salary, com_name=com_name,
com_type=com_type, com_size=com_size,
finance_stage=finance_stage, work_year=work_year, education=education,
job_benefits=job_benefits)
yield item
if next_url == "javascript:;":
logging.info('<<<<<<<<<<<<<熱門城市崗位數(shù)據(jù)已爬取結(jié)束>>>>>>>>>>>>>')
logging.info("<<<<<<<<<<<<<一共爬取了_{}_頁崗位數(shù)據(jù)>>>>>>>>>>>>>".format(self.page_no))
return
next_url = response.urljoin(next_url) # 網(wǎng)址拼接
self.page_no += 1
logging.info("<<<<<<<<<<<<<正在爬取第_{}_頁崗位數(shù)據(jù)>>>>>>>>>>>>>".format(self.page_no))
yield scrapy.Request(url=next_url, headers=self.random_header(), callback=self.parse_city)
保存數(shù)據(jù)
from itemadapter import ItemAdapter
class BosszpPipeline:
def process_item(self, item, spider):
"""
保存數(shù)據(jù)到本地 csv 文件
:param item: 數(shù)據(jù)項(xiàng)
:param spider:
:return:
"""
with open(file='全國-熱門城市崗位數(shù)據(jù).csv', mode='a+', encoding='utf8') as f:
f.write(
'{job_name},{job_area},{job_salary},{com_name},{com_type},{com_size},{finance_stage},{work_year},'
'{education},{job_benefits}'.format(
**item))
return item
編輯本地 CSV 文件
job_name,job_area,job_salary,com_name,com_type,com_size,finance_stage,work_year,education,job_benefits
3.3 數(shù)據(jù)清洗與預(yù)處理
完成上面爬蟲程序的編寫與運(yùn)行,我們就能將 Boss 直聘熱門城市崗位數(shù)據(jù)爬取到本地。通過觀察發(fā)現(xiàn)爬取到的數(shù)據(jù)出現(xiàn)了大量的臟數(shù)據(jù)和高耦合的數(shù)據(jù)。我們需要對這些臟數(shù)據(jù)進(jìn)行清洗與預(yù)處理后才能正常使用。
需求:
讀取 全國-熱門城市崗位數(shù)據(jù).csv 文件
對重復(fù)行進(jìn)行清洗。
對工作地址字段進(jìn)行預(yù)處理。要求:北京·海淀區(qū)·西北旺 --> 北京,海淀區(qū),西北旺。分隔成3個字段
對薪資字段進(jìn)行預(yù)處理。要求:30-60K·15薪 --> 最低:30,最高:60
對工作經(jīng)驗(yàn)字段進(jìn)行預(yù)處理。要求:經(jīng)驗(yàn)不限/在校/應(yīng)屆 :0,1-3年:1,3-5年:2,5-10年:3,10年以上:4
對企業(yè)規(guī)模字段進(jìn)行預(yù)處理。要求:500人以下:0,500-999:1,1000-9999:2,10000人以上:3
對崗位福利字段進(jìn)行預(yù)處理。要求:將描述中的中文','(逗號),替換成英文','(逗號)
對缺失值所在行進(jìn)行清洗。
將處理后的數(shù)據(jù)保存到 MySQL 數(shù)據(jù)庫
編寫清洗與預(yù)處理的代碼
# -*- coding:utf-8 -*-
"""
作者:jhzhong
功能:對崗位數(shù)據(jù)進(jìn)行清洗與預(yù)處理
需求:
1. 讀取 `全國-熱門城市崗位數(shù)據(jù).csv` 文件
2. 對重復(fù)行進(jìn)行清洗。
3. 對`工作地址`字段進(jìn)行預(yù)處理。要求:北京·海淀區(qū)·西北旺 --> 北京,海淀區(qū),西北旺。分隔成3個字段
4. 對`薪資`字段進(jìn)行預(yù)處理。要求:30-60K·15薪 --> 最低:30,最高:60
5. 對`工作經(jīng)驗(yàn)`字段進(jìn)行預(yù)處理。要求:經(jīng)驗(yàn)不限/在校/應(yīng)屆 :0,1-3年:1,3-5年:2,5-10年:3,10年以上:4
6. 對`企業(yè)規(guī)模`字段進(jìn)行預(yù)處理。要求:500人以下:0,500-999:1,1000-9999:2,10000人以上:3
7. 對`崗位福利`字段進(jìn)行預(yù)處理。要求:將描述中的中文','(逗號),替換成英文','(逗號)
8. 對缺失值所在行進(jìn)行清洗。
9. 將處理后的數(shù)據(jù)保存到 MySQL 數(shù)據(jù)庫
"""
# 導(dǎo)入模塊
import pandas as pd
from sqlalchemy import create_engine
import logging
# 讀取 全國-熱門城市崗位招聘數(shù)據(jù).csv 文件
all_city_zp_df = pd.read_csv('../全國-熱門城市崗位數(shù)據(jù).csv', encoding='utf8')
# 對重復(fù)行進(jìn)行清洗。
all_city_zp_df.drop_duplicates(inplace=True)
# 對`工作地址`字段進(jìn)行預(yù)處理。要求:北京·海淀區(qū)·西北旺 --> 北京,海淀區(qū),西北旺。分隔成3個字段
all_city_zp_area_df = all_city_zp_df['job_area'].str.split('·', expand=True)
all_city_zp_area_df = all_city_zp_area_df.rename(columns={0: "city", 1: "district", 2: "street"})
# 對`薪資`字段進(jìn)行預(yù)處理。要求:30-60K·15薪 --> 最低:30,最高:60
all_city_zp_salary_df = all_city_zp_df['job_salary'].str.split('K', expand=True)[0].str.split('-', expand=True)
all_city_zp_salary_df = all_city_zp_salary_df.rename(columns={0: 'salary_lower', 1: 'salary_high'})
# 對`工作經(jīng)驗(yàn)`字段進(jìn)行預(yù)處理。要求:經(jīng)驗(yàn)不限/在校/應(yīng)屆 :0,1-3年:1,3-5年:2,5-10年:3,10年以上:4
def fun_work_year(x):
if x in "1-3年":
return 1
elif x in "3-5年":
return 2
elif x in "5-10年":
return 3
elif x in "10年以上":
return 4
else:
return 0
all_city_zp_df['work_year'] = all_city_zp_df['work_year'].apply(lambda x: fun_work_year(x))
# 對`企業(yè)規(guī)模`字段進(jìn)行預(yù)處理。要求:500人以下:0,500-999:1,1000-9999:2,10000人以上:3
def fun_com_size(x):
if x in "500-999人":
return 1
elif x in "1000-9999人":
return 2
elif x in "10000人以上":
return 3
else:
return 0
# 對`崗位福利`字段進(jìn)行預(yù)處理。要求:將描述中的中文','(逗號),替換成英文','(逗號)
all_city_zp_df['job_benefits'] = all_city_zp_df['job_benefits'].str.replace(',', ',')
# 合并所有數(shù)據(jù)集
clean_all_city_zp_df = pd.concat([all_city_zp_df, all_city_zp_salary_df, all_city_zp_area_df], axis=1)
# 刪除冗余列
clean_all_city_zp_df.drop('job_area', axis=1, inplace=True) # 刪除原區(qū)域
clean_all_city_zp_df.drop('job_salary', axis=1, inplace=True) # 刪除原薪資
# 對缺失值所在行進(jìn)行清洗。
clean_all_city_zp_df.dropna(axis=0, how='any', inplace=True)
clean_all_city_zp_df.drop(axis=0,
index=(clean_all_city_zp_df.loc[(clean_all_city_zp_df['job_benefits'] == 'None')].index),
inplace=True)
# 將處理后的數(shù)據(jù)保存到 MySQL 數(shù)據(jù)庫
engine = create_engine('mysql+pymysql://root:123456@localhost:3306/bosszp_db?charset=utf8')
clean_all_city_zp_df.to_sql('t_boss_zp_info', con=engine, if_exists='replace')
logging.info("Write to MySQL Successfully!")
運(yùn)行程序,檢查數(shù)據(jù)是否清洗成功和插入到數(shù)據(jù)庫。
4 數(shù)據(jù)分析與可視化
成功運(yùn)行上面兩個流程后,我們已經(jīng)得到了可用于數(shù)據(jù)分析的高質(zhì)量數(shù)據(jù)。拿到這些數(shù)據(jù)以后,我們使用 python + sql 腳本的方式對數(shù)據(jù)進(jìn)行多維度分析,并使用 highcharts 工具進(jìn)行數(shù)據(jù)可視化。整個分析可視化通過輕量化 WEB 框架 Flask 來進(jìn)行部署。
Flask框架介紹
Flask是一個基于Werkzeug和Jinja2的輕量級Web應(yīng)用程序框架。與其他同類型框架相比,F(xiàn)lask的靈活性、輕便性和安全性更高,而且容易上手,它可以與MVC模式很好地結(jié)合進(jìn)行開發(fā)。Flask也有強(qiáng)大的定制性,開發(fā)者可以依據(jù)實(shí)際需要增加相應(yīng)的功能,在實(shí)現(xiàn)豐富的功能和擴(kuò)展的同時(shí)能夠保證核心功能的簡單。Flask豐富的插件庫能夠讓用戶實(shí)現(xiàn)網(wǎng)站定制的個性化,從而開發(fā)出功能強(qiáng)大的網(wǎng)站。
本項(xiàng)目在Flask開發(fā)后端時(shí),前端請求會遇到跨域的問題,解決該問題有修改數(shù)據(jù)類型為jsonp,采用GET方法,或者在Flask端加上響應(yīng)頭等方式,在此使用安裝Flask-CORS庫的方式解決跨域問題。此外需要安裝請求庫axios。
Flask框架圖
編寫可視化代碼
# -*- coding:utf-8 -*-
"""
功能:數(shù)據(jù)分析于可視化
"""
from flask import Flask, render_template
from bosszp.web.dbutils import DBUtils
import json
app = Flask(__name__)
def get_db_conn():
"""
獲取數(shù)據(jù)庫連接
:return: db_conn 數(shù)據(jù)庫連接對象
"""
return DBUtils(host='localhost', user='root', passw='123456', db='bosszp_db')
def msg(status, data='未加載到數(shù)據(jù)'):
"""
:param status: 狀態(tài)碼 200成功,201未找到數(shù)據(jù)
:param data: 響應(yīng)數(shù)據(jù)
:return: 字典 如{'status': 201, 'data': ‘未加載到數(shù)據(jù)’}
"""
return json.dumps({'status': status, 'data': data})
@app.route('/')
def index():
"""
首頁
:return: index.html 跳轉(zhuǎn)到首頁
"""
return render_template('index.html')
@app.route('/getwordcloud')
def get_word_cloud():
"""
獲取崗位福利詞云數(shù)據(jù)
:return:
"""
db_conn = get_db_conn()
text = \
db_conn.get_one(sql_str="SELECT GROUP_CONCAT(job_benefits) FROM t_boss_zp_info")[0]
if text is None:
return msg(201)
return msg(200, text)
@app.route('/getjobinfo')
def get_job_info():
"""
獲取熱門崗位招聘區(qū)域分布
:return:
"""
db_conn = get_db_conn()
results = db_conn.get_all(
sql_str="SELECT city,district,COUNT(1) as num FROM t_boss_zp_info GROUP BY city,district")
# {"city":"北京","info":[{"district":"朝陽區(qū)","num":27},{"海淀區(qū)":43}]}
if results is None or len(results) == 0:
return msg(201)
data = []
city_detail = {}
for r in results:
info = {'name': r[1], 'value': r[2]}
if r[0] not in city_detail:
city_detail[r[0]] = [info]
else:
city_detail[r[0]].append(info)
for k, v in city_detail.items():
temp = {'name': k, 'data': v}
data.append(temp)
return msg(200, data)
@app.route('/getjobnum')
def get_job_num():
"""
獲取個城市崗位數(shù)量
:return:
"""
db_conn = get_db_conn()
results = db_conn.get_all(sql_str="SELECT city,COUNT(1) num FROM t_boss_zp_info GROUP BY city")
if results is None or len(results) == 0:
return msg(201)
if results is None or len(results) == 0:
return msg(201)
data = []
for r in results:
data.append(list(r))
return msg(200, data)
@app.route('/getcomtypenum')
def get_com_type_num():
"""
獲取企業(yè)類型占比
:return:
"""
db_conn = get_db_conn()
results = db_conn.get_all(
sql_str="SELECT com_type, ROUND(COUNT(1)/(SELECT SUM(t1.num) FROM (SELECT COUNT(1) num FROM t_boss_zp_info GROUP BY com_type) t1)*100,2) percent FROM t_boss_zp_info GROUP BY com_type")
if results is None or len(results) == 0:
return msg(201)
data = []
for r in results:
data.append({'name': r[0], 'y': float(r[1])})
return msg(200, data)
# 扇形圖
@app.route('/geteducationnum')
def geteducationnum():
"""
獲取學(xué)歷占比
:return:
"""
db_conn = get_db_conn()
results = db_conn.get_all(
sql_str="SELECT t1.education,ROUND(t1.num/(SELECT SUM(t2.num) FROM(SELECT COUNT(1) num FROM t_boss_zp_info t GROUP BY t.education)t2)*100,2) FROM( SELECT t.education,COUNT(1) num FROM t_boss_zp_info t GROUP BY t.education) t1")
if results is None or len(results) == 0:
return msg(201)
data = []
for r in results:
data.append([r[0], float(r[1])])
return msg(200, data)
# 獲取排行榜
@app.route('/getorder')
def getorder():
"""
獲取企業(yè)招聘數(shù)量排行榜
:return:
"""
db_conn = get_db_conn()
results = db_conn.get_all(
sql_str="SELECT t.com_name,COUNT(1) FROM t_boss_zp_info t GROUP BY t.com_name ORDER BY COUNT(1) DESC LIMIT 10")
if results is None or len(results) == 0:
return msg(201)
data = []
for i, r in enumerate(results):
data.append({'id': i + 1,
'name': r[0],
'num': r[1]})
return msg(200, data)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8080, debug=True)
運(yùn)行
python run --host=0.0.0.0
現(xiàn)在在瀏覽器中打開 http://127.0.0.1:8080/ ,應(yīng)該可以看到可視化大屏了。文章來源:http://www.zghlxwxcb.cn/news/detail-765035.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-765035.html
5 最后
到了這里,關(guān)于大數(shù)據(jù)畢設(shè)分享 大數(shù)據(jù)招聘崗位數(shù)據(jù)分析與可視化 - 爬蟲 python 大屏可視化的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!