前程無憂崗位數據爬取+Tableau可視化分析


一、項目背景

隨着科技的不斷進步與發展,數據呈現爆發式的增長,各行各業對於數據的依賴越來越強,與數據打交道在所難免,而社會對於“數據”方面的人才需求也在不斷增大。因此了解當下企業究竟需要招聘什么樣的人才?需要什么樣的技能?不管是對於在校生,還是對於求職者來說,都顯得十分必要。

對於一名小白來說,想要入門數據分析,首先要了解目前社會對於數據相關崗位的需求情況,基於這一問題,本文針對前程無憂招聘網站,利用python爬取了其全國范圍內大數據、數據分析、數據挖掘、機器學習、人工智能等與數據相關的崗位招聘信息。並通過Tableau可視化工具分析比較了不同行業的崗位薪資、用人需求等情況;以及不同行業、崗位的知識、技能要求等。

二、數據爬取

  • 爬取字段:崗位名稱、公司名稱、薪資水平、工作經驗、學歷需求、工作地點、招聘人數、發布時間、公司類型、公司規模、行業領域、福利待遇、職位信息;
  • 說明:在前程無憂招聘網站中,我們在搜索框中輸入“數據”兩個字進行搜索發現,共有2000個一級頁面,其中每個頁面包含50條崗位信息;

一級頁面如下:

        二級頁面如下:

  • 爬取思路:先針對一級頁面爬取所有崗位對應的二級頁面鏈接,再根據二級頁面鏈接遍歷爬取相應崗位信息;
  • 開發環境:python3、Spyder

1、相關庫的導入與說明

import json
import requests
import pandas as pd
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from lxml import etree
from selenium.webdriver import ChromeOptions

由於前程無憂招聘網站的反爬機制較強,采用動態渲染+限制ip訪問頻率等多層反爬,因此在獲取二級頁面鏈接時需借助json進行解析,本文對於二級頁面崗位信息的獲取采用selenium模擬瀏覽器爬取,同時通過代理IP的方式,每隔一段時間換一次請求IP以免觸發網站反爬機制。 

2、獲取二級頁面鏈接

1)分析一級頁面url特征

# 第一頁URL的特征
"https://search.51job.com/list/000000,000000,0000,00,9,99,數據,2,1.html?"
# 第二頁URL的特征
"https://search.51job.com/list/000000,000000,0000,00,9,99,數據,2,2.html?"
# 第三頁URL的特征
"https://search.51job.com/list/000000,000000,0000,00,9,99,數據,2,3.html?"

通過觀察不同頁面的URL可以發現,不同頁面的URL鏈接只有“.html”前面的數字不同,該數字正好代表該頁的頁碼 ,因此只需要構造字符串拼接,然后通過for循環語句即可構造自動翻頁。

2)構建一級url庫

url1 = []
for i in range(2000):
    url_pre = "https://search.51job.com/list/000000,000000,0000,00,9,99,數據,2,%s" % (1+i) #設置自動翻頁   
    url_end = ".html?"
    url_all = url_pre + url_end
    url1.append(url_all)
print("一級URL庫創建完畢")

注意:爬取二級URL鏈接時發現並非爬取的所有鏈接都是規范的,會存在少部分異常URL,這會對后續崗位信息的爬取造成干擾,因此需要利用if條件語句對其進行剔除。

三、數據清洗

1、數據讀取、去重、空值處理

在獲取了所需數據之后,可以看出數據較亂,並不利於我們進行分析,因此在分析前需要對數據進行預處理,得到規范格式的數據才可以用來最終做可視化數據展示。

獲取的數據截圖如下:

1)相關庫導入及數據讀取

#導入相關庫
import pandas as pd
import numpy as np
import jieba
 
#讀取數據
df = pd.read_excel(r'E:\python爬蟲\前程無憂招聘信息.xlsx',index_col=0)

2)數據去重與控制處理

  • 對於重復值的定義,我們認為一個記錄的公司名稱和崗位名稱一致時,即可看作是重復值。因此利用drop_duplicates()函數剔除所有公司名稱和崗位名稱相同的記錄並保留第一個記錄。
  • 對於空值處理,只刪除所有字段信息都為nan的記錄。
#去除重復數據
df.drop_duplicates(subset=['公司名稱','崗位名稱'],inplace=True)
 
#空值刪除
df[df['公司名稱'].isnull()]
df.dropna(how='all',inplace=True)

3)崗位名稱標准化處理

基於前面對“崗位名稱”字段的統計情況,我們定義了目標崗位列表job_list,用來替換統一相近的崗位名稱,之后,我們將“數據專員”、“數據統計”統一歸為“數據分析”。

job_list = ['數據分析',"數據統計","數據專員",'數據挖掘','算法','大數據','開發工程師','運營',
            '軟件工程','前端開發','深度學習','ai','數據庫','倉庫管理','數據產品','客服',
            'java','.net','andrio','人工智能','c++','數據管理',"測試","運維","數據工程師"]
job_list = np.array(job_list)
def Rename(x,job_list=job_list):
    index = [i in x for i in job_list]
    if sum(index) > 0:
        return job_list[index][0]
    else:
        return x
job_info['崗位名稱'] = job_info['崗位名稱'].apply(Rename)
job_info["崗位名稱"] = job_info["崗位名稱"].apply(lambda x:x.replace("數據專員","數據分析"))
job_info["崗位名稱"] = job_info["崗位名稱"].apply(lambda x:x.replace("數據統計","數據分析"))

統一之后的“崗位名稱”如下圖所示:

import pandas as pd
import numpy as np
import jieba
 
#數據讀取
df = pd.read_excel(r'E:\python爬蟲\前程無憂招聘信息.xlsx',index_col=0)
 
#數據去重與空值處理
df.drop_duplicates(subset=['公司名稱','崗位名稱'],inplace=True)
df[df['招聘人數'].isnull()]
df.dropna(how='all',inplace=True)
 
#崗位名稱字段處理
df['崗位名稱'] = df['崗位名稱'].apply(lambda x:x.lower())
counts = df['崗位名稱'].value_counts() 
target_job = ['算法','開發','分析','工程師','數據','運營','運維','it','倉庫','統計']
index = [df['崗位名稱'].str.count(i) for i in target_job]
index = np.array(index).sum(axis=0) > 0
job_info = df[index]
job_list = ['數據分析',"數據統計","數據專員",'數據挖掘','算法','大數據','開發工程師',
            '運營','軟件工程','前端開發','深度學習','ai','數據庫','倉庫管理','數據產品',
            '客服','java','.net','andrio','人工智能','c++','數據管理',"測試","運維","數據工程師"]
job_list = np.array(job_list)
def Rename(x,job_list=job_list):
    index = [i in x for i in job_list]
    if sum(index) > 0:
        return job_list[index][0]
    else:
        return x
job_info['崗位名稱'] = job_info['崗位名稱'].apply(Rename)
job_info["崗位名稱"] = job_info["崗位名稱"].apply(lambda x:x.replace("數據專員","數據分析"))
job_info["崗位名稱"] = job_info["崗位名稱"].apply(lambda x:x.replace("數據統計","數據分析"))
 
#崗位薪資字段處理
index1 = job_info["崗位薪資"].str[-1].isin(["年","月"])
index2 = job_info["崗位薪資"].str[-3].isin(["萬","千"])
job_info = job_info[index1 & index2]
job_info['平均薪資'] = job_info['崗位薪資'].astype(str).apply(lambda x:np.array(x[:-3].split('-'),dtype=float))
job_info['平均薪資'] = job_info['平均薪資'].apply(lambda x:np.mean(x))
#統一工資單位
job_info['單位'] = job_info['崗位薪資'].apply(lambda x:x[-3:])
job_info['公司領域'].value_counts()
def con_unit(x):
    if x['單位'] == "萬/月":
        z = x['平均薪資']*10000
    elif x['單位'] == "千/月":
        z = x['平均薪資']*1000
    elif x['單位'] == "萬/年":
        z = x['平均薪資']/12*10000
    return int(z)
job_info['平均薪資'] = job_info.apply(con_unit,axis=1)
job_info['單位'] = '元/月'
 
#工作地點字段處理
job_info['工作地點'] = job_info['工作地點'].apply(lambda x:x.split('-')[0])
 
#公司領域字段處理
job_info['公司領域'] = job_info['公司領域'].apply(lambda x:x.split('/')[0])
 
#招聘人數字段處理
job_info['招聘人數'] = job_info['招聘人數'].apply(lambda x:x.replace("若干","1").strip()[1:-1])
 
#工作經驗與學歷要求字段處理
job_info['工作經驗'] = job_info['工作經驗'].apply(lambda x:x.replace("無需","1年以下").strip()[:-2])
job_info['學歷需求'] = job_info['學歷需求'].apply(lambda x:x.split()[0])
 
#公司規模字段處理
job_info['公司規模'].value_counts()
def func(x):
    if x == '少於50人':
        return "<50"
    elif x == '50-150人':
        return "50-150"
    elif x == '150-500人':
        return '150-500'
    elif x == '500-1000人':
        return '500-1000'
    elif x == '1000-5000人':
        return '1000-5000'
    elif x == '5000-10000人':
        return '5000-10000'
    elif x == '10000人以上':
        return ">10000"
    else:
        return np.nan
job_info['公司規模'] = job_info['公司規模'].apply(func)
 
#公司福利字段處理
job_info['公司福利'] = job_info['公司福利'].apply(lambda x:str(x).split())
 
#職位信息字段處理
job_info['職位信息'] = job_info['職位信息'].apply(lambda x:x.split('職能類別')[0])
with open(r"E:\C++\停用詞表.txt",'r',encoding = 'utf8') as f:
    stopword = f.read()
stopword = stopword.split()
job_info['職位信息'] = job_info['職位信息'].apply(lambda x:x.lower()).apply(lambda x:"".join(x)).apply(lambda x:x.strip()).apply(jieba.lcut).apply(lambda x:[i for i in x if i not in stopword])
cons = job_info['公司領域'].value_counts()
industries = pd.DataFrame(cons.index,columns=['行業領域'])
industry = pd.DataFrame(columns=['分詞明細','行業領域'])
for i in industries['行業領域']:
    words = []
    word = job_info['職位信息'][job_info['公司領域'] == i]
    word.dropna(inplace=True)
    [words.extend(str(z).strip('\'[]').split("\', \'")) for z in word]
    df1 = pd.DataFrame({'分詞明細':words,
                        '行業領域':i})
    industry = industry.append(df1,ignore_index=True)
industry = industry[industry['分詞明細'] != "\\n"]
industry = industry[industry['分詞明細'] != ""]
count = pd.DataFrame(industry['分詞明細'].value_counts())
lst = list(count[count['分詞明細'] >=300].index)
industry = industry[industry['分詞明細'].isin(lst)]
 
#數據存儲
industry.to_excel(r'E:\python爬蟲\數據預處理\詞雲.xlsx')       
job_info.to_excel(r'E:\python爬蟲\數據預處理\前程無憂(已清洗).xlsx')


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM