一句話概括本文:
爬取拉鉤Android職位相關資料,利用numpy,pandas和matplotlib對招人公司 情況和招聘要求進行資料分析。
引言:
在寫完上一篇《淺嘗Python資料分析:分析2018政府工作報告中的高頻詞》, 一直都處於一種亢奮的狀態,滿腦子都想著資料分析,膜一下當然很開心, 更重要的是感受到了Python資料分析的好玩,迫不及待地想寫個新的東西玩玩, 這不,給我翻到一個好玩的東西:《Python拉鉤資料採集與視覺化》 就是採集拉鉤上關於Python崗位的相關資訊,然後做資料分析,通過 圖表的形式把分析結果展示給別人看;在我潛水的很多個Android群裡 普遍有這樣的反饋:儘管是現在是招聘的金三銀四,但是Android的工作 真不好找?原因是Android崗位稀缺?要求過高?薪資問題?又或者其他 因素,我決定通過Python來採集相關資料,利用numpy,pandas,matplotlib 資料分析基礎三件胡亂分析一波:
試圖從分析結果中獲取點什麼有用的資訊,以便了解方便自己更好的瞭解 市場行情,不逼逼,開始本節內容~
1.知道下資料分析三件套
在開始之前你可能需要大概瞭解下這三個庫:numpy,pandas和matplotlib, 資料分析必備三件套,考慮如果要把文件吃透需要不少時間,還有文章篇幅 等原因,這裡不慢慢去啃了,後續可能會寫單獨的教學章節,本節給出相關 的參考連結,有興趣可先行自己研究~
書:《Python for Data Analysis, 2nd Edition》
PDF下載:Python for Data Analysis, 2nd Edition.pdf 中文翻譯:利用Python進行資料分析·第2版
numpy庫:
科學計算基礎包,為Python提供快速的陣列處理能力, 作為在演算法和庫之間傳遞資料的容器。 NumPy是在在一個連續的記憶體塊中儲存資料,獨立於其他Python內建物件。 NumPy的C語言編寫的演算法庫可以操作記憶體,而不必進行型別檢查或其它 前期工作。比起Python的內建序列,NumPy陣列使用的記憶體更少。
學習連結:
pandas庫:
提供了快速便捷處理結構化資料的大量資料結構和函式,有兩種資料
常見的資料結構,分別為:Series
(一維的標籤化陣列物件)和
DataFrame
(面向列的二維表結構)
學習連結:
- 十分鐘上手pandas:pandas.pydata.org/pandas-docs…
- 更多內容:pandas.pydata.org/pandas-docs…
matplotlib庫
用於繪製圖表和其它二維資料視覺化的Python庫
學習連結:
2.資料爬取
打算分析一波深圳區的,開啟首頁www.lagou.com/ 進去後選擇深圳站,搜尋欄輸入 android點進去後,發現有30頁:
隨手點下一頁,頁面沒有整個重新整理,基本都是Ajax了,
F12開發者選項,開啟抓包,Network選項卡clear一下,
選中**XHR
**,點下一頁,喲,有兩個:
點選preview看下具體的json內容:
不知道是什麼東西,隨手複製個451,然後切換到Element搜尋,
喲,原來是公司id,拼接下可以獲得一個跳到公司詳細資訊的url, 這裡暫時沒用,approve,譯作認證,就是認證公司id列表, 跟著一個true,猜測是企業是否認證的標識,可能是頁面上 不顯示未認證企業或者顯示不一樣的UI吧,接著看下一個介面:
明顯就是我們想Get的資料,hrInfoMap欄位是和HR相關的資訊,沒用 跳過,最下面的result陣列則是我們最關注的招聘資訊了,點開一個 確認下:
知道了要爬哪裡的資料,接著就是到怎麼模擬請求了:
先是請求頭,因為沒登入就可以訪問了,Cookies就不用傳了, 其他的能帶上就帶上,多了也沒什麼,然後是連結後面附帶 的引數,固定的不用改:
- city: 深圳
- needAddtionalResult: false
- isSchoolJob: 0
然後是Post提交的表單資料:
- first: false
- pn: 2
- kd: android
pn是頁碼,其他的都不用動!都清楚了,接著就寫下程式碼 模擬下了,流程都一清二楚了,不難寫出下面的程式碼:
執行下,把結果貼到Json格式化工具裡:
可以,另外這裡還有個點可以get以下,就是總共有多少頁,總共有738條資料, 每頁顯示15個,738/15=49,測了下確實是最後一頁!
接著捋一捋想要採集的欄位:
公司id
,招聘崗位
id,公司全名
,招聘職位名
,工作年限
,
學歷
,性質
,行業領域
,公司優勢
, 薪資範圍
,公司規模
,
技能標籤
,融資狀態
,公司標籤
,所在區域
,公司經度
,
公司緯度
因為我自己買的代理很多都是連線超時或者拒絕連線等各種問題, 所以直接用本機ip爬,隨機5-15s避免ip被封,趁著去吃飯的空檔, 讓他自己慢慢爬。一開始是打算寫正則來摳資料的,按照返回的 Json結構,我試著寫了這樣的正則:
執行後,看到爬取了4,5頁沒什麼問題,於是乎安心去吃飯了,後來 發現部分資料都亂套了,原來是有些頁面的Json欄位順序不一樣,我服...
還是迴歸Json按照欄位取穩妥,手動摳欄位,拼成一個列表, 最後塞一個陣列裡,最後通過**pandas庫的to_csv()**方法轉換 為一個列表。
3.用pandas的to_csv方法把資料都塞Excel裡
程式碼如下:
執行完後會在當前工程下生成一個result.csv檔案,開啟檢查下資料是否 都正確,處理下髒資料,發現有五個資料位置是錯亂的:
依次檢視錯亂的原因:
Android高階開發工程師 
最新iMAC 
雙休 
待遇豐厚 
Android系統&
移動開發經理 (Android &
移動App開發工程師(Android&
複製程式碼
這裡簡直是巨坑,上面的 
和&
是Html裡的轉義字元,需要呼叫
html.unescape
()方法轉義一波,對應相反的方法**escape
**()
當爬取的內容是字串的時候要小心這個坑!!!修改後的程式碼:
總共採集到736條資料,不算多,但也可以開始做資料分析了。
4.資料分析前可能遇到的一些問題
1)matplotlib中文亂碼問題
主要使用條形圖,餅圖和詞雲來展示資料分析結果! 使用matplotlib進行圖示繪製,基本都會遇到的一個問題,中文亂碼, 解決流程如下:
開啟終端,cd到路徑下,然後準備一枚中文ttf,接著命令列sudo mv 把ttf檔案拷貝到該路徑下:
接著雙擊安裝,安裝後修改配置檔案,對如圖三處做相應修改:
修改完畢後,執行下述命令刪除一波快取檔案
接著再執行就可以了:
其他系統處理matplotlib中文亂碼問題自行參見:matplotlib圖例中文亂碼
2)matplotlib繪製顯示不全
如圖所示,在繪製的時候可能會出現顯示不全的情況:
順道介紹下按鈕,依次是:
重置回主檢視,上一步檢視,下一步檢視,拖拽頁面, 區域性放大,設定,儲存成圖片
然後的話,可以點下設定,會出現:
拖拉調整下,直到差不多能顯示完全
接著記錄下對應的引數,程式碼中設定下:
5.開始資料分析
一.分析招聘公司的一些情況
行業領域
從詞雲可以看出,Android招聘大部分還是移動網際網路公司,接著依次是金融, 硬體,電子商務,電子商務?都是幹嘛的,利用pandas做下簡單篩選,
隨手搜了幾個百度下,這種從事電子商務大概是: 電商(有自己的購物APP,平臺),外包,支付,POS機等 接著是遊戲,資料服務,企業服務,o2o等等。
公司規模
融資狀態
PS:臥槽,15-50人和未融資公司的百分比竟然異常接近,應該大部分都是 小型的創業公司吧,基本都很坑...
所在區域
大部分招Android的公司還是集中在南山區,其次是福田區和寶安區, 小部分在龍華新區和龍崗區。
公司標籤
看下公司都打著怎麼樣的標籤招人
公司優勢
和上面一個樣,假如你公司要你寫招聘條件的時候,就不愁寫什麼啦~
二.分析對招聘者的一些要求
工作年限
招最多的是3-5年工作經驗,其次是1-3年,再接著是5-10年
學歷要求
以前以為學歷不重要,然而圖中本科要求佔比71.8%,沒有本科學歷意味著: 可能失去七成的機會,哭哭/(ㄒoㄒ)/~~,我這種渣渣還是繼續當鹹魚吧...
薪資情況
拉鉤標的薪酬都是有個範圍的,其實一般最小值就是你實際進公司後的 薪資,直接以最小值作為參考,圖中明顯的三個小高峰,10k,15k,8k。 猜測對應: 10k - 3年經驗左右的一般的中初級工程師 15k - 3-5年經驗的技術較好的中高階工程師 8k - 1到3年內的初中級工程師 當然土豪公司不在範圍內,看完自己找工作的時候開口要多少錢, 心裡應該有點B數啦。(哭哭,又拖後腿了/(ㄒoㄒ)/~~)
技能標籤
Java, iOS,架構,C++,系統開發,中級,高階,資深,視訊,資訊保安...
要求Java我能理解,這要求iOS是什麼鬼?現在找個Android崗都要會iOS了? 後來才發現並沒那麼誇張,只是招聘職位那裡Android/iOS,所以才有iOS 的標籤,還有些瞎幾把填的標籤,進去招聘要求裡一個iOS的字眼也沒有。
到此就分析完啦~
6.小結
本節依次抓取了一波拉勾網和Android職位相關的資料,利用這些資料對 公司情況和招聘要求進行了分析,通過圖表以及詞雲的形式,儘管沒有 得出非常有用的資訊,不過應該也get了不少東西,上上週週一就立flag 出的,結果因為專案發新版本,自己感冒涼了幾天,一直拖到現在... 因為篇幅和時間關係,有兩個遺憾:Jupyter Notebook 和 geopandas, 前者是用作資料視覺化展示的一個很強大的工具,而後者則是生成 地圖類的一個庫,還記得我們採集到的經緯度麼?弄一個類似於熱力 圖的東東不是很酷麼?學習成本有點高,後面再了試試吧!
附:最終程式碼(都可以在:github.com/coder-pig/R… 找到):
# 拉勾網Android招聘資料分析
import urllib.parse
import requests
import xlwt
import xlrd
import tools as t
import pandas as pd
import geopandas as gp
import re
import random
import time
import html
import matplotlib.pyplot as plt
import numpy as np
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
from collections import Counter
from scipy.misc import imread
import config as c
from shapely.geometry import Point, Polygon
max_page = 1
result_save_file = c.outputs_logs_path + 'result.csv'
pic_save_path = c.outputs_pictures_path + 'LaGou/'
default_font = c.res_documents + 'wryh.ttf' # 生成詞雲用的預設字型
default_mask = c.res_pictures + 'default_mask.jpg' # 預設遮罩圖片
# Ajax載入url
ajax_url = "https://www.lagou.com/jobs/positionAjax.json?"
# url拼接引數
request_params = {'px': 'default', 'city': '深圳', 'needAddtionalResult': 'false', 'isSchoolJob': '0'}
# post提交引數
form_data = {'first': 'false', 'pn': '1', 'kd': 'android'}
# 獲得頁數的正則
page_pattern = re.compile('"totalCount":(\d*),', re.S)
# csv表頭
csv_headers = [
'公司id', '職位名稱', '工作年限', '學歷', '職位性質', '薪資',
'融資狀態', '行業領域', '招聘崗位id', '公司優勢', '公司規模',
'公司標籤', '所在區域', '技能標籤', '公司經度', '公司緯度', '公司全名'
]
# 模擬請求頭
ajax_headers = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Host': 'www.lagou.com',
'Origin': 'https://www.lagou.com',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 '
'Safari/537.36',
'X-Anit-Forge-Code': '0',
'X-Anit-Forge-Token': 'None',
'X-Requested-With': 'XMLHttpRequest',
'Referer': 'https://www.lagou.com/jobs/list_android?labelWords=&fromSearch=true&suginput='
}
# 獲取每頁招聘資訊
def fetch_data(page):
fetch_url = ajax_url + urllib.parse.urlencode(request_params)
global max_page
while True:
try:
form_data['pn'] = page
print("抓取第:" + str(page) + "頁!")
resp = requests.post(url=fetch_url, data=form_data, headers=ajax_headers)
if resp.status_code == 200:
if page == 1:
max_page = int(int(page_pattern.search(resp.text).group(1)) / 15)
print("總共有:" + str(max_page) + "頁")
data_json = resp.json()['content']['positionResult']['result']
data_list = []
for data in data_json:
data_list.append((data['companyId'],
html.unescape(data['positionName']),
data['workYear'],
data['education'],
data['jobNature'],
data['salary'],
data['financeStage'],
data['industryField'],
data['positionId'],
html.unescape(data['positionAdvantage']),
data['companySize'],
data['companyLabelList'],
data['district'],
html.unescape(data['positionLables']),
data['longitude'],
data['latitude'],
html.unescape(data['companyFullName'])))
result = pd.DataFrame(data_list)
if page == 1:
result.to_csv(result_save_file, header=csv_headers, index=False, mode='a+')
else:
result.to_csv(result_save_file, header=False, index=False, mode='a+')
return None
except Exception as e:
print(e)
# 生成詞雲檔案
def make_wc(content, file_name, mask_pic=default_mask, font=default_font):
bg_pic = imread(mask_pic)
pic_colors = ImageColorGenerator(bg_pic)
wc = WordCloud(font_path=font, background_color='white', margin=2, max_font_size=250,
width=2000, height=2000,
min_font_size=30, max_words=1000)
wc.generate_from_frequencies(content)
wc.to_file(file_name)
# 資料分析方法(生成相關檔案)
def data_analysis(data):
# 1.分析招聘公司的相關資訊
# 行業領域
industry_field_list = []
for industry_field in data['行業領域']:
for field in industry_field.strip().replace(" ", ",").replace("、", ",").split(','):
industry_field_list.append(field)
counter = dict(Counter(industry_field_list))
counter.pop('')
make_wc(counter, pic_save_path + "wc_1.jpg")
# 公司規模
plt.figure(1)
data['公司規模'].value_counts().plot(kind='pie', autopct='%1.1f%%', explode=np.linspace(0, 0.5, 6))
plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
bottom=0.17, top=0.84)
plt.savefig(pic_save_path + 'result_1.jpg')
plt.close(1)
# 融資狀態
plt.figure(2)
data['融資狀態'].value_counts().plot(kind='pie', autopct='%1.1f%%')
plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
bottom=0.17, top=0.84)
plt.savefig(pic_save_path + 'result_2.jpg')
plt.close(2)
# 所在區域
plt.figure(3)
data['所在區域'].value_counts().plot(kind='pie', autopct='%1.1f%%', explode=[0, 0, 0, 0, 0, 0, 0, 1, 1.5])
plt.subplots_adjust(left=0.31, right=0.74, wspace=0.20, hspace=0.20,
bottom=0.26, top=0.84)
plt.savefig(pic_save_path + 'result_3.jpg')
plt.close(3)
# 公司標籤
tags_list = []
for tags in data['公司標籤']:
for tag in tags.strip().replace("[", "").replace("]", "").replace("'", "").split(','):
tags_list.append(tag)
counter = dict(Counter(tags_list))
counter.pop('')
make_wc(counter, pic_save_path + "wc_2.jpg")
# 公司優勢
advantage_list = []
for advantage_field in data['公司優勢']:
for field in advantage_field.strip().replace(" ", ",").replace("、", ",").replace(",", ",").replace("+", ",") \
.split(','):
industry_field_list.append(field)
counter = dict(Counter(industry_field_list))
counter.pop('')
counter.pop('移動網際網路')
make_wc(counter, pic_save_path + "wc_3.jpg")
# 2.分析招聘需求
# 工作年限要求
# 橫向條形圖
plt.figure(4)
data['工作年限'].value_counts().plot(kind='barh', rot=0)
plt.title("工作經驗直方圖")
plt.xlabel("年限/年")
plt.ylabel("公司/個")
plt.savefig(pic_save_path + 'result_4.jpg')
plt.close(4)
# 餅圖
plt.figure(5)
data['工作年限'].value_counts().plot(kind='pie', autopct='%1.1f%%', explode=np.linspace(0, 0.75, 6))
plt.title("工作經驗餅圖")
plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
bottom=0.17, top=0.84)
plt.savefig(pic_save_path + 'result_5.jpg')
plt.close(5)
# 學歷要求
plt.figure(6)
data['學歷'].value_counts().plot(kind='pie', autopct='%1.1f%%', explode=(0, 0.1, 0.2))
plt.title("學歷餅圖")
plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
bottom=0.17, top=0.84)
plt.savefig(pic_save_path + 'result_6.jpg')
plt.close(6)
# 薪資(先去掉後部分的最大工資,過濾掉kK以上詞彙,獲取索引按照整數生序排列)
plt.figure(7)
salary = data['薪資'].str.split('-').str.get(0).str.replace('k|K|以上', "").value_counts()
salary_index = list(salary.index)
salary_index.sort(key=lambda x: int(x))
final_salary = salary.reindex(salary_index)
plt.title("薪資條形圖")
final_salary.plot(kind='bar', rot=0)
plt.xlabel("薪資/K")
plt.ylabel("公司/個")
plt.savefig(pic_save_path + 'result_7.jpg')
plt.close(7)
# 技能標籤
skill_list = []
for skills in data['技能標籤']:
for skill in skills.strip().replace("[", "").replace("]", "").replace("'", "").split(','):
skill_list.append(skill)
counter = dict(Counter(skill_list))
counter.pop('')
counter.pop('Android')
make_wc(counter, pic_save_path + "wc_4.jpg")
# 處理資料
if __name__ == '__main__':
t.is_dir_existed(pic_save_path)
if not t.is_dir_existed(result_save_file, mkdir=False):
fetch_data(1)
for cur_page in range(2, max_page + 1):
# 隨緣休息5-15s
time.sleep(random.randint(5, 15))
fetch_data(cur_page)
else:
raw_data = pd.read_csv(result_save_file)
# data_analysis(raw_data)
# 篩選電子商務公司
dzsw_result = raw_data.loc[raw_data["行業領域"].str.find("電子商務") != -1, ["行業領域", "公司全名"]]
dzsw_result.to_csv(c.outputs_logs_path + "dzsw.csv", header=False, index=False, mode='a+')
# 篩選人15-50人的公司
p_num_result = raw_data.loc[raw_data["所在區域"] == "龍華新區", ["所在區域", "公司全名"]]
p_num_result.to_csv(c.outputs_logs_path + "lhxq.csv", header=False, index=False, mode='a+')
複製程式碼
來啊,Py交易啊
想加群一起學習Py的可以加下,智障機器人小Pig,驗證資訊裡包含: Python,python,py,Py,加群,交易,屁眼 中的一個關鍵詞即可通過;
驗證通過後回覆 加群 即可獲得加群連結(不要把機器人玩壞了!!!)~~~ 歡迎各種像我一樣的Py初學者,Py大神加入,一起愉快地交流學♂習,van♂轉py。