1. 程式人生 > >python、Java、大資料和Android的薪資如何?

python、Java、大資料和Android的薪資如何?

  莫名其妙,從去年年底開始,Python這個東西在中國,突然一下子就火起來了,直至現在,他的熱度更是超越了java,成為軟體工程師最為關注的話題。Python之所以能火起來,很大一方面是因為大資料、人工智慧和機器學習越來越受人關注的原因,那麼,伴隨著Python的火熱,他的薪資是否也相應的高了起來了呢?於是,針對這個話題,在今年暑假,我做了一個關於Python、java和大資料和安卓的工作崗位的調查。

  Java火了幾十年,工作也是所有程式語言中最容易找的,這裡面有很大一部分原因是由於安卓還得由Java開發(即使現在出了Kotlin),那麼Python和大資料的工作狀態又是怎麼樣的呢?於是在這裡,我從51job中爬取了這四個職業的相關情況。

一、專案介紹

主要目標

1、分析python、Java、大資料和Android崗位的薪資如何?

2、分析python、Java、大資料和Android崗位在全國的分佈情況

3、python、Java、大資料和Android的前景到底如何?

環境

win7、python2、pychram

技術

1、資料採集:scrapy、

2、資料儲存:csv檔案、json檔案

3、資料清洗:pandas

4、視覺化:matplotlib、百度地圖API

二、爬取

在招聘網上分別搜尋這四個職業,查看了一下url、頁碼和需要爬取的資料,求出xpath

使用scrapy框架進行爬取,程式碼如下:

items:

import scrapy


class Job51Item(scrapy.Item):
    # 職位名
    jobname = scrapy.Field()

    # 公司名
    company = scrapy.Field()

    # 工作地點
    work_place = scrapy.Field()

    # 薪資
    salary = scrapy.Field()

    # 職位連結
    joblink = scrapy.Field()

spiders:

# -*- coding: utf-8 -*-
import scrapy
from
..items import Job51Item class JobSpider(scrapy.Spider): name = 'job' allowed_domains = ['51job.com'] offset = 1 # ------------ # 控制鏈 lang = '安卓' # 職位 page = 260 # 頁碼 # ------------ start_urls = ['https://search.51job.com/list/000000,000000,0000,00,9,99,%s,2,%d.html'%(lang,offset)] def parse(self, response): ajob = response.xpath('//div[@id="resultList"]/div[@class="el"]') for job in ajob: item = Job51Item() item['jobname'] = job.xpath('./p/span/a/@title').extract() item['company'] = job.xpath('./span[1]/a/text()').extract() item['work_place'] = job.xpath('./span[2]/text()').extract() item['salary'] = job.xpath('./span[3]/text()').extract() item['joblink'] = job.xpath('./p/span/a/@href').extract() yield item if self.offset <= self.page: self.offset += 1 yield scrapy.Request(url='https://search.51job.com/list/000000,000000,0000,00,9,99,%s,2,%d.html'%(self.lang,self.offset),callback=self.parse)

修改控制鏈中的langpage變數,分別爬取4個職位。

執行scrapyscrapy crawl job -o android1.csv

資料儲存在一個csv檔案中,會得到5csv檔案,對應4種職位,其中AndroidAndroid和安卓:

接下來對檔案去重合並:

# -*- coding: utf-8 -*-
import pandas as pd

java_job = pd.read_csv('data/job_java.csv')
# print java_job.shape
# (100000, 5)

python_job = pd.read_csv('data/job_python.csv')
# print python_job.shape
# (41421, 5)

bigdata_job = pd.read_csv('data/job_bigdata.csv')
# print bigdata_job.shape
# (61191, 5)

android1_job = pd.read_csv('data/job_android1.csv')
# print android1_job.shape
# (31734, 5)

android2_job = pd.read_csv('data/job_android2.csv')
# print android2_job.shape
# (12961, 5)

df = pd.concat([java_job,python_job,bigdata_job,android1_job,android2_job])
# df = python_job.append(java_job).append(bigdata_job)
# print df.shape
# (202612, 10)
# 新增Android12之後:(247308, 5)

# df.to_csv('data/job.csv',index=False)
df.drop_duplicates(inplace=True)
print df.shape
# (168544, 5)
# (192781, 5)
df = df.reindex(columns=[u'jobname', u'work_place', u'salary', u'company', u'joblink'])
df.to_csv('data/job.csv',index=False)

檔案:

部分檔案結果截圖:

接著跟進連結,爬取職位詳細資訊,如圖:

程式碼如下:

items:

class BaseJobItem(scrapy.Item):

    # 職位連結
    job_link = scrapy.Field()

    # 職位資訊
    job_info = scrapy.Field()

    # 職能型別
    job_type = scrapy.Field()

spiders

# -*- coding: utf-8 -*-
import scrapy
from ..items import BaseJobItem
import pandas as pd


def get_link():

    df = pd.read_csv('../data/job.csv',encoding='utf-8')

    return df['joblink']


class JobSpider(scrapy.Spider):
    name = 'basejob'
    allowed_domains = ['51job.com']

    start_urls = get_link()

    def parse(self, response):

        item = BaseJobItem()

        job_info = response.xpath('//div[@class="bmsg job_msg inbox"]/p/text()').extract()
        job_type = response.xpath('//div[@class="bmsg job_msg inbox"]/div[@class="mt10"]/p[1]/span[@class="el"]/text()').extract()

        item['job_link'] = response.url
        item['job_info'] = job_info
        item['job_type'] = job_type

        return item

執行:scrapy crawl basejob -o basejob.csv

資料量有點大,話費了三個小時爬完。

效果如下:

檔案有184M

接下來將兩個檔案(job.csvbasejob.csv)合併:

# -*- coding: utf-8 -*-
import pandas as pd

df1 = pd.read_csv('./data/basejob.csv',header=0,encoding='utf-8',names=u'job_info,job_type,joblink'.split(','))

df2 = pd.read_csv('./data/job.csv',encoding='utf-8')

# print df1.head()
df = pd.merge(df1,df2,on='joblink')

print df.sample(5)

df = df.reindex(columns=u'jobname,work_place,salary,company,joblink,job_type,job_info'.split(','))
df.to_csv('./data/zhaoping.csv',index=False,encoding='utf-8')
# ,index_label=u'jobname,work_place,salary,company,joblink,job_type,job_info'.split(',')

得到最終檔案zhaoping.csv

 三、分析

這四種職業的薪資如何呢?針對這個問題,我將這些資料進行清洗,然後分析再使之視覺化。

因為只需要分析薪資,所以知道職位和薪資的欄位就行了,這裡使用job.csv檔案進行分析。

首先讀取資料並清洗:

import pandas as pd

df = pd.read_csv('data/job.csv', encoding='utf-8')

df = df[~df['salary'].isna()]

df['salary'] = df['salary'].apply(get_salary)

接下來將薪資格式化:

def get_salary(salary):
    """
    將薪資格式化
    :param salary:薪資,如:1-1.5萬/月
    :return: 10K
    """

    time = salary.split('/')[1]
    if salary.__contains__('-'):
        money = salary.split('/')[0][-1]
        salary_num = salary.split('-')[0]
    else:
        salary_num = re.search('\d+',salary.split('/')[0]).group()
        money = salary.split('/')[0].strip(salary_num)
    try:
        salary_num = float(salary_num)
    except:
        print salary,'=',money,salary_num
    if time == u'':
        salary_num = salary_num/12
    elif time == u'':
        salary_num *= 30.
    elif time == u'小時':
        salary_num *= 30*12
    if money == u'':
        salary_num *= 10
    elif money == u'':
        salary_num /= 1000

    return salary_num

獲取不同語言的薪資待遇的對比並畫圖:

def diff_lang():
    """
    獲取不同語言的薪資待遇的對比
    :return:
    """

    lang = ['python','java',u'大資料',u'安卓','android']

    avg_salary = map(get_avg_salary,lang)

    # 針對Android和安卓做特殊處理
    lang = lang[:-1]
    avg_salary = avg_salary[:-2]+[sum(avg_salary[-2:])/len(avg_salary[-2:])]

    print lang
    print avg_salary

    for i,j in zip(lang,avg_salary):
        print '%s的平均薪資為:%.3fK' % (i.encode('utf-8'),j)

    p = plt.bar(lang,avg_salary)

    autolabel(p)
    plt.xlabel(u'程式語言')
    plt.ylabel(u'平均薪資')
    plt.title(u'python、java、大資料和安卓職業薪資待遇對比')
    plt.show()

還有獲取某個程式語言的平均薪資的方法:

def get_avg_salary(lang='',city=''):
    """
    獲取某個程式語言的平均薪資
    :param lang: 程式語言名
    :return: 平均薪資
    """
    jobdf = df[df['jobname'].str.contains(lang)]

    if city != '':
        jobdf = jobdf[jobdf['work_place'].str.contains(city)]
        if jobdf.shape[0] < 10:
            return
    sum_salary = jobdf['salary']

    return sum_salary.astype(float).mean()

還有畫圖時顯示柱狀圖上的數值的方法:

def autolabel(rects):
    """
    定義函式來顯示柱狀上的數值
    :param rects:matplotlib.container.BarContainer
    :return:
    """
    for rect in rects:
        height = rect.get_height()
        plt.text(rect.get_x(), 1.01*height, '%.1f' % float(height))

為了顯示中文字還要宣告一下字型:

plt.rcParams['font.sans-serif'] = ['kaiti']

執行diff_lang()函式:

從圖中可以看出,大資料的薪資是最高的,達到了1W以上,而PythonJava位居二三,卻遠遠沒有大資料的薪資高,而安卓在這幾個職位中薪資是最低的。

然後對同一語言不通地區薪資的待遇進行分析對比:

def diff_place():
    """
    獲取同一語言不通地區薪資的待遇
    :return:
    """

    citys = list(df['work_place'].str.split('-').map(lambda x:x[0]).drop_duplicates())

    citys.remove(u'朝陽')
    # 朝陽有點特殊,有些城市直接就是朝陽,不過數量太少,直接忽略了,所以這裡做朝陽的特殊處理

    lang = ['python', 'java', u'大資料',u'安卓','android']

    # ls如:['python','北京']
    ls = [[a,b] for a in lang for b in citys]

    # x是某種語言在某個城市的平均薪資
    x = [get_avg_salary(*l) for l in ls]


    info = {}

    for i,j in zip(ls,x):
        # if j != None:
        #     print i[0],i[1],j
        if not info.has_key(i[0]):
            info[i[0]] = {}
            info[i[0]]['city'] = []
            info[i[0]]['avg_salary'] = []
        if j != None:
            info[i[0]]['city'] += [i[1]]
            info[i[0]]['avg_salary'] += [j]

    # info的可能取值如:info = {"python": {"city": ["上海", "成都",...],"avg_salary": [11.974358974358974, 7.016129032258065, ...]},...}

    # 特殊處理:對安卓和Android的資料進行合併
    info = get_android(info)

    with open('./data/inf.json','w') as inf:
        json.dump(info,inf)

    plt.figure(1,(12,6))
    plt.title(u'python、java、大資料和安卓職業各城市薪資待遇對比(單位:K)')
    for l in lang[:-1]:
        plt.subplot(len(lang[:-1]),1,lang.index(l) + 1)

        so = zip(info[l]['city'],info[l]['avg_salary'])
        so.sort(key=lambda x:x[1],reverse=True)
        p = plt.bar(range(len(info[l]['city'])),map(lambda x:x[1],so),label=l)
        plt.xticks(range(len(info[l]['city'])),map(lambda x:x[0],so),rotation=45)
        autolabel(p)
        plt.tight_layout()
        plt.legend()

    plt.show()

對安卓和Android的資料進行合併:

def get_android(info):
    """
    對安卓和Android的資料進行合併
    :param info: = {"python": {"city": ["上海", "成都",...],"avg_salary": [11.974358974358974, 7.016129032258065, ...]},...}

    :return: info
    """
    citys = set(info['android']['city']+info[u'安卓']['city'])

    for city in citys:
        i,j = 0, 0
        if city in info['android']['city']:
            i = info['android']['avg_salary'][info['android']['city'].index(city)]
        if city in info[u'安卓']['city']:
            j = info[u'安卓']['avg_salary'][info[u'安卓']['city'].index(city)]
        else:
            info[u'安卓']['city'].append(city)
            info[u'安卓']['avg_salary'].append(i)
        info[u'安卓']['avg_salary'][info[u'安卓']['city'].index(city)] = (i+j)/2
    del info['android']
    return info

最後得到同一語言不同地區薪資的待遇結果圖如下:

可以以熱力圖顯示資料,這裡使用百度的api

# -*- coding: utf-8 -*-
import json
from urllib import urlopen, quote
import sys

reload(sys)
sys.setdefaultencoding('utf-8')

def getlnglat(address):
    url = 'http://api.map.baidu.com/geocoder/v2/'
    output = 'json'
    ak = 'FOtHtZ92dCKMjpx0XA05g8VEZn95QWOK'
    add = quote(address.encode('utf-8')) #由於本文城市變數為中文,為防止亂碼,先用quote進行編碼
    uri = url + '?' + 'address=' + add  + '&output=' + output + '&ak=' + ak
    print uri
    req = urlopen(uri)
    res = req.read() #將其他編碼的字串解碼成unicode
    temp = json.loads(res) #對json資料進行解析
    return temp

file = open(r'./data/city.json','w') #建立json資料檔案
with open(r'./data/test.json', 'r') as f:

    js = json.load(f)

    data = []
    for k,v in js.iteritems():
        c = {}
        c['city'] = k
        c['points'] = []
        for i in range(len(v['city'])):
            if v['city'][i] == u'異地招聘':
                continue
            lnglat = getlnglat(v['city'][i])  # 採用構造的函式來獲取經度
            test = {}
            test['lng'] = lnglat['result']['location']['lng']
            test['lat'] = lnglat['result']['location']['lat']
            test['count'] = v['avg_salary'][i]

            c['points'].append(test)
        data.append(c)

    json.dump(data,file,ensure_ascii=False)

那麼Python在不同地區薪資的待遇熱力圖如下,其中,越往中間顏色越深薪資越高:

從上如看出Python 的主要工作地區集中在長江三角洲、珠江三角洲一帶,而北京的薪資是最高的還有幾個內地城市佔比也不低。

那麼看一下Java在不同地區薪資的待遇熱力圖:

 

從圖可以看出,Java工作地點同樣是集中於那三帶地區,不過相比於Python,他的主要工作地點更多,且最高薪資大多集中在珠江三角洲。

再看一下大資料在不同地區薪資的待遇熱力圖:

目測大資料和Java分佈差別不大,不過從圖中紅色區域分佈可以看出,大資料的薪資更高。

最後看一下安卓在不同地區薪資的待遇熱力圖:

 

安卓的工作分佈低於其他的幾種(比Python略高點),而且薪資也也不如其他的幾門語言。

從上述四個熱力圖分析不難看出:

1、大資料無論是工作地點還是薪資均高於其他三種職業;

2、Python火則火矣,薪資也不低,但工作地點還是太少;

3、Java仍舊是寶刀未老,其工作地點和薪資也僅次於大資料行業;

4、安卓終究過時了,薪資比不上其他三個職業,也就工作地點要比Python多點;

由此觀之,大資料的發展空間是最大的,前途也是最好的,Java仍然是不二的選擇,Android已過時,Python還待發展。

再看一下4種職位的崗位分析圖

先看Python崗位的程式碼:

# -*- coding: utf-8 -*-
import pandas as pd
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['kaiti']

df = pd.read_csv('./data/job_python.csv',encoding='utf-8')

s = df['jobname'].value_counts()

job = s[s>150]

plt.pie(x =job.values,labels=job.index,autopct='%2.1f%%')

plt.show()

其他的同理,最後得到餅圖:

Python

Java

大資料:

安卓:

最後來看一下Python語言的職能型別詞雲,程式碼:

# -*- coding: utf-8 -*-
import pandas as pd


df1 = pd.read_csv('./data/job_python.csv',encoding='utf-8')

df2 = pd.read_csv('./data/zhaoping.csv', encoding='utf-8')

df = pd.merge(df1,df2,on=list(df1.columns))

df = df[~df['job_info'].isna()]

dfpy = df[df['job_info'].str.contains('python')]

s = dfpy['job_type'].str.split(',').sum()

# print pd.Series(s).value_counts()
print s

# 繪製詞雲圖:
from wordcloud import WordCloud
import matplotlib.pylab as plt


wl = " ".join(s)

generate = WordCloud(
    # 'C:/Users/Windows/fonts/msyh.ttf'
    font_path = 'C:/Users/Windows/fonts/msyh.ttf',
    background_color='white',
    max_words=30,
    prefer_horizontal = 0.8,
    random_state=88
).generate(wl)

plt.figure(figsize=(8,5))
plt.imshow(generate)
plt.axis("off")
# plt.savefig(u'../day5-2/黑卡詞雲圖.png')
plt.show()

其他職業的也大致如此.

Python:

Java:

大資料:

安卓: