摘要:實(shí)際上,前程無(wú)憂(yōu)招聘網(wǎng)站上與數(shù)據(jù)有關(guān)的只有幾百頁(yè),而我們爬取了頁(yè)的所有數(shù)據(jù),因此在后面進(jìn)行數(shù)據(jù)處理時(shí)需要把無(wú)關(guān)的數(shù)據(jù)剔除掉。
目錄
1、相關(guān)庫(kù)的導(dǎo)入與說(shuō)明
1)相關(guān)庫(kù)導(dǎo)入及數(shù)據(jù)讀取
2)構(gòu)建關(guān)鍵詞,篩選名稱(chēng)
3)崗位名稱(chēng)標(biāo)準(zhǔn)化處理
4、各類(lèi)型企業(yè)崗位需求樹(shù)狀分布圖
5、經(jīng)驗(yàn)學(xué)歷與薪資需求突出顯示表?
????????隨著科技的不斷進(jìn)步與發(fā)展,數(shù)據(jù)呈現(xiàn)爆發(fā)式的增長(zhǎng),各行各業(yè)對(duì)于數(shù)據(jù)的依賴(lài)越來(lái)越強(qiáng),與數(shù)據(jù)打交道在所難免,而社會(huì)對(duì)于“數(shù)據(jù)”方面的人才需求也在不斷增大。因此了解當(dāng)下企業(yè)究竟需要招聘什么樣的人才?需要什么樣的技能?不管是對(duì)于在校生,還是對(duì)于求職者來(lái)說(shuō),都顯得十分必要。
? ? ? ? 對(duì)于一名小白來(lái)說(shuō),想要入門(mén)數(shù)據(jù)分析,首先要了解目前社會(huì)對(duì)于數(shù)據(jù)相關(guān)崗位的需求情況,基于這一問(wèn)題,本文針對(duì)前程無(wú)憂(yōu)招聘網(wǎng)站,利用python爬取了其全國(guó)范圍內(nèi)大數(shù)據(jù)、數(shù)據(jù)分析、數(shù)據(jù)挖掘、機(jī)器學(xué)習(xí)、人工智能等與數(shù)據(jù)相關(guān)的崗位招聘信息。并通過(guò)Tableau可視化工具分析比較了不同行業(yè)的崗位薪資、用人需求等情況;以及不同行業(yè)、崗位的知識(shí)、技能要求等。
? ? ? ? ?可視化分析效果圖示例:
????????一級(jí)頁(yè)面如下:
????????二級(jí)頁(yè)面如下:
import jsonimport requestsimport pandas as pdfrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom lxml import etreefrom selenium.webdriver import ChromeOptions
? ? ? ? 由于前程無(wú)憂(yōu)招聘網(wǎng)站的反爬機(jī)制較強(qiáng),采用動(dòng)態(tài)渲染+限制ip訪問(wèn)頻率等多層反爬,因此在獲取二級(jí)頁(yè)面鏈接時(shí)需借助json進(jìn)行解析,本文對(duì)于二級(jí)頁(yè)面崗位信息的獲取采用selenium模擬瀏覽器爬取,同時(shí)通過(guò)代理IP的方式,每隔一段時(shí)間換一次請(qǐng)求IP以免觸發(fā)網(wǎng)站反爬機(jī)制。?
# 第一頁(yè)URL的特征"https://search.51job.com/list/000000,000000,0000,00,9,99,數(shù)據(jù),2,1.html?"# 第二頁(yè)URL的特征"https://search.51job.com/list/000000,000000,0000,00,9,99,數(shù)據(jù),2,2.html?"# 第三頁(yè)URL的特征"https://search.51job.com/list/000000,000000,0000,00,9,99,數(shù)據(jù),2,3.html?"
? ? ? ? 通過(guò)觀察不同頁(yè)面的URL可以發(fā)現(xiàn),不同頁(yè)面的URL鏈接只有“.html”前面的數(shù)字不同,該數(shù)字正好代表該頁(yè)的頁(yè)碼?,因此只需要構(gòu)造字符串拼接,然后通過(guò)for循環(huán)語(yǔ)句即可構(gòu)造自動(dòng)翻頁(yè)。
url1 = []for i in range(2000): url_pre = "https://search.51job.com/list/000000,000000,0000,00,9,99,數(shù)據(jù),2,%s" % (1+i) #設(shè)置自動(dòng)翻頁(yè) url_end = ".html?" url_all = url_pre + url_end url1.append(url_all)print("一級(jí)URL庫(kù)創(chuàng)建完畢")
url2 = []j = 0for url in url1: j += 1 re1 = requests.get(url , headers = headers,proxies= {"http":"tps131.kdlapi.com:15818"},timeout=(5,10)) #通過(guò)proxies設(shè)置代理ip html1 = etree.HTML(re1.text) divs = html1.xpath("http://script[@type = "text/javascript"]/text()")[0].replace("window.__SEARCH_RESULT__ = ","") js = json.loads(divs) for i in range(len(js["engine_jds"])): if js["engine_jds"][i]["job_href"][0:22] == "https://jobs.51job.com": url2.append(js["engine_jds"][i]["job_href"]) else: print("url異常,棄用") #剔除異常url print("已爬取"+str(j)+"頁(yè)")print("成功爬取"+str(len(url2))+"條二級(jí)URL")
注意:爬取二級(jí)URL鏈接時(shí)發(fā)現(xiàn)并非爬取的所有鏈接都是規(guī)范的,會(huì)存在少部分異常URL,這會(huì)對(duì)后續(xù)崗位信息的爬取造成干擾,因此需要利用if條件語(yǔ)句對(duì)其進(jìn)行剔除。
option = ChromeOptions()option.add_experimental_option("excludeSwitches", ["enable-automation"])option.add_argument("--proxy-server=http://tps131.kdlapi.com:15818") #設(shè)置代理ipdriver = webdriver.Chrome(options=option)for url in url2: co = 1 while co == 1: try: driver.get(url) wait = WebDriverWait(driver,10,0.5) wait.until(EC.presence_of_element_located((By.ID,"topIndex"))) except: driver.close() driver = webdriver.Chrome(options=option) co = 1 else: co = 0 try: 福利待遇 = driver.find_elements_by_xpath("http://div[@class = "t1"]")[0].text 崗位名稱(chēng) = driver.find_element_by_xpath("http://div[@class = "cn"]/h1").text 薪資水平 = driver.find_element_by_xpath("http://div[@class = "cn"]/strong").text 職位信息 = driver.find_elements_by_xpath("http://div[@class = "bmsg job_msg inbox"]")[0].text 公司類(lèi)型 = driver.find_elements_by_xpath("http://div[@class = "com_tag"]/p")[0].text 公司規(guī)模 = driver.find_elements_by_xpath("http://div[@class = "com_tag"]/p")[1].text 公司領(lǐng)域 = driver.find_elements_by_xpath("http://div[@class = "com_tag"]/p")[2].text 公司名稱(chēng) = driver.find_element_by_xpath("http://div[@class = "com_msg"]/a/p").text 工作地點(diǎn) = driver.find_elements_by_xpath("http://div[@class = "cn"]//p[@class = "msg ltype"]")[0].text.split("|")[0] 工作經(jīng)驗(yàn) = driver.find_elements_by_xpath("http://div[@class = "cn"]//p[@class = "msg ltype"]")[0].text.split("|")[1] 學(xué)歷要求 = driver.find_elements_by_xpath("http://div[@class = "cn"]//p[@class = "msg ltype"]")[0].text.split("|")[2] 招聘人數(shù) = driver.find_elements_by_xpath("http://div[@class = "cn"]//p[@class = "msg ltype"]")[0].text.split("|")[3] 發(fā)布時(shí)間 = driver.find_elements_by_xpath("http://div[@class = "cn"]//p[@class = "msg ltype"]")[0].text.split("|")[4] except: 福利待遇 = "nan" 崗位名稱(chēng) = "nan" 薪資水平 = "nan" 職位信息 = "nan" 公司類(lèi)型 = "nan" 公司規(guī)模 = "nan" 公司領(lǐng)域 = "nan" 公司名稱(chēng) = "nan" 工作地點(diǎn) = "nan" 工作經(jīng)驗(yàn) = "nan" 學(xué)歷要求 = "nan" 招聘人數(shù) = "nan" 發(fā)布時(shí)間 = "nan" print("信息提取異常,棄用") finally: info = { "崗位名稱(chēng)" : 崗位名稱(chēng), "公司名稱(chēng)" : 公司名稱(chēng), "薪資水平" : 薪資水平, "工作經(jīng)驗(yàn)" : 工作經(jīng)驗(yàn), "學(xué)歷要求" : 學(xué)歷要求, "工作地點(diǎn)" : 工作地點(diǎn), "招聘人數(shù)" : 招聘人數(shù), "發(fā)布時(shí)間" : 發(fā)布時(shí)間, "公司類(lèi)型" : 公司類(lèi)型, "公司規(guī)模" : 公司規(guī)模, "公司領(lǐng)域" : 公司領(lǐng)域, "福利待遇" : 福利待遇, "職位信息" : 職位信息 } jobs_info.append(info)df = pd.DataFrame(jobs_info)df.to_excel(r"E:/python爬蟲(chóng)/前程無(wú)憂(yōu)招聘信息.xlsx")
? ? ? ? 在爬取并剔除異常數(shù)據(jù)之后,最終得到了90000多條完整的數(shù)據(jù)做分析,但經(jīng)過(guò)觀察發(fā)現(xiàn),所爬取的數(shù)據(jù)并非全都與“數(shù)據(jù)”崗位相關(guān)聯(lián)。實(shí)際上,前程無(wú)憂(yōu)招聘網(wǎng)站上與“數(shù)據(jù)”有關(guān)的只有幾百頁(yè),而我們爬取了2000頁(yè)的所有數(shù)據(jù),因此在后面進(jìn)行數(shù)據(jù)處理時(shí)需要把無(wú)關(guān)的數(shù)據(jù)剔除掉。在爬取前根據(jù)對(duì)代碼的測(cè)試發(fā)現(xiàn),有些崗位字段在進(jìn)行爬取時(shí)會(huì)出現(xiàn)錯(cuò)位,從而導(dǎo)致數(shù)據(jù)存儲(chǔ)失敗,為了不影響后面代碼的執(zhí)行,這里設(shè)置了“try-except”進(jìn)行異常處理,同時(shí)使用while循環(huán)語(yǔ)句在服務(wù)器出現(xiàn)請(qǐng)求失敗時(shí)關(guān)閉模擬瀏覽器并進(jìn)行重新請(qǐng)求。
????????在獲取了所需數(shù)據(jù)之后,可以看出數(shù)據(jù)較亂,并不利于我們進(jìn)行分析,因此在分析前需要對(duì)數(shù)據(jù)進(jìn)行預(yù)處理,得到規(guī)范格式的數(shù)據(jù)才可以用來(lái)最終做可視化數(shù)據(jù)展示。
? ? ? ? 獲取的數(shù)據(jù)截圖如下:
#導(dǎo)入相關(guān)庫(kù)import pandas as pdimport numpy as npimport jieba#讀取數(shù)據(jù)df = pd.read_excel(r"E:/python爬蟲(chóng)/前程無(wú)憂(yōu)招聘信息.xlsx",index_col=0)
#去除重復(fù)數(shù)據(jù)df.drop_duplicates(subset=["公司名稱(chēng)","崗位名稱(chēng)"],inplace=True)#空值刪除df[df["公司名稱(chēng)"].isnull()]df.dropna(how="all",inplace=True)
? ? ? ? 首先我們對(duì)“崗位名稱(chēng)”的格式進(jìn)行調(diào)整,將其中所有大寫(xiě)英文字母統(tǒng)一轉(zhuǎn)換為小寫(xiě),例如將"Java"轉(zhuǎn)換為"java",然后對(duì)所有崗位做一個(gè)頻次統(tǒng)計(jì),統(tǒng)計(jì)結(jié)果發(fā)現(xiàn)“崗位名稱(chēng)”字段很雜亂,且存在很多與“數(shù)據(jù)”無(wú)關(guān)的崗位,因此要對(duì)數(shù)據(jù)做一個(gè)篩選。
df["崗位名稱(chēng)"] = df["崗位名稱(chēng)"].apply(lambda x:x.lower())counts = df["崗位名稱(chēng)"].value_counts()
? ? ? ? 首先我們列出與“數(shù)據(jù)”崗位“有關(guān)的一系列關(guān)鍵詞,然后通過(guò)count()與for語(yǔ)句對(duì)所有記錄進(jìn)行統(tǒng)計(jì)判斷,如果包含任一關(guān)鍵詞則保留該記錄,如果不包含則刪除該字段。
#構(gòu)建目標(biāo)關(guān)鍵詞target_job = ["算法","開(kāi)發(fā)","分析","工程師","數(shù)據(jù)","運(yùn)營(yíng)","運(yùn)維","it","倉(cāng)庫(kù)","統(tǒng)計(jì)"]#篩選目標(biāo)數(shù)據(jù)index = [df["崗位名稱(chēng)"].str.count(i) for i in target_job]index = np.array(index).sum(axis=0) > 0job_info = df[index]
? ? ? ? 基于前面對(duì)“崗位名稱(chēng)”字段的統(tǒng)計(jì)情況,我們定義了目標(biāo)崗位列表job_list,用來(lái)替換統(tǒng)一相近的崗位名稱(chēng),之后,我們將“數(shù)據(jù)專(zhuān)員”、“數(shù)據(jù)統(tǒng)計(jì)”統(tǒng)一歸為“數(shù)據(jù)分析”。
job_list = ["數(shù)據(jù)分析","數(shù)據(jù)統(tǒng)計(jì)","數(shù)據(jù)專(zhuān)員","數(shù)據(jù)挖掘","算法","大數(shù)據(jù)","開(kāi)發(fā)工程師","運(yùn)營(yíng)", "軟件工程","前端開(kāi)發(fā)","深度學(xué)習(xí)","ai","數(shù)據(jù)庫(kù)","倉(cāng)庫(kù)管理","數(shù)據(jù)產(chǎn)品","客服", "java",".net","andrio","人工智能","c++","數(shù)據(jù)管理","測(cè)試","運(yùn)維","數(shù)據(jù)工程師"]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 xjob_info["崗位名稱(chēng)"] = job_info["崗位名稱(chēng)"].apply(Rename)job_info["崗位名稱(chēng)"] = job_info["崗位名稱(chēng)"].apply(lambda x:x.replace("數(shù)據(jù)專(zhuān)員","數(shù)據(jù)分析"))job_info["崗位名稱(chēng)"] = job_info["崗位名稱(chēng)"].apply(lambda x:x.replace("數(shù)據(jù)統(tǒng)計(jì)","數(shù)據(jù)分析"))
? ? ? ? 統(tǒng)一之后的“崗位名稱(chēng)”如下圖所示:
?
? ? ? ? 對(duì)于“崗位薪資”字段的處理,重點(diǎn)在于對(duì)其單位格式轉(zhuǎn)換,在簡(jiǎn)單觀察該字段后發(fā)現(xiàn),其存在“萬(wàn)/年”、“萬(wàn)/月”、“千/月”等不同單位,因此需要對(duì)其做一個(gè)統(tǒng)一換算,將數(shù)據(jù)格式統(tǒng)一轉(zhuǎn)換為“元/月”,并根據(jù)最高工資與最低工資求出平均值。
job_info["崗位薪資"].value_counts()#剔除異常數(shù)據(jù)index1 = job_info["崗位薪資"].str[-1].isin(["年","月"])index2 = job_info["崗位薪資"].str[-3].isin(["萬(wàn)","千"])job_info = job_info[index1 & index2]#計(jì)算平均工資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))#統(tǒng)一工資單位job_info["單位"] = job_info["崗位薪資"].apply(lambda x:x[-3:])def con_unit(x): if x["單位"] == "萬(wàn)/月": z = x["平均薪資"]*10000 elif x["單位"] == "千/月": z = x["平均薪資"]*1000 elif x["單位"] == "萬(wàn)/年": z = x["平均薪資"]/12*10000 return int(z)job_info["平均薪資"] = job_info.apply(con_unit,axis=1)job_info["單位"] = "元/月"
說(shuō)明:首先我們對(duì)該字段進(jìn)行統(tǒng)計(jì)預(yù)覽,之后做一個(gè)數(shù)據(jù)篩選剔除異常單位與空值記錄,再計(jì)算出每個(gè)字段的平均工資,接著定義一個(gè)函數(shù),將格式換算為“元/月”,得到最終的“平均薪資”字段。
? ? ? ? 對(duì)于“公司規(guī)模”字段的處理較簡(jiǎn)單,只需要定義一個(gè)if條件語(yǔ)句將其格式做一個(gè)轉(zhuǎn)換即可。
job_info["公司規(guī)模"].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.nanjob_info["公司規(guī)模"] = job_info["公司規(guī)模"].apply(func)
job_info["職位信息"] = job_info["職位信息"].apply(lambda x:x.split("職能類(lèi)別")[0])with open(r"E:/python爬蟲(chóng)/數(shù)據(jù)處理/停用詞表.txt","r",encoding = "utf8") as f: stopword = f.read()stopword = stopword.split()#對(duì)“職業(yè)信息”字段進(jìn)行簡(jiǎn)單處理,去除無(wú)意義的文字,構(gòu)造jieba分詞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])#按照行業(yè)進(jìn)行分類(lèi),求出每一個(gè)行業(yè)下各關(guān)鍵詞的詞頻統(tǒng)計(jì),以便于后期做詞云圖cons = job_info["公司領(lǐng)域"].value_counts()industries = pd.DataFrame(cons.index,columns=["行業(yè)領(lǐng)域"])industry = pd.DataFrame(columns=["分詞明細(xì)","行業(yè)領(lǐng)域"])for i in industries["行業(yè)領(lǐng)域"]: words = [] word = job_info["職位信息"][job_info["公司領(lǐng)域"] == i] word.dropna(inplace=True) [words.extend(str(z).strip("/"[]").split("/", /"")) for z in word] df1 = pd.DataFrame({"分詞明細(xì)":words, "行業(yè)領(lǐng)域":i}) industry = industry.append(df1,ignore_index=True)industry = industry[industry["分詞明細(xì)"] != "http://n"]industry = industry[industry["分詞明細(xì)"] != ""]#剔除詞頻小于300的關(guān)鍵詞count = pd.DataFrame(industry["分詞明細(xì)"].value_counts())lst = list(count[count["分詞明細(xì)"] >=300].index)industry = industry[industry["分詞明細(xì)"].isin(lst)]#數(shù)據(jù)存儲(chǔ)industry.to_excel(r"E:/python爬蟲(chóng)/數(shù)據(jù)處理/詞云.xlsx")
#工作地點(diǎn)字段處理job_info["工作地點(diǎn)"] = job_info["工作地點(diǎn)"].apply(lambda x:x.split("-")[0])#公司領(lǐng)域字段處理job_info["公司領(lǐng)域"] = job_info["公司領(lǐng)域"].apply(lambda x:x.split("/")[0])a = job_info["公司領(lǐng)域"].value_counts()#招聘人數(shù)字段處理job_info["招聘人數(shù)"] = job_info["招聘人數(shù)"].apply(lambda x:x.replace("若干","1").strip()[1:-1])#工作經(jīng)驗(yàn)與學(xué)歷要求字段處理job_info["工作經(jīng)驗(yàn)"] = job_info["工作經(jīng)驗(yàn)"].apply(lambda x:x.replace("無(wú)需","1年以下").strip()[:-2])job_info["學(xué)歷需求"] = job_info["學(xué)歷需求"].apply(lambda x:x.split()[0])#公司福利字段處理job_info["公司福利"] = job_info["公司福利"].apply(lambda x:str(x).split())
? ? ? ? 我們針對(duì)清洗干凈后的數(shù)據(jù)另存為一個(gè)文檔,對(duì)源數(shù)據(jù)不做修改。
job_info.to_excel(r"E:/python爬蟲(chóng)/前程無(wú)憂(yōu)(已清洗).xlsx")
結(jié)論分析:從氣泡圖中可以看出,“數(shù)據(jù)”相關(guān)崗位數(shù)量較高的城市有:上海、深圳、廣州、北京、杭州、武漢等。
結(jié)論分析:通過(guò)條形圖可以看出,“數(shù)據(jù)”相關(guān)崗位用人需求達(dá)1000人以上的城市有15個(gè),需求由高到低依次為:上海、深圳、廣州、北京、武漢、杭州、成都、南京、蘇州、無(wú)錫、西安、長(zhǎng)沙、鄭州、重慶。其中上海用人需求高達(dá)10000人。
結(jié)論分析:從不同行業(yè)的用人需求與薪資對(duì)比可知,用人需求排名前4的行業(yè)分別:計(jì)算機(jī)軟件、互聯(lián)網(wǎng)、電子技術(shù)、計(jì)算機(jī)服務(wù);平均薪資排名前4的行業(yè)分別為:互聯(lián)網(wǎng)、計(jì)算機(jī)軟件、通信、專(zhuān)業(yè)服務(wù)。可以發(fā)現(xiàn),“數(shù)據(jù)”相關(guān)崗位在計(jì)算機(jī)領(lǐng)域需求大,薪資高,前景好。
結(jié)論分析:在發(fā)布的眾多崗位需求信息中,以民營(yíng)公司為主,其崗位數(shù)量、用人需求極高,但薪資待遇一般,而上市公司的崗位數(shù)量一般,但薪資待遇好。
????????注:顏色深淺表示薪資高低,數(shù)字表示招聘人數(shù)
結(jié)論分析:根據(jù)突出顯示表可以發(fā)現(xiàn),在學(xué)歷要求方面,大專(zhuān)與本科生需求量較大;經(jīng)驗(yàn)要求方面,3年以下相關(guān)經(jīng)驗(yàn)的崗位占大多數(shù),而薪資方面,學(xué)歷越高,經(jīng)驗(yàn)越豐富則薪資越高。因此可以判斷數(shù)據(jù)分析行業(yè)還是一個(gè)較新興的行業(yè),目前行業(yè)的基礎(chǔ)崗位較多,且具有豐富經(jīng)驗(yàn)的專(zhuān)家較少。
?結(jié)論分析:上圖通過(guò)列舉了傳統(tǒng)制造業(yè)、計(jì)算機(jī)相關(guān)行業(yè)以及服務(wù)業(yè)三個(gè)行業(yè)進(jìn)行對(duì)比分析,三個(gè)行業(yè)對(duì)于“數(shù)據(jù)”相關(guān)崗位工作要求的共同點(diǎn)都是注重相關(guān)的行業(yè)經(jīng)驗(yàn)及數(shù)據(jù)處理等能力,而計(jì)算機(jī)相關(guān)行業(yè)對(duì)于技術(shù)如開(kāi)發(fā)、數(shù)據(jù)庫(kù)、系統(tǒng)維護(hù)等編程能力要求較高,傳統(tǒng)制造業(yè)和服務(wù)行業(yè)則更側(cè)重于業(yè)務(wù)分析、管理、團(tuán)隊(duì)合作綜合型能力等。
?
import jsonimport requestsimport pandas as pdfrom lxml import etreefrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver import ChromeOptionsfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECurl1 = []url2 = []jobs_info = []for i in range(2000): url_pre = "https://search.51job.com/list/000000,000000,0000,00,9,99,數(shù)據(jù),2,%s" % (1+i) #頁(yè)面跳轉(zhuǎn) url_end = ".html?" url_all = url_pre + url_end url1.append(url_all)print("一級(jí)URL庫(kù)創(chuàng)建完畢")#從json中提取數(shù)據(jù)并加載headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36", "Connection": "close", "Host": "search.51job.com"}j = 0for url in url1: j += 1 re1 = requests.get(url , headers = headers,proxies= {"http":"tps131.kdlapi.com:15818"},timeout=(5,10)) html1 = etree.HTML(re1.text) divs = html1.xpath("http://script[@type = "text/javascript"]/text()")[0].replace("window.__SEARCH_RESULT__ = ","") js = json.loads(divs) for i in range(len(js["engine_jds"])): if js["engine_jds"][i]["job_href"][0:22] == "https://jobs.51job.com": url2.append(js["engine_jds"][i]["job_href"]) else: print("url異常,棄用") print("已解析"+str(j)+"頁(yè)")print("成功提取"+str(len(url2))+"條二級(jí)URL")#爬取崗位數(shù)據(jù)option = ChromeOptions()option.add_experimental_option("excludeSwitches", ["enable-automation"])option.add_argument("--proxy-server=http://tps131.kdlapi.com:15818") driver = webdriver.Chrome(options=option)for url in url2: co = 1 while co == 1: try: #設(shè)置IP代理 driver.get(url) wait = WebDriverWait(driver,10,0.5) wait.until(EC.presence_of_element_located((By.ID,"topIndex"))) except: driver.close() driver = webdriver.Chrome(options=option) co = 1 else: co = 0 try: 福利待遇 = driver.find_elements_by_xpath("http://div[@class = "t1"]")[0].text 崗位名稱(chēng) = driver.find_element_by_xpath("http://div[@class = "cn"]/h1").text 薪資水平 = driver.find_element_by_xpath("http://div[@class = "cn"]/strong").text 職位信息 = driver.find_elements_by_xpath("http://div[@class = "bmsg job_msg inbox"]")[0].text 公司類(lèi)型 = driver.find_elements_by_xpath("http://div[@class = "com_tag"]/p")[0].text 公司規(guī)模 = driver.find_elements_by_xpath("http://div[@class = "com_tag"]/p")[1].text 公司領(lǐng)域 = driver.find_elements_by_xpath("http://div[@class = "com_tag"]/p")[2].text 公司名稱(chēng) = driver.find_element_by_xpath("http://div[@class = "com_msg"]/a/p").text 工作地點(diǎn) = driver.find_elements_by_xpath("http://div[@class = "cn"]//p[@class = "msg ltype"]")[0].text.split("|")[0] 工作經(jīng)驗(yàn) = driver.find_elements_by_xpath("http://div[@class = "cn"]//p[@class = "msg ltype"]")[0].text.split("|")[1] 學(xué)歷要求 = driver.find_elements_by_xpath("http://div[@class = "cn"]//p[@class = "msg ltype"]")[0].text.split("|")[2] 招聘人數(shù) = driver.find_elements_by_xpath("http://div[@class = "cn"]//p[@class = "msg ltype"]")[0].text.split("|")[3] 發(fā)布時(shí)間 = driver.find_elements_by_xpath("http://div[@class = "cn"]//p[@class = "msg ltype"]")[0].text.split("|")[4] except: 福利待遇 = "nan" 崗位名稱(chēng) = "nan" 薪資水平 = "nan" 職位信息 = "nan" 公司類(lèi)型 = "nan" 公司規(guī)模 = "nan" 公司領(lǐng)域 = "nan" 公司名稱(chēng) = "nan" 工作地點(diǎn) = "nan" 工作經(jīng)驗(yàn) = "nan" 學(xué)歷要求 = "nan" 招聘人數(shù) = "nan" 發(fā)布時(shí)間 = "nan" print("信息提取異常,棄用") finally: info = { "崗位名稱(chēng)" : 崗位名稱(chēng), "公司名稱(chēng)" : 公司名稱(chēng), "薪資水平" : 薪資水平, "工作經(jīng)驗(yàn)" : 工作經(jīng)驗(yàn), "學(xué)歷要求" : 學(xué)歷要求, "工作地點(diǎn)" : 工作地點(diǎn), "招聘人數(shù)" : 招聘人數(shù), "發(fā)布時(shí)間" : 發(fā)布時(shí)間, "公司類(lèi)型" : 公司類(lèi)型, "公司規(guī)模" : 公司規(guī)模, "公司領(lǐng)域" : 公司領(lǐng)域, "福利待遇" : 福利待遇, "職位信息" : 職位信息 } jobs_info.append(info)df = pd.DataFrame(jobs_info)df.to_excel(r"E:/python爬蟲(chóng)/前程無(wú)憂(yōu)招聘信息.xlsx")
import pandas as pdimport numpy as npimport jieba#數(shù)據(jù)讀取df = pd.read_excel(r"E:/python爬蟲(chóng)/前程無(wú)憂(yōu)招聘信息.xlsx",index_col=0)#數(shù)據(jù)去重與空值處理df.drop_duplicates(subset=["公司名稱(chēng)","崗位名稱(chēng)"],inplace=True)df[df["招聘人數(shù)"].isnull()]df.dropna(how="all",inplace=True)#崗位名稱(chēng)字段處理df["崗位名稱(chēng)"] = df["崗位名稱(chēng)"].apply(lambda x:x.lower())counts = df["崗位名稱(chēng)"].value_counts() target_job = ["算法","開(kāi)發(fā)","分析","工程師","數(shù)據(jù)","運(yùn)營(yíng)","運(yùn)維","it","倉(cāng)庫(kù)","統(tǒng)計(jì)"]index = [df["崗位名稱(chēng)"].str.count(i) for i in target_job]index = np.array(index).sum(axis=0) > 0job_info = df[index]job_list = ["數(shù)據(jù)分析","數(shù)據(jù)統(tǒng)計(jì)","數(shù)據(jù)專(zhuān)員","數(shù)據(jù)挖掘","算法","大數(shù)據(jù)","開(kāi)發(fā)工程師", "運(yùn)營(yíng)","軟件工程","前端開(kāi)發(fā)","深度學(xué)習(xí)","ai","數(shù)據(jù)庫(kù)","倉(cāng)庫(kù)管理","數(shù)據(jù)產(chǎn)品", "客服","java",".net","andrio","人工智能","c++","數(shù)據(jù)管理","測(cè)試","運(yùn)維","數(shù)據(jù)工程師"]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 xjob_info["崗位名稱(chēng)"] = job_info["崗位名稱(chēng)"].apply(Rename)job_info["崗位名稱(chēng)"] = job_info["崗位名稱(chēng)"].apply(lambda x:x.replace("數(shù)據(jù)專(zhuān)員","數(shù)據(jù)分析"))job_info["崗位名稱(chēng)"] = job_info["崗位名稱(chēng)"].apply(lambda x:x.replace("數(shù)據(jù)統(tǒng)計(jì)","數(shù)據(jù)分析"))#崗位薪資字段處理index1 = job_info["崗位薪資"].str[-1].isin(["年","月"])index2 = job_info["崗位薪資"].str[-3].isin(["萬(wàn)","千"])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))#統(tǒng)一工資單位job_info["單位"] = job_info["崗位薪資"].apply(lambda x:x[-3:])job_info["公司領(lǐng)域"].value_counts()def con_unit(x): if x["單位"] == "萬(wàn)/月": z = x["平均薪資"]*10000 elif x["單位"] == "千/月": z = x["平均薪資"]*1000 elif x["單位"] == "萬(wàn)/年": z = x["平均薪資"]/12*10000 return int(z)job_info["平均薪資"] = job_info.apply(con_unit,axis=1)job_info["單位"] = "元/月"#工作地點(diǎn)字段處理job_info["工作地點(diǎn)"] = job_info["工作地點(diǎn)"].apply(lambda x:x.split("-")[0])#公司領(lǐng)域字段處理job_info["公司領(lǐng)域"] = job_info["公司領(lǐng)域"].apply(lambda x:x.split("/")[0])#招聘人數(shù)字段處理job_info["招聘人數(shù)"] = job_info["招聘人數(shù)"].apply(lambda x:x.replace("若干","1").strip()[1:-1])#工作經(jīng)驗(yàn)與學(xué)歷要求字段處理job_info["工作經(jīng)驗(yàn)"] = job_info["工作經(jīng)驗(yàn)"].apply(lambda x:x.replace("無(wú)需","1年以下").strip()[:-2])job_info["學(xué)歷需求"] = job_info["學(xué)歷需求"].apply(lambda x:x.split()[0])#公司規(guī)模字段處理job_info["公司規(guī)模"].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.nanjob_info["公司規(guī)模"] = job_info["公司規(guī)模"].apply(func)#公司福利字段處理job_info["公司福利"] = job_info["公司福利"].apply(lambda x:str(x).split())#職位信息字段處理job_info["職位信息"] = job_info["職位信息"].apply(lambda x:x.split("職能類(lèi)別")[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["公司領(lǐng)域"].value_counts()industries = pd.DataFrame(cons.index,columns=["行業(yè)領(lǐng)域"])industry = pd.DataFrame(columns=["分詞明細(xì)","行業(yè)領(lǐng)域"])for i in industries["行業(yè)領(lǐng)域"]: words = [] word = job_info["職位信息"][job_info["公司領(lǐng)域"] == i] word.dropna(inplace=True) [words.extend(str(z).strip("/"[]").split("/", /"")) for z in word] df1 = pd.DataFrame({"分詞明細(xì)":words, "行業(yè)領(lǐng)域":i}) industry = industry.append(df1,ignore_index=True)industry = industry[industry["分詞明細(xì)"] != "http://n"]industry = industry[industry["分詞明細(xì)"] != ""]count = pd.DataFrame(industry["分詞明細(xì)"].value_counts())lst = list(count[count["分詞明細(xì)"] >=300].index)industry = industry[industry["分詞明細(xì)"].isin(lst)]#數(shù)據(jù)存儲(chǔ)industry.to_excel(r"E:/python爬蟲(chóng)/數(shù)據(jù)預(yù)處理/詞云.xlsx") job_info.to_excel(r"E:/python爬蟲(chóng)/數(shù)據(jù)預(yù)處理/前程無(wú)憂(yōu)(已清洗).xlsx")
?
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/121420.html
摘要:直接抄其中一份的結(jié)論吧各地區(qū)招聘公司數(shù)量和平均待遇。可以看出不論是招聘公司的數(shù)據(jù)還是平均待遇水平主要都是北上廣深杭州占優(yōu)勢(shì)。但事實(shí)證明,總是要有一些代價(jià)的。要學(xué)會(huì)看報(bào)錯(cuò)信息。函數(shù)定義結(jié)束后需要按兩次回車(chē)重新回到提示符下。 又是寫(xiě)在前面的亂七八糟 持續(xù)學(xué)習(xí)的第三天了,持續(xù)學(xué)習(xí)是一個(gè)不容易培養(yǎng)的好習(xí)慣,但是堅(jiān)持就是勝利嘛~昨天因?yàn)橐稽c(diǎn)點(diǎn)事情,所以沒(méi)能學(xué)習(xí)很長(zhǎng)時(shí)間,今天要補(bǔ)回來(lái)。周末要搬家,...
摘要:成功爬取了拉鉤網(wǎng)上多個(gè)招聘崗位的具體信息后,數(shù)據(jù)可視化并得出分析結(jié)果如下從整體看,北上廣深杭這五個(gè)城市前端工程師招聘崗位,北京是遙遙領(lǐng)先,是深圳的兩倍,是廣州的三倍,其次到上海,深圳,杭州,廣州居末。 前前言 本文首發(fā)于 github blog 不想看爬蟲(chóng)過(guò)程只想看職位錢(qián)途數(shù)據(jù)分析請(qǐng)看這里:前端招聘崗位分析C++招聘崗位分析JAVA招聘崗位分析PHP招聘崗位分析Python招聘崗位分析...
摘要:另外數(shù)學(xué)成為了一個(gè)關(guān)鍵詞,編程語(yǔ)言主要是等,運(yùn)營(yíng)也出現(xiàn)在詞云中說(shuō)明數(shù)據(jù)分析師也需要有運(yùn)營(yíng)能力。 功能點(diǎn) 爬取數(shù)據(jù) 所有公司數(shù)據(jù),名稱(chēng)簡(jiǎn)寫(xiě),城市,行業(yè),職位數(shù)量,人數(shù)范圍,標(biāo)簽,介紹,融資階段,平均工資 github2016年度最受歡迎編程語(yǔ)言相應(yīng)年數(shù)薪水,城市,學(xué)歷要求,公司融資階段,公司行業(yè) 大數(shù)據(jù)行業(yè)五大崗位相應(yīng)年數(shù)薪水,城市,學(xué)歷要求,公司融資階段,公司行業(yè),崗位要求 編程語(yǔ)...
摘要:填寫(xiě)自己對(duì)應(yīng)的網(wǎng)頁(yè)更改相應(yīng)數(shù)據(jù)的編碼格式遇到請(qǐng)求掛起當(dāng)前任務(wù),等操作完成執(zhí)行之后的代碼,當(dāng)協(xié)程掛起時(shí),事件循環(huán)可以去執(zhí)行其他任務(wù)。 前言 2012,一個(gè)卡牌,一個(gè)雷...
摘要:編程基礎(chǔ)要學(xué)習(xí)如何用進(jìn)行數(shù)據(jù)分析,數(shù)據(jù)分析師建議第一步是要了解一些的編程基礎(chǔ),知道的數(shù)據(jù)結(jié)構(gòu),什么是向量列表數(shù)組字典等等了解的各種函數(shù)及模塊。數(shù)據(jù)分析師認(rèn)為數(shù)據(jù)分析有的工作都在處理數(shù)據(jù)。 showImg(https://segmentfault.com/img/bVbnbZo?w=1024&h=653); 本文為CDA數(shù)據(jù)分析研究院原創(chuàng)作品,轉(zhuǎn)載需授權(quán) 1.為什么選擇Python進(jìn)行數(shù)...
閱讀 1324·2021-11-24 09:38
閱讀 3262·2021-11-22 12:03
閱讀 4188·2021-11-11 10:59
閱讀 2327·2021-09-28 09:36
閱讀 1037·2021-09-09 09:32
閱讀 3430·2021-08-05 10:00
閱讀 2537·2021-07-23 15:30
閱讀 2980·2019-08-30 13:12