爬取拉勾網關於python職位相關的數據信息,並將爬取的數據已csv各式存入文件,而後對csv文件相關字段的數據進行清洗,並對數據可視化展現,包括柱狀圖展現、直方圖展現、詞雲展現等並根據可視化的數據作進一步的分析,其他分析和展現讀者可自行發揮和擴展包括各類分析和不一樣的存儲方式等。。。。。html
在以上安裝或使用過程當中可能讀者會遇到安裝或導入失敗等問題自行百度,選擇依賴包的合適版本python
經過Chrome搜索'python工程師',而後右鍵點擊檢查或者F12,,使用檢查功能查看網頁源代碼,當咱們點擊下一頁觀察瀏覽器的搜索欄的url並無改變,這是由於拉勾網作了反爬蟲機制, 職位信息並不在源代碼裏,而是保存在JSON的文件裏,所以咱們直接下載JSON,並使用字典方法直接讀取數據.便可拿到咱們想要的python職位相關的信息,面試
待爬取的python工程師職位信息以下:正則表達式
爲了能爬到咱們想要的數據,咱們要用程序來模擬瀏覽器來查看網頁,因此咱們在爬取的過程當中會加上頭信息,頭信息也是咱們經過分析網頁獲取到的,經過網頁分析咱們知道該請求的頭信息,以及請求的信息和請求的方式是POST請求,這樣咱們就能夠該url請求拿到咱們想的數據作進一步處理json
爬取網頁信息代碼以下:api
import requests url = ' https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false' def get_json(url, num): """ 從指定的url中經過requests請求攜帶請求頭和請求體獲取網頁中的信息, :return: """ url1 = 'https://www.lagou.com/jobs/list_python%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88?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_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?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('請求響應結果:', page_data, '\n\n') return page_data print(get_json(url, 1))
經過搜索咱們知道每頁顯示15個職位,最多顯示30頁,經過分析網頁源代碼知道,能夠經過JSON裏讀取總職位數,經過總的職位數和每頁能顯示的職位數.咱們能夠計算出總共有多少頁,而後使用循環按頁爬取, 最後將職位信息彙總, 寫入到CSV格式的文件中.瀏覽器
程序運行結果如圖: cookie
爬取全部python相關職位信息以下:網絡
數據清洗其實會佔用很大一部分工做,咱們在這裏只作一些簡單的數據分析後入庫。在拉勾網輸入python相關的職位會有18988個。你能夠根據工做中需求選擇要入庫的字段,並對一些字段作進一步的篩選,好比咱們能夠去除職位名稱中爲實習生的崗位,過濾指定的字段區域在咱們指定區域的職位,取字段薪資的平均值,以最低值和差值的四分之一爲平均值等等根據需求自由發揮session
import pandas as pd import matplotlib.pyplot as plt import statsmodels.api as sm from wordcloud import WordCloud from scipy.misc import imread from imageio import imread import jieba from pylab import mpl # 使用matplotlib可以顯示中文 mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默認字體 mpl.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負號'-'顯示爲方塊的問題 # 讀取數據 df = pd.read_csv('Python_development_engineer.csv', encoding='utf-8') # 進行數據清洗,過濾掉實習崗位 # df.drop(df[df['職位名稱'].str.contains('實習')].index, inplace=True) # print(df.describe()) # 因爲csv文件中的字符是字符串形式,先用正則表達式將字符串轉化爲列表,在去區間的均值 pattern = '\d+' # print(df['工做經驗'], '\n\n\n') # print(df['工做經驗'].str.findall(pattern)) df['工做年限'] = df['工做經驗'].str.findall(pattern) print(type(df['工做年限']), '\n\n\n') avg_work_year = [] count = 0 for i in df['工做年限']: # print('每一個職位對應的工做年限',i) # 若是工做經驗爲'不限'或'應屆畢業生',那麼匹配值爲空,工做年限爲0 if len(i) == 0: avg_work_year.append(0) # print('nihao') count += 1 # 若是匹配值爲一個數值,那麼返回該數值 elif len(i) == 1: # print('hello world') avg_work_year.append(int(''.join(i))) count += 1 # 若是匹配爲一個區間則取平均值 else: num_list = [int(j) for j in i] avg_year = sum(num_list) / 2 avg_work_year.append(avg_year) count += 1 print(count) df['avg_work_year'] = avg_work_year # 將字符串轉化爲列表,薪資取最低值加上區間值得25%,比較貼近現實 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)
下面是對數據的可視化展現,僅以部分視圖進行一些可視化的展現,若是讀者想對其餘字段作一些展現以及想使用不一樣的視圖類型進行展現,請自行發揮,注:如下代碼中引入的模塊見最後的完整代碼
若是咱們想看看關於互聯網行業python工程師相關的崗位你們廣泛薪資的一個分部區間在哪一個範圍,佔據了多達的比例咱們就能夠藉助matplotlib庫,來將咱們保存在csv文件中的數據進行可視化的展現,然咱們可以更直觀的看到數據的一個分部趨勢
# 繪製python薪資的頻率直方圖並保存 plt.hist(df['月薪'],bins=8,facecolor='#ff6700',edgecolor='blue') # bins是默認的條形數目 plt.xlabel('薪資(單位/千元)') plt.ylabel('頻數/頻率') plt.title('python薪資直方圖') plt.savefig('python薪資分佈.jpg') plt.show()
運行結果以下:
經過地理python職位地理位置的分部咱們能夠大體瞭解IT行業主要集中分部在哪些城市,這樣也更利於咱們選擇地域進行選擇性就業,能夠得到更多的面試機會等,參數可自行調試,或根據須要添加。
# 繪製餅狀圖並保存 city = df['城市'].value_counts() print(type(city)) # print(len(city)) label = city.keys() print(label) city_list = [] count = 0 n = 1 distance = [] 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()
運行結果以下:
pycharts是python中調用百度基於js開發的echarts接口,也能夠對數據進行各類可視化操做,更多數據可視化圖形展現,可參考echarts官網:https://www.echartsjs.com/,echarts官網提供了各類實例供咱們參考,如折線圖、柱狀圖、餅圖、路徑圖、樹圖等等,基於pyecharts的文檔可參考如下官網:https://pyecharts.org/#/,更多用法也可自行百度網絡資源
city = df['城市'].value_counts() print(type(city)) print(city) # print(len(city)) keys = city.index # 等價於keys = city.keys() values = city.values from pyecharts import Bar bar = Bar("python職位的城市分佈圖") bar.add("城市", keys, values) bar.print_echarts_options() # 該行只爲了打印配置項,方便調試時使用 bar.render(path='a.html')
運行結果以下:
詞雲圖又叫文字雲,是對文本數據中出現頻率較高的關鍵詞予以視覺上的突出,造成"關鍵詞的渲染"就相似雲同樣的彩色圖片,從而過濾掉大量的文本信息,,令人一眼就能夠領略文本數據的主要表達意思。利用jieba分詞和詞雲生成WorldCloud(可自定義背景),下面就是對python相關職位的福利作了一個詞雲的展現,能夠更直觀的看到大多數公司的福利待遇集中在哪些地方
# 繪製福利待遇的詞雲 text = '' for line in df['公司福利']: if len(eval(line)) == 0: continue else: for word in eval(line): # print(word) text += word cut_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()
運行結果以下:
完整代碼在下面,代碼均測試可正常運行,感興趣的小夥伴可去嘗試和了解其中的使用方法,如運行或者模塊安裝等失敗能夠在評論區進行留言,讓咱們一同解決吧
若是你以爲對你有幫助能夠點個贊哦,原創內容轉載需說明出處!!!
爲了防止咱們頻繁請求一個網站被限制ip,咱們在爬取每一頁後選擇睡一段時間,固然你也可使用代理等其餘方式自行實現
import requests import math import time import pandas as pd def get_json(url, num): """ 從指定的url中經過requests請求攜帶請求頭和請求體獲取網頁中的信息, :return: """ url1 = 'https://www.lagou.com/jobs/list_python%E5%BC%80%E5%8F%91%E5%B7%A5%E7%A8%8B%E5%B8%88?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_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?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('請求響應結果:', page_data, '\n\n') return page_data def get_page_num(count): """ 計算要抓取的頁數,經過在拉勾網輸入關鍵字信息,能夠發現最多顯示30頁信息,每頁最多顯示15個職位信息 :return: """ page_num = math.ceil(count / 15) if page_num > 30: return 30 else: return page_num def get_page_info(jobs_list): """ 獲取職位 :param jobs_list: :return: """ page_info_list = [] for i in jobs_list: # 循環每一頁全部職位信息 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_list def 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開發相關職位總數:{},總頁數爲:{}".format(total_page_count, num)) for num in range(1, num + 1): # 獲取每一頁的職位相關的信息 page_data = get_json(url, num) # 獲取響應json jobs_list = page_data['content']['positionResult']['result'] # 獲取每頁的全部python相關的職位信息 page_info = get_page_info(jobs_list) print("每一頁python相關的職位信息:%s" % page_info, '\n\n') total_info += page_info print('已經爬取到第{}頁,職位總數爲{}'.format(num, len(total_info))) time.sleep(20) # 將總數據轉化爲data frame再輸出,而後在寫入到csv各式的文件中 df = pd.DataFrame(data=total_info, columns=['公司全名', '公司簡稱', '公司規模', '融資階段', '區域', '職位名稱', '工做經驗', '學歷要求', '薪資', '職位福利', '經營範圍', '職位類型', '公司福利', '第二職位類型', '城市']) # df.to_csv('Python_development_engineer.csv', index=False) print('python相關職位信息已保存') if __name__ == '__main__': main()
數據可視化涉及到matplotlib、jieba、wordcloud、pyecharts、pylab、scipy等等模塊的使用,讀者能夠自行了解各個模塊的使用方法,和其中涉及的各類參數
import pandas as pd import matplotlib.pyplot as plt import statsmodels.api as sm from wordcloud import WordCloud from scipy.misc import imread # from imageio import imread import jieba from pylab import mpl # 使用matplotlib可以顯示中文 mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默認字體 mpl.rcParams['axes.unicode_minus'] = False # 解決保存圖像是負號'-'顯示爲方塊的問題 # 讀取數據 df = pd.read_csv('Python_development_engineer.csv', encoding='utf-8') # 進行數據清洗,過濾掉實習崗位 # df.drop(df[df['職位名稱'].str.contains('實習')].index, inplace=True) # print(df.describe()) # 因爲csv文件中的字符是字符串形式,先用正則表達式將字符串轉化爲列表,在去區間的均值 pattern = '\d+' # print(df['工做經驗'], '\n\n\n') # print(df['工做經驗'].str.findall(pattern)) df['工做年限'] = df['工做經驗'].str.findall(pattern) print(type(df['工做年限']), '\n\n\n') avg_work_year = [] count = 0 for i in df['工做年限']: # print('每一個職位對應的工做年限',i) # 若是工做經驗爲'不限'或'應屆畢業生',那麼匹配值爲空,工做年限爲0 if len(i) == 0: avg_work_year.append(0) # print('nihao') count += 1 # 若是匹配值爲一個數值,那麼返回該數值 elif len(i) == 1: # print('hello world') avg_work_year.append(int(''.join(i))) count += 1 # 若是匹配爲一個區間則取平均值 else: num_list = [int(j) for j in i] avg_year = sum(num_list) / 2 avg_work_year.append(avg_year) count += 1 print(count) df['avg_work_year'] = avg_work_year # 將字符串轉化爲列表,薪資取最低值加上區間值得25%,比較貼近現實 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) """一、繪製python薪資的頻率直方圖並保存""" plt.hist(df['月薪'], bins=8, facecolor='#ff6700', edgecolor='blue') # bins是默認的條形數目 plt.xlabel('薪資(單位/千元)') plt.ylabel('頻數/頻率') plt.title('python薪資直方圖') plt.savefig('python薪資分佈.jpg') plt.show() """二、繪製餅狀圖並保存""" city = df['城市'].value_counts() print(type(city)) # print(len(city)) label = city.keys() print(label) city_list = [] count = 0 n = 1 distance = [] 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() """三、繪製福利待遇的詞雲""" text = '' for line in df['公司福利']: if len(eval(line)) == 0: continue else: for word in eval(line): # print(word) text += word cut_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() """四、基於pyechart的柱狀圖""" city = df['城市'].value_counts() print(type(city)) print(city) # print(len(city)) keys = city.index # 等價於keys = city.keys() values = city.values from pyecharts import Bar bar = Bar("python職位的城市分佈圖") bar.add("城市", keys, values) bar.print_echarts_options() # 該行只爲了打印配置項,方便調試時使用 bar.render(path='a.html')