爬取拉勾網(wǎng)關(guān)于python職位相關(guān)的數(shù)據(jù)信息,并將爬取的數(shù)據(jù)已csv各式存入文件,然后對csv文件相關(guān)字段的數(shù)據(jù)進(jìn)行清洗,并對數(shù)據(jù)可視化展示,包括柱狀圖展示、直方圖展示、詞云展示等并根據(jù)可視化的數(shù)據(jù)做進(jìn)一步的分析,其余分析和展示讀者可自行發(fā)揮和擴(kuò)展包括各種分析和不同的存儲方式等。。。。。
在以上安裝或使用過程中可能讀者會遇到安裝或?qū)胧〉葐栴}自行百度,選擇依賴包的合適版本
通過Chrome搜索'python工程師',然后右鍵點(diǎn)擊檢查或者F12,,使用檢查功能查看網(wǎng)頁源代碼,當(dāng)我們點(diǎn)擊下一頁觀察瀏覽器的搜索欄的url并沒有改變,這是因?yàn)槔淳W(wǎng)做了反爬蟲機(jī)制, 職位信息并不在源代碼里,而是保存在JSON的文件里,因此我們直接下載JSON,并使用字典方法直接讀取數(shù)據(jù).即可拿到我們想要的python職位相關(guān)的信息,
待爬取的python工程師職位信息如下:
為了能爬到我們想要的數(shù)據(jù),我們要用程序來模擬瀏覽器來查看網(wǎng)頁,所以我們在爬取的過程中會加上頭信息,頭信息也是我們通過分析網(wǎng)頁獲取到的,通過網(wǎng)頁分析我們知道該請求的頭信息,以及請求的信息和請求的方式是POST請求,這樣我們就可以該url請求拿到我們想的數(shù)據(jù)做進(jìn)一步處理
爬取網(wǎng)頁信息代碼如下:
import requestsurl = ' https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'def get_json(url, num): """ 從指定的url中通過requests請求攜帶請求頭和請求體獲取網(wǎng)頁中的信息, :return: """ url1 = 'https://www.lagou.com/jobs/list_python開發(fā)工程師?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_數(shù)據(jù)分析?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('請求響應(yīng)結(jié)果:', page_data, '\n\n') return page_dataprint(get_json(url, 1))
通過搜索我們知道每頁顯示15個職位,最多顯示30頁,通過分析網(wǎng)頁源代碼知道,可以通過JSON里讀取總職位數(shù),通過總的職位數(shù)和每頁能顯示的職位數(shù).我們可以計(jì)算出總共有多少頁,然后使用循環(huán)按頁爬取, 最后將職位信息匯總, 寫入到CSV格式的文件中.
程序運(yùn)行結(jié)果如圖:?
爬取所有python相關(guān)職位信息如下:
數(shù)據(jù)清洗其實(shí)會占用很大一部分工作,我們在這里只做一些簡單的數(shù)據(jù)分析后入庫。在拉勾網(wǎng)輸入python相關(guān)的職位會有18988個。你可以根據(jù)工作中需求選擇要入庫的字段,并對一些字段做進(jìn)一步的篩選,比如我們可以去除職位名稱中為實(shí)習(xí)生的崗位,過濾指定的字段區(qū)域在我們指定區(qū)域的職位,取字段薪資的平均值,以最低值和差值的四分之一為平均值等等根據(jù)需求自由發(fā)揮
import pandas as pdimport matplotlib.pyplot as pltimport statsmodels.api as smfrom wordcloud import WordCloudfrom scipy.misc import imreadfrom imageio import imreadimport jiebafrom pylab import mpl# 使用matplotlib能夠顯示中文mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默認(rèn)字體mpl.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負(fù)號'-'顯示為方塊的問題# 讀取數(shù)據(jù)df = pd.read_csv('Python_development_engineer.csv', encoding='utf-8')# 進(jìn)行數(shù)據(jù)清洗,過濾掉實(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 = 0for i in df['工作年限']: # print('每個職位對應(yīng)的工作年限',i) # 如果工作經(jīng)驗(yàn)為'不限'或'應(yīng)屆畢業(yè)生',那么匹配值為空,工作年限為0 if len(i) == 0: avg_work_year.append(0) # print('nihao') count = 1 # 如果匹配值為一個數(shù)值,那么返回該數(shù)值 elif len(i) == 1: # print('hello world') avg_work_year.append(int(''.join(i))) count = 1 # 如果匹配為一個區(qū)間則取平均值 else: num_list = [int(j) for j in i] avg_year = sum(num_list) / 2 avg_work_year.append(avg_year) count = 1print(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ù)的可視化展示,僅以部分視圖進(jìn)行一些可視化的展示,如果讀者想對其他字段做一些展示以及想使用不同的視圖類型進(jìn)行展示,請自行發(fā)揮,注:以下代碼中引入的模塊見最后的完整代碼
如果我們想看看關(guān)于互聯(lián)網(wǎng)行業(yè)python工程師相關(guān)的崗位大家普遍薪資的一個分部區(qū)間在哪個范圍,占據(jù)了多達(dá)的比例我們就可以借助matplotlib庫,來將我們保存在csv文件中的數(shù)據(jù)進(jìn)行可視化的展示,然我們能夠更直觀的看到數(shù)據(jù)的一個分部趨勢
# 繪制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é)果如下:
通過地理python職位地理位置的分部我們可以大致了解IT行業(yè)主要集中分部在哪些城市,這樣也更利于我們選擇地域進(jìn)行選擇性就業(yè),可以獲得更多的面試機(jī)會等,參數(shù)可自行調(diào)試,或根據(jù)需要添加。
# 繪制餅狀圖并保存city = df['城市'].value_counts()print(type(city))# print(len(city))label = city.keys()print(label)city_list = []count = 0n = 1distance = []for i in city: city_list.append(i) print('列表長度', 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é)果如下:
pycharts是python中調(diào)用百度基于js開發(fā)的echarts接口,也可以對數(shù)據(jù)進(jìn)行各種可視化操作,更多數(shù)據(jù)可視化圖形展示,可參考echarts官網(wǎng):https://www.echartsjs.com/,echarts官網(wǎng)提供了各種實(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 # 等價于keys = city.keys()values = city.valuesfrom pyecharts import Barbar = Bar("python職位的城市分布圖")bar.add("城市", keys, values)bar.print_echarts_options() # 該行只為了打印配置項(xiàng),方便調(diào)試時使用bar.render(path='a.html')
運(yùn)行結(jié)果如下:
?
詞云圖又叫文字云,是對文本數(shù)據(jù)中出現(xiàn)頻率較高的關(guān)鍵詞予以視覺上的突出,形成"關(guān)鍵詞的渲染"就類似云一樣的彩色圖片,從而過濾掉大量的文本信息,,使人一眼就可以領(lǐng)略文本數(shù)據(jù)的主要表達(dá)意思。利用jieba分詞和詞云生成WorldCloud(可自定義背景),下面就是對python相關(guān)職位的福利做了一個詞云的展示,可以更直觀的看到大多數(shù)公司的福利待遇集中在哪些地方
# 繪制福利待遇的詞云text = ''for line in df['公司福利']: if len(eval(line)) == 0: continue else: for word in eval(line): # print(word) text = wordcut_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é)果如下:
完整代碼在下面,代碼均測試可正常運(yùn)行,感興趣的小伙伴可去嘗試和了解其中的使用方法,如運(yùn)行或者模塊安裝等失敗可以在評論區(qū)進(jìn)行留言,讓我們一同解決吧
如果你覺得對你有幫助可以點(diǎn)個贊哦,原創(chuàng)內(nèi)容轉(zhuǎn)載需說明出處?。。?/p>
為了防止我們頻繁請求一個網(wǎng)站被限制ip,我們在爬取每一頁后選擇睡一段時間,當(dāng)然你也可以使用代理等其他方式自行實(shí)現(xiàn)
import requestsimport mathimport timeimport pandas as pddef get_json(url, num): """ 從指定的url中通過requests請求攜帶請求頭和請求體獲取網(wǎng)頁中的信息, :return: """ url1 = 'https://www.lagou.com/jobs/list_python開發(fā)工程師?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_數(shù)據(jù)分析?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('請求響應(yīng)結(jié)果:', page_data, '\n\n') return page_datadef get_page_num(count): """ 計(jì)算要抓取的頁數(shù),通過在拉勾網(wǎng)輸入關(guān)鍵字信息,可以發(fā)現(xiàn)最多顯示30頁信息,每頁最多顯示15個職位信息 :return: """ page_num = math.ceil(count / 15) if page_num > 30: return 30 else: return page_numdef get_page_info(jobs_list): """ 獲取職位 :param jobs_list: :return: """ page_info_list = [] for i in jobs_list: # 循環(huán)每一頁所有職位信息 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_listdef 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開發(fā)相關(guān)職位總數(shù):{},總頁數(shù)為:{}".format(total_page_count, num)) for num in range(1, num 1): # 獲取每一頁的職位相關(guān)的信息 page_data = get_json(url, num) # 獲取響應(yīng)json jobs_list = page_data['content']['positionResult']['result'] # 獲取每頁的所有python相關(guān)的職位信息 page_info = get_page_info(jobs_list) print("每一頁python相關(guān)的職位信息:%s" % page_info, '\n\n') total_info = page_info print('已經(jīng)爬取到第{}頁,職位總數(shù)為{}'.format(num, len(total_info))) time.sleep(20) # 將總數(shù)據(jù)轉(zhuǎn)化為data frame再輸出,然后在寫入到csv各式的文件中 df = pd.DataFrame(data=total_info, columns=['公司全名', '公司簡稱', '公司規(guī)模', '融資階段', '區(qū)域', '職位名稱', '工作經(jīng)驗(yàn)', '學(xué)歷要求', '薪資', '職位福利', '經(jīng)營范圍', '職位類型', '公司福利', '第二職位類型', '城市']) # df.to_csv('Python_development_engineer.csv', index=False) print('python相關(guān)職位信息已保存')if __name__ == '__main__': main()
數(shù)據(jù)可視化涉及到matplotlib、jieba、wordcloud、pyecharts、pylab、scipy等等模塊的使用,讀者可以自行了解各個模塊的使用方法,和其中涉及的各種參數(shù)
import pandas as pdimport matplotlib.pyplot as pltimport statsmodels.api as smfrom wordcloud import WordCloudfrom scipy.misc import imread# from imageio import imreadimport jiebafrom pylab import mpl# 使用matplotlib能夠顯示中文mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默認(rèn)字體mpl.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負(fù)號'-'顯示為方塊的問題# 讀取數(shù)據(jù)df = pd.read_csv('Python_development_engineer.csv', encoding='utf-8')# 進(jìn)行數(shù)據(jù)清洗,過濾掉實(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 = 0for i in df['工作年限']: # print('每個職位對應(yīng)的工作年限',i) # 如果工作經(jīng)驗(yàn)為'不限'或'應(yīng)屆畢業(yè)生',那么匹配值為空,工作年限為0 if len(i) == 0: avg_work_year.append(0) # print('nihao') count = 1 # 如果匹配值為一個數(shù)值,那么返回該數(shù)值 elif len(i) == 1: # print('hello world') avg_work_year.append(int(''.join(i))) count = 1 # 如果匹配為一個區(qū)間則取平均值 else: num_list = [int(j) for j in i] avg_year = sum(num_list) / 2 avg_work_year.append(avg_year) count = 1print(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 = 0n = 1distance = []for i in city: city_list.append(i) print('列表長度', 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 = wordcut_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 # 等價于keys = city.keys()values = city.valuesfrom pyecharts import Barbar = Bar("python職位的城市分布圖")bar.add("城市", keys, values)bar.print_echarts_options() # 該行只為了打印配置項(xiàng),方便調(diào)試時使用bar.render(path='a.html')
?
來源:https://www.icode9.com/content-1-306551.html聯(lián)系客服