前言
爬取拉勾網(wǎng)關(guān)于python職位相關(guān)的數(shù)據(jù)信息,并將爬取的數(shù)據(jù)已csv各式存入文件,然后對(duì)csv文件相關(guān)字段的數(shù)據(jù)進(jìn)行清洗,并對(duì)數(shù)據(jù)可視化展示,包括柱狀圖展示、直方圖展示、詞云展示等并根據(jù)可視化的數(shù)據(jù)做進(jìn)一步的分析,其余分析和展示讀者可自行發(fā)揮和擴(kuò)展包括各種分析和不同的存儲(chǔ)方式等。。。。。
一、爬取和分析相關(guān)依賴包
- Python版本: Python3.6
- requests: 下載網(wǎng)頁(yè)
- math: 向上取整
- time: 暫停進(jìn)程
- pandas:數(shù)據(jù)分析并保存為csv文件
- matplotlib:繪圖
- pyecharts:繪圖
- statsmodels:統(tǒng)計(jì)建模
- wordcloud、scipy、jieba:生成中文詞云
- pylab:設(shè)置畫圖能顯示中文
在以上安裝或使用過(guò)程中可能讀者會(huì)遇到安裝或?qū)胧〉葐?wèn)題自行百度,選擇依賴包的合適版本
二、分析網(wǎng)頁(yè)結(jié)構(gòu)
通過(guò)Chrome搜索'python工程師',然后右鍵點(diǎn)擊檢查或者F12,,使用檢查功能查看網(wǎng)頁(yè)源代碼,當(dāng)我們點(diǎn)擊下一頁(yè)觀察瀏覽器的搜索欄的url并沒(méi)有改變,這是因?yàn)槔淳W(wǎng)做了反爬蟲(chóng)機(jī)制, 職位信息并不在源代碼里,而是保存在JSON的文件里,因此我們直接下載JSON,并使用字典方法直接讀取數(shù)據(jù).即可拿到我們想要的python職位相關(guān)的信息,
待爬取的python工程師職位信息如下:
為了能爬到我們想要的數(shù)據(jù),我們要用程序來(lái)模擬瀏覽器來(lái)查看網(wǎng)頁(yè),所以我們?cè)谂廊〉倪^(guò)程中會(huì)加上頭信息,頭信息也是我們通過(guò)分析網(wǎng)頁(yè)獲取到的,通過(guò)網(wǎng)頁(yè)分析我們知道該請(qǐng)求的頭信息,以及請(qǐng)求的信息和請(qǐng)求的方式是POST請(qǐng)求,這樣我們就可以該url請(qǐng)求拿到我們想的數(shù)據(jù)做進(jìn)一步處理
爬取網(wǎng)頁(yè)信息代碼如下:
import requests
url = ' https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
def get_json(url, num):
"""
從指定的url中通過(guò)requests請(qǐng)求攜帶請(qǐng)求頭和請(qǐng)求體獲取網(wǎng)頁(yè)中的信息,
:return:
"""
url1 = 'https://www.lagou.com/jobs/list_python%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88?labelWords=&fromSearch=true&suginput='
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
'Host': 'www.lagou.com',
'Referer': 'https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?labelWords=&fromSearch=true&suginput=',
'X-Anit-Forge-Code': '0',
'X-Anit-Forge-Token': 'None',
'X-Requested-With': 'XMLHttpRequest'
}
data = {
'first': 'true',
'pn': num,
'kd': 'python工程師'}
s = requests.Session()
print('建立session:', s, '\n\n')
s.get(url=url1, headers=headers, timeout=3)
cookie = s.cookies
print('獲取cookie:', cookie, '\n\n')
res = requests.post(url, headers=headers, data=data, cookies=cookie, timeout=3)
res.raise_for_status()
res.encoding = 'utf-8'
page_data = res.json()
print('請(qǐng)求響應(yīng)結(jié)果:', page_data, '\n\n')
return page_data
print(get_json(url, 1))
通過(guò)搜索我們知道每頁(yè)顯示15個(gè)職位,最多顯示30頁(yè),通過(guò)分析網(wǎng)頁(yè)源代碼知道,可以通過(guò)JSON里讀取總職位數(shù),通過(guò)總的職位數(shù)和每頁(yè)能顯示的職位數(shù).我們可以計(jì)算出總共有多少頁(yè),然后使用循環(huán)按頁(yè)爬取, 最后將職位信息匯總, 寫入到CSV格式的文件中.
程序運(yùn)行結(jié)果如圖:
爬取所有python相關(guān)職位信息如下:
三、數(shù)據(jù)清洗后入庫(kù)
數(shù)據(jù)清洗其實(shí)會(huì)占用很大一部分工作,我們?cè)谶@里只做一些簡(jiǎn)單的數(shù)據(jù)分析后入庫(kù)。在拉勾網(wǎng)輸入python相關(guān)的職位會(huì)有18988個(gè)。你可以根據(jù)工作中需求選擇要入庫(kù)的字段,并對(duì)一些字段做進(jìn)一步的篩選,比如我們可以去除職位名稱中為實(shí)習(xí)生的崗位,過(guò)濾指定的字段區(qū)域在我們指定區(qū)域的職位,取字段薪資的平均值,以最低值和差值的四分之一為平均值等等根據(jù)需求自由發(fā)揮
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.api as sm
from wordcloud import WordCloud
from scipy.misc import imread
from imageio import imread
import jieba
from pylab import mpl
# 使用matplotlib能夠顯示中文
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默認(rèn)字體
mpl.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負(fù)號(hào)'-'顯示為方塊的問(wèn)題
# 讀取數(shù)據(jù)
df = pd.read_csv('Python_development_engineer.csv', encoding='utf-8')
# 進(jìn)行數(shù)據(jù)清洗,過(guò)濾掉實(shí)習(xí)崗位
# df.drop(df[df['職位名稱'].str.contains('實(shí)習(xí)')].index, inplace=True)
# print(df.describe())
# 由于csv文件中的字符是字符串形式,先用正則表達(dá)式將字符串轉(zhuǎn)化為列表,在去區(qū)間的均值
pattern = '\d+'
# print(df['工作經(jīng)驗(yàn)'], '\n\n\n')
# print(df['工作經(jīng)驗(yàn)'].str.findall(pattern))
df['工作年限'] = df['工作經(jīng)驗(yàn)'].str.findall(pattern)
print(type(df['工作年限']), '\n\n\n')
avg_work_year = []
count = 0
for i in df['工作年限']:
# print('每個(gè)職位對(duì)應(yīng)的工作年限',i)
# 如果工作經(jīng)驗(yàn)為'不限'或'應(yīng)屆畢業(yè)生',那么匹配值為空,工作年限為0
if len(i) == 0:
avg_work_year.append(0)
# print('nihao')
count += 1
# 如果匹配值為一個(gè)數(shù)值,那么返回該數(shù)值
elif len(i) == 1:
# print('hello world')
avg_work_year.append(int(''.join(i)))
count += 1
# 如果匹配為一個(gè)區(qū)間則取平均值
else:
num_list = [int(j) for j in i]
avg_year = sum(num_list) / 2
avg_work_year.append(avg_year)
count += 1
print(count)
df['avg_work_year'] = avg_work_year
# 將字符串轉(zhuǎn)化為列表,薪資取最低值加上區(qū)間值得25%,比較貼近現(xiàn)實(shí)
df['salary'] = df['薪資'].str.findall(pattern)
#
avg_salary_list = []
for k in df['salary']:
int_list = [int(n) for n in k]
avg_salary = int_list[0] + (int_list[1] - int_list[0]) / 4
avg_salary_list.append(avg_salary)
df['月薪'] = avg_salary_list
# df.to_csv('python.csv', index=False)
四、數(shù)據(jù)可視化展示
下面是對(duì)數(shù)據(jù)的可視化展示,僅以部分視圖進(jìn)行一些可視化的展示,如果讀者想對(duì)其他字段做一些展示以及想使用不同的視圖類型進(jìn)行展示,請(qǐng)自行發(fā)揮,注:以下代碼中引入的模塊見(jiàn)最后的完整代碼
1、繪制python薪資的頻率直方圖并保存
如果我們想看看關(guān)于互聯(lián)網(wǎng)行業(yè)python工程師相關(guān)的崗位大家普遍薪資的一個(gè)分部區(qū)間在哪個(gè)范圍,占據(jù)了多達(dá)的比例我們就可以借助matplotlib庫(kù),來(lái)將我們保存在csv文件中的數(shù)據(jù)進(jìn)行可視化的展示,然我們能夠更直觀的看到數(shù)據(jù)的一個(gè)分部趨勢(shì)
# 繪制python薪資的頻率直方圖并保存
plt.hist(df['月薪'],bins=8,facecolor='#ff6700',edgecolor='blue') # bins是默認(rèn)的條形數(shù)目
plt.xlabel('薪資(單位/千元)')
plt.ylabel('頻數(shù)/頻率')
plt.title('python薪資直方圖')
plt.savefig('python薪資分布.jpg')
plt.show()
運(yùn)行結(jié)果如下:
2、繪制python相關(guān)職位的地理位置餅狀圖
通過(guò)地理python職位地理位置的分部我們可以大致了解IT行業(yè)主要集中分部在哪些城市,這樣也更利于我們選擇地域進(jìn)行選擇性就業(yè),可以獲得更多的面試機(jī)會(huì)等,參數(shù)可自行調(diào)試,或根據(jù)需要添加。
# 繪制餅狀圖并保存
city = df['城市'].value_counts()
print(type(city))
# print(len(city))
label = city.keys()
print(label)
city_list = []
count = 0
n = 1
distance = []
for i in city:
city_list.append(i)
print('列表長(zhǎng)度', len(city_list))
count += 1
if count > 5:
n += 0.1
distance.append(n)
else:
distance.append(0)
plt.pie(city_list, labels=label, labeldistance=1.2, autopct='%2.1f%%', pctdistance=0.6, shadow=True, explode=distance)
plt.axis('equal') # 使餅圖為正圓形
plt.legend(loc='upper left', bbox_to_anchor=(-0.1, 1))
plt.savefig('python地理位置分布圖.jpg')
plt.show()
運(yùn)行結(jié)果如下:
3、繪制基于pyechart的城市分布柱狀圖
pycharts是python中調(diào)用百度基于js開(kāi)發(fā)的echarts接口,也可以對(duì)數(shù)據(jù)進(jìn)行各種可視化操作,更多數(shù)據(jù)可視化圖形展示,可參考echarts官網(wǎng):https://www.echartsjs.com/,echarts官網(wǎng)提供了各種實(shí)例供我們參考,如折線圖、柱狀圖、餅圖、路徑圖、樹(shù)圖等等,基于pyecharts的文檔可參考以下官網(wǎng):https://pyecharts.org/#/,更多用法也可自行百度網(wǎng)絡(luò)資源
city = df['城市'].value_counts()
print(type(city))
print(city)
# print(len(city))
keys = city.index # 等價(jià)于keys = city.keys()
values = city.values
from pyecharts import Bar
bar = Bar("python職位的城市分布圖")
bar.add("城市", keys, values)
bar.print_echarts_options() # 該行只為了打印配置項(xiàng),方便調(diào)試時(shí)使用
bar.render(path='a.html')
運(yùn)行結(jié)果如下:
4、繪制python福利相關(guān)的詞云
詞云圖又叫文字云,是對(duì)文本數(shù)據(jù)中出現(xiàn)頻率較高的關(guān)鍵詞予以視覺(jué)上的突出,形成"關(guān)鍵詞的渲染"就類似云一樣的彩色圖片,從而過(guò)濾掉大量的文本信息,,使人一眼就可以領(lǐng)略文本數(shù)據(jù)的主要表達(dá)意思。利用jieba分詞和詞云生成WorldCloud(可自定義背景),下面就是對(duì)python相關(guān)職位的福利做了一個(gè)詞云的展示,可以更直觀的看到大多數(shù)公司的福利待遇集中在哪些地方
# 繪制福利待遇的詞云
text = ''
for line in df['公司福利']:
if len(eval(line)) == 0:
continue
else:
for word in eval(line):
# print(word)
text += word
cut_word = ','.join(jieba.cut(text))
word_background = imread('公主.jpg')
cloud = WordCloud(
font_path=r'C:\Windows\Fonts\simfang.ttf',
background_color='black',
mask=word_background,
max_words=500,
max_font_size=100,
width=400,
height=800
)
word_cloud = cloud.generate(cut_word)
word_cloud.to_file('福利待遇詞云.png')
plt.imshow(word_cloud)
plt.axis('off')
plt.show()
運(yùn)行結(jié)果如下:
五、爬蟲(chóng)及可視化完整代碼
完整代碼在下面,代碼均測(cè)試可正常運(yùn)行,感興趣的小伙伴可去嘗試和了解其中的使用方法,如運(yùn)行或者模塊安裝等失敗可以在評(píng)論區(qū)進(jìn)行留言,讓我們一同解決吧
如果你覺(jué)得對(duì)你有幫助可以點(diǎn)個(gè)贊哦,原創(chuàng)內(nèi)容轉(zhuǎn)載需說(shuō)明出處!!!
1、爬蟲(chóng)完整代碼
為了防止我們頻繁請(qǐng)求一個(gè)網(wǎng)站被限制ip,我們?cè)谂廊∶恳豁?yè)后選擇睡一段時(shí)間,當(dāng)然你也可以使用代理等其他方式自行實(shí)現(xiàn)
import requests
import math
import time
import pandas as pd
def get_json(url, num):
"""
從指定的url中通過(guò)requests請(qǐng)求攜帶請(qǐng)求頭和請(qǐng)求體獲取網(wǎng)頁(yè)中的信息,
:return:
"""
url1 = 'https://www.lagou.com/jobs/list_python%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88?labelWords=&fromSearch=true&suginput='
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
'Host': 'www.lagou.com',
'Referer': 'https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?labelWords=&fromSearch=true&suginput=',
'X-Anit-Forge-Code': '0',
'X-Anit-Forge-Token': 'None',
'X-Requested-With': 'XMLHttpRequest'
}
data = {
'first': 'true',
'pn': num,
'kd': 'python工程師'}
s = requests.Session()
print('建立session:', s, '\n\n')
s.get(url=url1, headers=headers, timeout=3)
cookie = s.cookies
print('獲取cookie:', cookie, '\n\n')
res = requests.post(url, headers=headers, data=data, cookies=cookie, timeout=3)
res.raise_for_status()
res.encoding = 'utf-8'
page_data = res.json()
print('請(qǐng)求響應(yīng)結(jié)果:', page_data, '\n\n')
return page_data
def get_page_num(count):
"""
計(jì)算要抓取的頁(yè)數(shù),通過(guò)在拉勾網(wǎng)輸入關(guān)鍵字信息,可以發(fā)現(xiàn)最多顯示30頁(yè)信息,每頁(yè)最多顯示15個(gè)職位信息
:return:
"""
page_num = math.ceil(count / 15)
if page_num > 30:
return 30
else:
return page_num
def get_page_info(jobs_list):
"""
獲取職位
:param jobs_list:
:return:
"""
page_info_list = []
for i in jobs_list: # 循環(huán)每一頁(yè)所有職位信息
job_info = []
job_info.append(i['companyFullName'])
job_info.append(i['companyShortName'])
job_info.append(i['companySize'])
job_info.append(i['financeStage'])
job_info.append(i['district'])
job_info.append(i['positionName'])
job_info.append(i['workYear'])
job_info.append(i['education'])
job_info.append(i['salary'])
job_info.append(i['positionAdvantage'])
job_info.append(i['industryField'])
job_info.append(i['firstType'])
job_info.append(i['companyLabelList'])
job_info.append(i['secondType'])
job_info.append(i['city'])
page_info_list.append(job_info)
return page_info_list
def main():
url = ' https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
first_page = get_json(url, 1)
total_page_count = first_page['content']['positionResult']['totalCount']
num = get_page_num(total_page_count)
total_info = []
time.sleep(10)
print("python開(kāi)發(fā)相關(guān)職位總數(shù):{},總頁(yè)數(shù)為:{}".format(total_page_count, num))
for num in range(1, num + 1):
# 獲取每一頁(yè)的職位相關(guān)的信息
page_data = get_json(url, num) # 獲取響應(yīng)json
jobs_list = page_data['content']['positionResult']['result'] # 獲取每頁(yè)的所有python相關(guān)的職位信息
page_info = get_page_info(jobs_list)
print("每一頁(yè)python相關(guān)的職位信息:%s" % page_info, '\n\n')
total_info += page_info
print('已經(jīng)爬取到第{}頁(yè),職位總數(shù)為{}'.format(num, len(total_info)))
time.sleep(20)
# 將總數(shù)據(jù)轉(zhuǎn)化為data frame再輸出,然后在寫入到csv各式的文件中
df = pd.DataFrame(data=total_info,
columns=['公司全名', '公司簡(jiǎn)稱', '公司規(guī)模', '融資階段', '區(qū)域', '職位名稱', '工作經(jīng)驗(yàn)', '學(xué)歷要求', '薪資', '職位福利', '經(jīng)營(yíng)范圍',
'職位類型', '公司福利', '第二職位類型', '城市'])
# df.to_csv('Python_development_engineer.csv', index=False)
print('python相關(guān)職位信息已保存')
if __name__ == '__main__':
main()
2、可視化完整代碼
數(shù)據(jù)可視化涉及到matplotlib、jieba、wordcloud、pyecharts、pylab、scipy等等模塊的使用,讀者可以自行了解各個(gè)模塊的使用方法,和其中涉及的各種參數(shù)
import pandas as pd
import matplotlib.pyplot as plt
import statsmodels.api as sm
from wordcloud import WordCloud
from scipy.misc import imread
# from imageio import imread
import jieba
from pylab import mpl
# 使用matplotlib能夠顯示中文
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默認(rèn)字體
mpl.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負(fù)號(hào)'-'顯示為方塊的問(wèn)題
# 讀取數(shù)據(jù)
df = pd.read_csv('Python_development_engineer.csv', encoding='utf-8')
# 進(jìn)行數(shù)據(jù)清洗,過(guò)濾掉實(shí)習(xí)崗位
# df.drop(df[df['職位名稱'].str.contains('實(shí)習(xí)')].index, inplace=True)
# print(df.describe())
# 由于csv文件中的字符是字符串形式,先用正則表達(dá)式將字符串轉(zhuǎn)化為列表,在去區(qū)間的均值
pattern = '\d+'
# print(df['工作經(jīng)驗(yàn)'], '\n\n\n')
# print(df['工作經(jīng)驗(yàn)'].str.findall(pattern))
df['工作年限'] = df['工作經(jīng)驗(yàn)'].str.findall(pattern)
print(type(df['工作年限']), '\n\n\n')
avg_work_year = []
count = 0
for i in df['工作年限']:
# print('每個(gè)職位對(duì)應(yīng)的工作年限',i)
# 如果工作經(jīng)驗(yàn)為'不限'或'應(yīng)屆畢業(yè)生',那么匹配值為空,工作年限為0
if len(i) == 0:
avg_work_year.append(0)
# print('nihao')
count += 1
# 如果匹配值為一個(gè)數(shù)值,那么返回該數(shù)值
elif len(i) == 1:
# print('hello world')
avg_work_year.append(int(''.join(i)))
count += 1
# 如果匹配為一個(gè)區(qū)間則取平均值
else:
num_list = [int(j) for j in i]
avg_year = sum(num_list) / 2
avg_work_year.append(avg_year)
count += 1
print(count)
df['avg_work_year'] = avg_work_year
# 將字符串轉(zhuǎn)化為列表,薪資取最低值加上區(qū)間值得25%,比較貼近現(xiàn)實(shí)
df['salary'] = df['薪資'].str.findall(pattern)
#
avg_salary_list = []
for k in df['salary']:
int_list = [int(n) for n in k]
avg_salary = int_list[0] + (int_list[1] - int_list[0]) / 4
avg_salary_list.append(avg_salary)
df['月薪'] = avg_salary_list
# df.to_csv('python.csv', index=False)
"""1、繪制python薪資的頻率直方圖并保存"""
plt.hist(df['月薪'], bins=8, facecolor='#ff6700', edgecolor='blue') # bins是默認(rèn)的條形數(shù)目
plt.xlabel('薪資(單位/千元)')
plt.ylabel('頻數(shù)/頻率')
plt.title('python薪資直方圖')
plt.savefig('python薪資分布.jpg')
plt.show()
"""2、繪制餅狀圖并保存"""
city = df['城市'].value_counts()
print(type(city))
# print(len(city))
label = city.keys()
print(label)
city_list = []
count = 0
n = 1
distance = []
for i in city:
city_list.append(i)
print('列表長(zhǎng)度', len(city_list))
count += 1
if count > 5:
n += 0.1
distance.append(n)
else:
distance.append(0)
plt.pie(city_list, labels=label, labeldistance=1.2, autopct='%2.1f%%', pctdistance=0.6, shadow=True, explode=distance)
plt.axis('equal') # 使餅圖為正圓形
plt.legend(loc='upper left', bbox_to_anchor=(-0.1, 1))
plt.savefig('python地理位置分布圖.jpg')
plt.show()
"""3、繪制福利待遇的詞云"""
text = ''
for line in df['公司福利']:
if len(eval(line)) == 0:
continue
else:
for word in eval(line):
# print(word)
text += word
cut_word = ','.join(jieba.cut(text))
word_background = imread('公主.jpg')
cloud = WordCloud(
font_path=r'C:\Windows\Fonts\simfang.ttf',
background_color='black',
mask=word_background,
max_words=500,
max_font_size=100,
width=400,
height=800
)
word_cloud = cloud.generate(cut_word)
word_cloud.to_file('福利待遇詞云.png')
plt.imshow(word_cloud)
plt.axis('off')
plt.show()
"""4、基于pyechart的柱狀圖"""
city = df['城市'].value_counts()
print(type(city))
print(city)
# print(len(city))
keys = city.index # 等價(jià)于keys = city.keys()
values = city.values
from pyecharts import Bar
bar = Bar("python職位的城市分布圖")
bar.add("城市", keys, values)
bar.print_echarts_options() # 該行只為了打印配置項(xiàng),方便調(diào)試時(shí)使用
bar.render(path='a.html')
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元

