最近有不少程序員又開始找工作了,為了了解目前技術類各職位的數量、薪資、招聘公司、崗位職責及要求,我爬取了拉勾網北上廣深4個城市的招聘數據,共3w條。職位包括:人工智能(AI)、大數據、數據分析、后端(Java、C|C++、PHP、Python)、前端、Android、iOS、嵌入式和測試。下面我將分兩部分進行介紹,第一部分是數據抓取;第二部分是數據分析。如需源代碼在公眾號(見文末)回復關鍵字 職位 即可。如遇到圖片打不開的問題,可訪問:https://juejin.im/post/5e83edfbf265da47d537ba74
數據抓取
這里我並不是通過傳統的抓網頁,解析HTML代碼的方式爬取數據,而是用 Charles 軟件抓取拉鈎APP請求數據的接口實現。
大概的流程是啟動Charles -> 手機連接Charles代理(二者需處於同一個局域網)-> 打開APP請求數據->觀察Charles截的包,從中找到我們想要的接口
首先,找到搜索職位的接口
/v1/entry/positionsearch/searchPosition
這是一個 POST 請求,我們還要找到請求的 header 和 body,最關鍵的 header 和 body 如下
header:
'X-L-REQ-HEADER': '{"deviceType":150,"userType":0,"lgId":"11835BCC-8815-456A-A094-64FB2B9323EF_1585362240","reqVersion":73600,"appVersion":"7.36.0","userToken":"xxx"}'
'content-type': "application/json"
其中,userToken字段每個不一樣,需要自己抓包確定
body
{"tagType": "", "isAd": "1", "showId": "", "district": "", "keywordSource": 0, "keyword": "數據開發",
"salaryUpper": 0, "hiTag": "", "longitudeAndLatitude": "-1.000000,-1.000000", "pageNo": 1, "sort": 0,
"pageSize": 15, "refreshHiTagList": True, "lastShowCompanyId": 0, "nearByKilometers": "", "city": "北京",
"businessZone": "", "shieldDeliveyCompany": False, "salaryLower": 0, "subwayLineName": "",
"subwayStation": ""}
其中,我們只需要關注 keyword,pageNo,pageSize字段,分別代表搜索什么職位,搜索第幾頁,每頁搜多少條。
有了這個信息我們就可以通過程序來請求不同的職位數據,同時為了獲取職位更詳細的信息我們還可以查找獲取職位詳情頁的接口,方式與此類似,這里就不再贅述了。請求職位的代碼如下
def get_data(self):
for city in self.cities_conf:
for position in self.positions_conf:
self.position_search_body['keyword'] = position
self.position_search_body['city'] = city
pageNo = 1
has_more = 1
while has_more:
try:
self.position_search_body['pageNo'] = pageNo
url = 'https://gate.lagou.com/v1/entry/positionsearch/searchPosition'
res = requests.post(url, data=json.dumps(self.position_search_body), headers=self.headers)
print('成功爬取%s市-%s職位的第%d頁數據!' % (city, position, pageNo))
item = {'city': city, 'pType': position}
print(res.json())
positionCardVos = res.json()['content']['positionCardVos']
self._parse_record(positionCardVos, item)
pageNo += 1
if positionCardVos is None or len(positionCardVos) < 15:
has_more = 0
time.sleep(random.random() * 5)
except Exception as e:
msg = '鏈接訪問不成功,正在重試!Exception: %s' % e
print(msg)
time.sleep((1 + random.random()) * 10)
變量 position 代表不同的職位,這里請求的時候會加隨機停留時間,目的為了防止請求過於平凡。我們抓去別人的數據應該注意這一點,不能惡意爬別人的數據。應該模擬得更像普通人一樣去請求數據,如果請求過於頻繁導致別人服務出現問題那真實罪大惡極。
_parse_record 方法是解析請求的數據,並存入mongo。首先解析數據沒什么好說的,就是解析json而已。簡單說下為什么存入mongo,第一,解析的json數據,mongo存儲就是用json格式,讀取和寫入非常方便;第二,mongo不用提前設計表Schema,對我們這種臨時性和不確定性的分析帶來方便;第三,mongo可以存儲海量的數據;第四,mongo會緩存熱點數據,我們在后續分析時候讀取會非常快。
_parse_record 方法代碼如下,為了避免啰嗦,我只保留部分字段的解析,其他的代碼可以下載詳細代碼來看
def _parse_record(self, data, item):
if data:
for position in data:
item['pId'] = position.get('positionId')
item['_id'] = '%s_%s_%d' % (item['city'], item['pType'], item['pId'])
# ... 省略
try:
position_detail_res = requests.get(self.position_detail_url % item['pId']
, timeout=20, headers=self.headers) # 請求詳情頁的數據
position_content = position_detail_res.json()['content']
item['pAdvantage'] = position_content.get('positionAdvantage')
# ...省略
time.sleep(random.random() * 2)
except Exception as e:
msg = '抓去職位%d詳情頁失敗, Exception: %s' % (item['pId'], e)
print(msg)
self.db['positions'].update_one({'_id': item['_id']}, {'$set': item}, upsert=True)
msg = '成功保存數據:{}!'.format(item)
print(msg)
可以看到方法中還請求了職位詳情數據來豐富每一條數據的維度。
數據分析
抓取數據后下面就是分析了,主要用pandas進行統計和畫圖。由於代碼是用jupyter寫的,這里不方便貼,所以我直接貼結論,感興趣的朋友可以自行查看詳細代碼。
1、哪個城市目前招聘的崗位多
可以看到,目前北京招聘的崗位最多,其次是上海和深圳,廣州是最少的。
2、每個城市各崗位的需求量
北上廣深4個城市目前招聘較多的崗位主要是后端-Java、前端、AI和測試。
3、各崗位的平均薪資情況
AI崗位的薪資最高,平均每個月30k以上;其次是大數據崗位,平均每個月26k左右,iOS的平均薪資比Android稍微高一些。另外,目前的前端崗位平均薪資偏低。
4、幾年工作經驗比較吃香
以北京招聘數據為例,目前招聘的各崗位都是以3-5年工作經驗為主,1-3年經驗的需求量不大。所以,這里也要提醒職場新人,不要輕易跳槽。
其他城市的分布情況與北京類似,這里就不貼圖了。
5、什么學歷比較吃香
以北京為例,目前招聘的崗位除了AI需要不少的碩士甚至博士外,其他崗位以本科學歷為主。
其他城市分布與北京類似。
6、什么規模公司對崗位需求大
北京
廣州
可以看到,北京招聘的企業主要是2000人以上規模的大公司,上海和深圳的分布與北京類似。而廣州在AI、前端和后端-Java幾個崗位的招聘主要以50-1000人的中等規模公司為主。
7、HR什么時間段更活躍
以北京為例,各崗位的HR大部分在下午活躍,所以大家可以將簡歷的投遞時間選在下午。
其他城市分布與北京類似。
8、崗位的職責和要求
限於篇幅,我只跑了AI、后端-Java和前端這3個崗位的數據,以詞雲的形式展現
希望這次分析能對你有用,歡迎公眾號「渡碼」,回復關鍵字“職位”即可獲取本次分析的源碼。