爬取BOSS直聘信息并进行清理和可视化分析(python小白)

时间:2024-03-22 13:44:08
年底了,学习数据分析快四个月了。为了尽快找到一份数据分析相关的工作,计划把BOSS直聘上的相关职位都爬取下来分析分析,也好检验一下最近的学习成果。python新手,代码写的乱,将就看吧。首先,对给BOSS直聘服务器造成的扰动表示歉意;其次,赶紧赐我一个好工作吧!因为地处珠三角,这次计划爬取广州和深圳与数据分析、数据挖掘、数据运营相关的职位。

作为初学者,在实际操作的路上遇到无数坑,都一一记录下来,为以后提升打好基础。


# -*- coding=utf-8 -*-
import requests
import os
import re
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np
import time

首先设置文件路径。本文是用jupyter notebook写的,也可以不设置路径,后面需要的话再从notebook上下载文件。

#设置df的最大显示字符数
pd.set_option('max_colwidth',500)
#设置文件路径
folder_name='E:\share tragedy\liepin'
if not os.path.exists(folder_name):
    os.makedirs(folder_name)

数据抓取

BOSS直聘网站上有相当多的招聘信息,是按照城市+职位分类来分组显示的,其url像“https://www.zhipin.com/c101280100-p100511/?page=2&ka=page-2” 这样,c是城市名,p是职位position。所以首先通过主页url提取职位position信息,生成职位position表(df_job表)。

BOSS直聘采用很严格的反爬虫机制,登录页面有拖动验证,爬取信息过快时还会随时需要输入验证码,经常会造成爬取中断。

#获得职位编码对照表,主页面url如下
url="https://www.zhipin.com/?sid=sem_pz_bdpc_dasou_title"
#创建空白df,列名为职位编号(position)和职位名称
df_job=pd.DataFrame(columns=[['job_num','job_title']])
#构造表头。这里使用几个随机IP,模拟chrome浏览器登陆,并通过浏览器查找到cookie,方便后面的爬取,减少被是识别的几率。
proxies={'http': 'http://210.22.176.146:32153','http': 'http://211.152.33.24:48749','http': 'http://175.165.128.214:1133','http': 'http://36.110.14.66:50519'}
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
              'cookie':'_uab_collina=154410324775207731129147; lastCity=101010100; t=vPAu9pVZjhJw4CEs; wt=vPAu9pVZjhJw4CEs; sid=sem_pz_bdpc_dasou_title; JSESSIONID=""; __c=1544875350; __g=sem_pz_bdpc_dasou_title; __l=l=%2Fwww.zhipin.com%2F%3Fsid%3Dsem_pz_bdpc_dasou_title&r=https%3A%2F%2Fwww.baidu.com%2Fs%3Fwd%3Dboss%25E7%259B%25B4%25E8%2581%2598%26rsv_spt%3D1%26rsv_iqid%3D0xa2eaa2390016f56e%26issp%3D1%26f%3D8%26rsv_bp%3D0%26rsv_idx%3D2%26ie%3Dutf-8%26tn%3D90066238_hao_pg%26rsv_enter%3D1%26rsv_t%3D161dvC%252FaDWi%252Fh%252B1%252F7Li2Ji8FrSldZ4PCYkrVrBo1BpjThzGjwIzfr1jHvtvsMEXU2CM3GntQ&g=%2Fwww.zhipin.com%2F%3Fsid%3Dsem_pz_bdpc_dasou_title; Hm_lvt_194df3105ad7148dcf2b98a91b5e727a=1544103248,1544688540,1544757018,1544875351; 356'}
response=requests.get(url,headers=headers)
#读取url页面内容,找到'<div,class=‘text’>'相关的内容
soup=BeautifulSoup(response.content,'lxml')
job=soup.find_all('div','text')
#从job里面提取职位编号和职位名称,填充df_job
for i in range(0,len(job)):
    job_num_all=job[i].contents
    for j in range(1,len(job_num_all)):
        if j%2==1:
            job_num=job_num_all[j]['href'][12:19]
            job_title=job_num_all[j].text
            df_job=df_job.append(pd.DataFrame({'job_num':[job_num],'job_title':[job_title]}),ignore_index=True)
df_job.to_csv('E:/share tragedy/liepin/df_job.csv')
#获得城市编码对照表,这里重点城市比较少,直接查找网站获取城市代码后创建一个df_city
data={'city_num':[100010000,101010100,101020100,101280100,101280600,101210100,101030100,101110100,101190400,101200100,101230200,101250100,101270100,101180100,101040100],
      'city_name':['全国','北京','上海','广州','深圳','杭州','天津','西安','苏州','武汉','厦门','长沙','成都','郑州','重庆']}

df_city=pd.DataFrame(data)

df_city.to_csv('E:/share tragedy/liepin/df_city.csv')

打开生成的df_job和df_city表,发现跟数据分析相关的职位编号有3个,跟数据挖掘相关的职位编号有2个,其他还有数据运营和商业数据分析是跟数据分析相关的。很明显这些职位分类里面有很多是重叠的,所以后面需要查重。另外,boss直聘设置是每页显示30条招聘信息,最多显示10页,每条招聘信息对应一个唯一的27位编码(类似于’As2434Hsg-hsdbhdir34iygjhl-'这样),由大小写字母、数字和-构成。确定了编码也就确定了这条招聘信息。接下来首先需要爬取相关的编码,然后构造每条招聘信息的对应url,再逐一爬取。

#获取招聘信息编码,并生成对应的网页地址
#首先定义一个爬取招聘信息编码的函数get_join_sign,输入城市编码和职位编码号,a为爬取的页面数,通常boss直聘只显示10页,所以a=11,也可以人为设置.
def get_job_sign(job_city,job_title,a=11):
    df_ma=pd.DataFrame(columns=['p_new'])
    #为减少对服务器的压力,防止被封或需要刷新验证码,建议每次爬取的城市代码+职位代码数不超过5.
    if len(job_city)+len(job_title)>6:
        print '过多数据,可能因验证码中断操作,建议城市数+职位数小于5!'
    #每条url对应页面可以抓取30条职位编码,所以将大循环放最里面.
    for j in job_city:
        for k in job_title:
            for i in range(1,a):
                urls='https://www.zhipin.com/c'+str(j)+'-'+k+'/?page='+str(i)+'&ka=page-'+str(i)
                proxies={'http': 'http://210.22.176.146:32153','http': 'http://211.152.33.24:48749','http': 'http://175.165.128.214:1133','http': 'http://36.110.14.66:50519'}
                headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
                           'cookie':'_uab_collina=154410324775207731129147; lastCity=101010100; t=vPAu9pVZjhJw4CEs; wt=vPAu9pVZjhJw4CEs; sid=sem_pz_bdpc_dasou_title; JSESSIONID=""; __c=1544875350;__g=sem_pz_bdpc_dasou_title; __l=l=%2Fwww.zhipin.com%2F%3Fsid%3Dsem_pz_bdpc_dasou_title&r=https%3A%2F%2Fwww.baidu.com%2Fs%3Fwd%3Dboss%25E7%259B%25B4%25E8%2581%2598%26rsv_spt%3D1%26rsv_iqid%3D0xa2eaa2390016f56e%26issp%3D1%26f%3D8%26rsv_bp%3D0%26rsv_idx%3D2%26ie%3Dutf-8%26tn%3D90066238_hao_pg%26rsv_enter%3D1%26rsv_t%3D161dvC%252FaDWi%252Fh%252B1%252F7Li2Ji8FrSldZ4PCYkrVrBo1BpjThzGjwIzfr1jHvtvsMEXU2CM3GntQ&g=%2Fwww.zhipin.com%2F%3Fsid%3Dsem_pz_bdpc_dasou_title;Hm_lvt_194df3105ad7148dcf2b98a91b5e727a=1544103248,1544688540,1544757018,1544875351; 356'}

                response=requests.get(urls,headers=headers)
                #这里强烈建议每爬取一次页面休息30-60秒(sleep方法),既减轻对服务器的压力,也防止被封号或刷新验证码,同时可以保证能爬取所有需要的招聘信息编码。
                #time.sleep(30)
                page=response.content
                #因为每页有30条招聘信息编码,采用正则表达式提取更快捷方便
                data_jid=re.findall(r'data-jid="[a-zA-Z0-9-.+-]+~"',page,re.M)  
                if data_jid is not None:
                    for l in data_jid:
                        l=l[10:]
                        l=l[:-2]
                        #将招聘信息编码输入df_ma
                        df_ma=df_ma.append(pd.DataFrame({'p_new':[l]}),ignore_index=True)
    return df_ma

爬取广州、深圳所有关于数据分析师、数据挖掘、数据运营、商业数据分析的招聘信息;这里广州和深圳分开爬取后再合并,如果一次爬取建议用sleep方法,每爬取一条信息休息30秒。


df=get_job_sign([101280600],['p100104','p100509','p100511','p120301','p130103','p260102','p140108'])
#查重,减少后面重复爬取
df=df.drop_duplicates('p_new',keep='first')
#生成详细招聘信息的urls
df['number']=range(1,len(df)+1)
df['urls']="https://www.zhipin.com/job_detail/"+df['p_new']+"~.html?ka=search_list_"+df['number'].apply(lambda x:str(x)) 
df.to_csv('df_SZ_urls.csv')
print len(df['urls'])
过多数据,可能因验证码中断操作,建议城市数+职位数小于5!
508

定义一个提取职位信息的函数,输入为爬取的html内容,输出为df。招聘信息里有一些是不太完善的,经常会造成提取的信息内容与索引不对应,给后面数据清理造成麻烦,需要特别注意。


def get_job_detail(html):
    #创建空的列表,包括发布日期,薪水,城市,经验,学历,公司融资进展,公司规模,职位性质,职位名称,公司名称,注册资金,公司地址,公司描述和职位描述
    df_only=pd.DataFrame(columns=[['pub_date','salary','city','experience','education','finance','scale','trade',
                                 'job_title','company','registered_capital','address','company_describe','job_responsibility']])
    
    soup=BeautifulSoup(html,"lxml")
    
    #发布日期
    pub_date=soup.find('div','job-author')
    if pub_date is None:
        pub_date='no date'
    else:
        pub_date=pub_date.span.string[3:13]
    #薪水    
    salary=soup.find_all('div','name')
    if len(salary)<1:
        salary='no salary'
    elif 1<=len(salary)<=2:
        salary=salary[0].span.string
    else:
        salary=salary[1].span.string
    #城市,经验,学历    
    city_experience_education=soup.select('div p')
    if len(city_experience_education)<=2:
        city='unknown'
        experience='unknown'
        education='unknown'
    else:
        city=city_experience_education[2].contents[0][3:]
        experience=city_experience_education[2].contents[2][3:]
        education=city_experience_education[2].contents[4][3:]
    #融资进展,公司规模,职位性质
    finance_scale_trade=soup.select('div p')
    if len( finance_scale_trade)<=3:
        finance='unknown'
        scale='unknown'
        trade='unknown'
    else:
        finance_scale_trade=finance_scale_trade[3].contents
        if len(finance_scale_trade)<5:
            finance='unknown'
            scale=finance_scale_trade[0]
            trade=finance_scale_trade[2].string
        else:
            finance=finance_scale_trade[0]
            scale=finance_scale_trade[2]
            trade=finance_scale_trade[4].string
    #职位名称
    job_title=soup.find('div','job-tags')
    if job_title is None:
        job_title='no title'
    else:
        job_title=job_title.span.string

    #公司名称
    company=soup.find_all('div','name')
    if len(company)<=2:
        company="unknown"
    else:
        company=company[2].string 
    #注册资金
    registered_capital=soup.find('div','level-list')
    if registered_capital is None:
        registered_capital=0
    else:
        registered_capital=registered_capital.find_all('li')
        if registered_capital is None:
            registered_capital=0
        else:
            registered_capital=registered_capital[1].get_text()[5:]
                
    #公司地址       
    address=soup.find('div','location-address')
    if address is None:
        address='no address'
    else:
        address=address.string
    #公司描述   
    company_describe=soup.find_all('div','text')
    if len(company_describe)>=3:
        company_describe=company_describe[2].text
    elif 1<len(company_describe)<=2:
        company_describe=company_describe[1].text
    else:
        company_describe='no describe'
    #职位要求   
    job_responsibility=soup.find('div','text')
    if job_responsibility is None:
        job_responsibility= 'no responsibility'
    else:
        job_responsibility=job_responsibility.text
    #需要特别注意的是在填充df_only时必须加上ignore_index=Ture,否则后面爬取的时候如果碰到刷新验证码会无法进行下去。
    df_only=df_only.append(pd.DataFrame({'pub_date':[pub_date],'salary':[salary],'city':[city],'experience':[experience],'education':[education],'finance':[finance],'scale':[scale],'trade':[trade],'job_title':[job_title],'company':[company],'registered_capital':[registered_capital],'address':[address],'company_describe':[company_describe],'job_responsibility':[job_responsibility]}),ignore_index=True)
    return df_only

通过url库爬取对应招聘页面信息并提取汇总到一起。因为爬取过程中经常会有刷新验证码造成爬取中断,为了从中断的地方重新开始,设置了一个很low的办法,就是首次正常运行第一步的程序,后面中断后重新运行第二步的程序,注意后面一直是重新运行第二步程序,直到爬取结束。最好的办法当然还是使用sleep方法。

#第一步!!!通过引入m来进行循环爬取
SZ_test=pd.DataFrame(columns=[['pub_date','salary','city','experience','education','finance','scale','trade','job_title','company','registered_capital','address','company_describe','job_responsibility']])
m=0

#第二步
#df=pd.read_csv('df_SZ_urls.csv')
#SZ_test=pd.read_csv('SZ_test.csv',index_col=0) #这里必须加上index_col=0,否则pandas会自动生成很多unamed的索引列,造成爬取无法继续下去。
#if len(SZ_test['city'])==0:
#    m=0
#else:
#    m=len(SZ_test['city'])-1  #这里减去1是为了防止爬取信息遗漏。

for k in df['urls'][m:len(df['urls'])]:
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
              'cookie':'_uab_collina=154410324775207731129147; lastCity=101010100; t=vPAu9pVZjhJw4CEs; wt=vPAu9pVZjhJw4CEs; sid=sem_pz_bdpc_dasou_title; JSESSIONID=""; __c=1544875350; __g=sem_pz_bdpc_dasou_title; __l=l=%2Fwww.zhipin.com%2F%3Fsid%3Dsem_pz_bdpc_dasou_title&r=https%3A%2F%2Fwww.baidu.com%2Fs%3Fwd%3Dboss%25E7%259B%25B4%25E8%2581%2598%26rsv_spt%3D1%26rsv_iqid%3D0xa2eaa2390016f56e%26issp%3D1%26f%3D8%26rsv_bp%3D0%26rsv_idx%3D2%26ie%3Dutf-8%26tn%3D90066238_hao_pg%26rsv_enter%3D1%26rsv_t%3D161dvC%252FaDWi%252Fh%252B1%252F7Li2Ji8FrSldZ4PCYkrVrBo1BpjThzGjwIzfr1jHvtvsMEXU2CM3GntQ&g=%2Fwww.zhipin.com%2F%3Fsid%3Dsem_pz_bdpc_dasou_title; Hm_lvt_194df3105ad7148dcf2b98a91b5e727a=1544103248,1544688540,1544757018,1544875351; __a=10641235.1544103244.1544757018.1544875350.142.5.3.3; Hm_lpvt_194df3105ad7148dcf2b98a91b5e727a=1544875356'}
    proxies={'http': 'http://210.22.176.146:32153','http': 'http://211.152.33.24:48749','http': 'http://175.165.128.214:1133','http': 'http://36.110.14.66:50519'}
    response=requests.get(k,headers=headers,proxies=proxies)
    print "you have got "+str(k)+" working" 
    #time.sleep(30)
    html=response.content
    df_1=get_job_detail(html)
    #我这里是广州和深圳的分开爬取,生成两个csv文件,后面再合并到一起
    SZ_test=SZ_test.append(df_1,ignore_index=True)
    SZ_test.to_csv('SZ_test.csv')
    
    print '已经完成'
       

数据清理

#读取所有文件,生成一个新的合并的df。
df_GZ=pd.read_csv('GZ_test.csv',index_col=0)
df_SZ=pd.read_csv('SZ_test.csv',index_col=0)
df=pd.concat([df_GZ,df_SZ],ignore_index=False)
#重设索引
df.reset_index(drop=True,inplace=True)
df
#复制数据,去掉重复项。
df_copy=df.copy()
df_copy.duplicated().value_counts()
df_copy.drop_duplicates(inplace=True)
df_copy['city'].value_counts()
深圳         526
广州         364
unknown      1
Name: city, dtype: int64
#公司介绍和职位介绍主要是自己想了解一下,对于后面数据可视化没什么意义,先删除。
df_copy=df_copy[['address','city','company','education','experience','finance','job_title','pub_date','registered_capital','salary','scale','trade']]
df_copy.drop(266,inplace=True,axis=0)
df_copy[df_copy['city']=='unknown']
df_copy.reset_index(drop=True,inplace=True)
df_copy.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 890 entries, 0 to 889
Data columns (total 12 columns):
address               890 non-null object
city                  890 non-null object
company               890 non-null object
education             890 non-null object
experience            890 non-null object
finance               890 non-null object
job_title             890 non-null object
pub_date              890 non-null object
registered_capital    868 non-null object
salary                890 non-null object
scale                 890 non-null object
trade                 890 non-null object
dtypes: object(12)
memory usage: 83.5+ KB

存在的问题:

1.为便于统计,address需要更改为xx区;类似于“中国储能大厦、深圳万利达科技大厦、深圳创意园”这样的需要明确具体所属区;
2.education、experience栏有些与后面salary的关系不可信;
3.finance列出现63个unknown值;
4.registered_capital列既有人民币又有美元、港元,有的小数点后有四位,有些注册资金为空白;有些注册资金为0(其中一个为str型);
5.salary为薪水范围,计划拆分为最低和最高薪水,有一行salary不合规范,含很多空格;

数据清洗

1.address需要更改为xx区;类似于“中国储能大厦、深圳万利达科技大厦、深圳创意园”这样的需要明确具体所属区;采用replace方法。
df_copy.replace({'中国储能大厦':'南山区','深圳万利达科技大厦':'南山区','广州高普路华天时代大厦':'天河区',
                  '南山科技园':'南山区','深圳平安科技南山职场':'南山区','深圳深圳文化创意园东方明珠科技大厦6楼':'福田区',
                '广州天河棠下荷光路盛达商务园b栋6楼':'天河区','深圳超多维科技大厦12楼':'南山区',
                 '深圳科兴科学园A4栋18号楼':'南山区'},inplace=True)

接下来将所有的地址全部替换为区,因为对中文文本正则表达式不是很熟悉,这里先构建一个各区的词列表,利用re模块的search方法匹配,匹配成功就说明该公司在xx区,未匹配成功的引入reexamin,再一一对应修改。

str_pattern='天河|黄埔|荔湾|番禺|白云|从化|海珠|越秀|花都|南山|福田|龙岗|龙华新|宝安|龙华|罗湖|盐田'
pattern=re.compile(str_pattern)
l=[]
j=0
for k in df_copy['address']:
    m=pattern.search(k)
    if m:
        d=k[m.start():m.end()]
        l.append(d)
    else:
        l.append('reexamin'+str(j))
        j+=1
address_new=pd.Series(l)    
len(address_new)
890
df_copy['address_new']=address_new
df_copy[df_copy['address_new']=='reexamin0|reexamin1|reexamin2'] 
df_copy.replace({'reexamin0':'天河','reexamin1':'南山','reexamin2':'龙华新'},inplace=True)
#df_copy['address_new'].value_counts()
3.finance列出现63个unknown值;
#df_copy[df_copy['finance']=='unknown']['company'].value_counts()

随机选取一些公司查看,都没有融资相关的信息,这里把他们单独归为一类。

4.registered_capital列既有人民币又有美元、港元,有的小数点后有四位,22个注册资金为空白;9个注册资金为0(其中一个为str型);
df_copy[df_copy['registered_capital']=='0']
#公司名未知,无法查找,且salary一栏恰好是问题5需要清理的对象,直接删除该行
df_copy.drop(755,inplace=True,axis=0)

#重设索引,方便下一步处理。
df_copy.reset_index(drop=True,inplace=True)

针对港元和美元,采取的思路是首先利用re模块search registered_capital栏是否有美元或港元,然后利用isinstance方法判断是否可以提取相关的信息,并提取注册资金数字(只提取整数部分),如果有美元或港元就乘以对应汇率,这样就全部将注册资金转换为人民币了;如果该栏是空值,就输入unknown,再手动查找更改。

str_pattern='港元|美元'
pattern=re.compile(str_pattern)
l=[]
#j=0
for k in df_copy['registered_capital']:
    if isinstance(k,str):
        m=pattern.search(k)
        n=int(re.findall(r'\d+',k,re.M)[0])
        if m:
            d=k[m.start():m.end()]
            if d=='美元':
                s=n*6.8
            else:
                s=n/1.16
            l.append(s)
        else:
            l.append(n)
            #j+=1
    else:
        l.append('unknown')
reg_new=pd.Series(l)    
#print l
len(reg_new)


889
df_copy['reg_new']=reg_new
#df_copy[df_copy['reg_new']=='unknown']
#随机查了几个公司,多数没有注册资金,对后面的分析没什么影响,不填补
5.salary为薪水范围,计划拆分为最低和最高薪水,有一行salary不合规范,含很多空格;
#前面已经删了了salary含很多空格的行;为便于处理,将salary按照最低工资和最高工资拆分为两列
df_copy['salary_min'],df_copy['salary_max']=df_copy['salary'].str.split('-',n=1).str
df_copy['salary_min']=df_copy['salary_min'].str[:-1]
df_copy['salary_max']=df_copy['salary_max'].str[:-1]
#df_copy['salary_mean']=(df_copy['salary_min']+df_copy['salary_min'])*0.5
#删除不需要的列,另存为csv文件,大功告成!
df_copy.drop(['address','registered_capital'],axis=1,inplace=True)
df_copy.to_csv('df_copy.csv')

数据可视化分析

import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
from pylab import * 
from collections import Counter
df_copy=pd.read_csv('df_copy.csv')
#设置一下中文字体,否则后面matplotlib不能显示
mpl.rcParams['font.sans-serif'] = ['SimHei']

1.广州跟深圳的工作机会哪个更多

这里采用频率直方图,统计广、深各个区出现的次数,并按照广州和深圳分别画图,便于统计。由于是不同x坐标轴,所以分开画图。


#设置x轴字体,不然后面会出现无法显示x轴汉字的问题
mpl.rcParams['font.sans-serif'] = ['SimHei'] 
#x轴为区名,y轴为各区出现的次数也即招聘次数的统计。
#广州各区的工作机会统计,注意x坐标是汉字,需要先转化为数字画图,再利用xticks还原回来才能正确显示。
x1=['天河','黄埔','荔湾','番禺','白云','从化','海珠','越秀','花都']
x11=range(len(x1))
y1=[]
for i in x1:
    y=df_copy[df_copy['address_new']==i]['address_new'].count()
    y1.append(y)
#深圳各区的工作机会统计
x2=['南山','福田','龙岗','龙华新','宝安','龙华','罗湖','盐田']
x21=range(len(x2))
y2=[]
for i in x2:
    y=df_copy[df_copy['address_new']==i]['address_new'].count()
    y2.append(y)
#绘制频率直方图
plt.bar(x11,y1,color='blue',align='center')
plt.xticks(x11,x1)
plt.title('广州')
plt.show()
plt.bar(x21,y2,color='blue',align='center')
plt.xticks(x21,x2)
plt.title('深圳')
plt.show()
print y1,y2

爬取BOSS直聘信息并进行清理和可视化分析(python小白)

爬取BOSS直聘信息并进行清理和可视化分析(python小白)

[175, 25, 20, 38, 22, 1, 52, 28, 3] [306, 98, 44, 2, 36, 21, 16, 2]

深圳的工作机会主要集中在南山(306)、福田(98)、宝安(36)和龙岗(44),广州的工作机会主要集中在天河(175)、海珠(52)、番禺(38)、黄埔(25)和越秀(28)。深圳的工作机会明显比广州多很多,特别是南山区有腾讯、oppo、vivo、百度、环球易购等大型企业。

2.广深哪些公司招聘最多?

# _*_ coding=utf-8 _*_
#引入Counter函数统计各个公司出现的次数,并生成对应的列表x和y
s=Counter(df_copy['company']).most_common(25)
x=[]
y=[]
for i,j in s:
    x.append(i)
    y.append(j)
    print i,j
x1=range(len(x))
#画图,注意这里需要设置rotation=90,否则下面公司名会重叠
fig=plt.figure(figsize=(12,8),dpi=120)
plt.bar(x1,y,color='red',alpha=0.5)
plt.xticks(x1,x,rotation=90)
plt.show()
腾讯科技(深圳)有限公司 69
华为技术有限公司 16
百度在线网络技术(北京)有限公司 15
OPPO广东移动通信有限公司 14
维沃移动通信有限公司 14
深圳市环球易购电子商务有限公司 12
平安科技(深圳)有限公司 11
软通动力信息技术(集团)有限公司 11
深圳依时货拉拉科技有限公司 10
深圳市珍爱网信息技术有限公司 7
北京字节跳动科技有限公司 6
上海橙信网络科技有限公司 6
万惠投资管理有限公司 6
广州华多网络科技有限公司 6
广州视源电子科技股份有限公司 6
广州博冠信息科技有限公司 6
北京尚德在线教育科技有限公司 5
深圳投哪金融服务有限公司 5
广州尊游软件科技有限公司 5
广东健客医药有限公司 5
广州时代数据服务有限公司 4
名创优品股份有限公司 4
深圳市升学文化传播有限公司 4
广州市巴图鲁信息科技有限公司 4
深圳库尚信息技术有限公司 4

爬取BOSS直聘信息并进行清理和可视化分析(python小白)_52_1.png)在这里插入图片描述

招聘最多的还是腾讯、华为、百度、oppo、vivo、环球易购、平安、软通动力这些大型科技公司,小公司的招聘比较少。

3.两个城市招聘岗位薪水的分布情况?

#首先定义count函数,统计各值出现的频率
def count(L):
    s=Counter(L)
    x=list(s.keys())
    y=list(s.values())
    return x,y
#绘制频率直方图
x1,y1=count(df_copy[df_copy['city']=='广州']['salary_min'])
x2,y2=count(df_copy[df_copy['city']=='深圳']['salary_min'])
fig=plt.figure(figsize=(8,6),dpi=120)
l1=plt.plot(x1,y1,color='blue',linewidth=0.6,label='广州')
l2=plt.plot(x2,y2,color='red',linestyle='-',linewidth=0.6,label='深圳')
plt.axis((0,70,0,150))
plt.xlabel('最低薪水(k)')
plt.ylabel('统计值')
plt.xticks((0,5,10,15,20,25,30,35,40,50,60,70))
plt.yticks((0,25,50,75,100,125,150))
plt.legend(loc='best')
fig.tight_layout(h_pad=2.0)
plt.show()

爬取BOSS直聘信息并进行清理和可视化分析(python小白)
爬取BOSS直聘信息并进行清理和可视化分析(python小白)

深圳的最低工资普遍高于广州,大部分在10k以上,主要为15k、20k、25k和30k,而广州的最低工资主要为6k、8k、10k、15k、20k,20k以上就很少出现。广州的工资比深圳要低很多啊!

4.薪水与学历、工作经验、融资情况和公司规模的关系

#首先依据education、experience、finance、scale将最低工资栏拆分,再重新合并成数个list,以便后面将箱线图画在一起。
a1=df_copy[df_copy['education']=='中专/技校']['salary_min']
a2=df_copy[df_copy['education']=='高中']['salary_min']
a3=df_copy[df_copy['education']=='大专']['salary_min']
a4=df_copy[df_copy['education']=='本科']['salary_min']
a5=df_copy[df_copy['education']=='硕士']['salary_min']
a6=df_copy[df_copy['education']=='博士']['salary_min']
a7=df_copy[df_copy['education']=='不限']['salary_min']
a=[a1,a2,a3,a4,a5,a6,a7]

b1=df_copy[df_copy['experience']=='应届生']['salary_min']
b2=df_copy[df_copy['experience']=='1年以内']['salary_min']
b3=df_copy[df_copy['experience']=='1-3年']['salary_min']
b4=df_copy[df_copy['experience']=='3-5年']['salary_min']
b5=df_copy[df_copy['experience']=='5-10年']['salary_min']
b6=df_copy[df_copy['experience']=='10年以上']['salary_min']
b7=df_copy[df_copy['experience']=='经验不限']['salary_min']
b=[b1,b2,b3,b4,b5,b6,b7]

c1=df_copy[df_copy['finance']=='未融资']['salary_min']
c2=df_copy[df_copy['finance']=='天使轮']['salary_min']
c3=df_copy[df_copy['finance']=='A轮']['salary_min']
c4=df_copy[df_copy['finance']=='B轮']['salary_min']
c5=df_copy[df_copy['finance']=='C轮']['salary_min']
c6=df_copy[df_copy['finance']=='D轮及以上']['salary_min']
c7=df_copy[df_copy['finance']=='已上市']['salary_min']
c8=df_copy[df_copy['finance']=='不需要融资']['salary_min']
c9=df_copy[df_copy['finance']=='unknown']['salary_min']
c=[c1,c2,c3,c4,c5,c6,c7,c8,c9]

d1=df_copy[df_copy['scale']=='0-20人']['salary_min']
d2=df_copy[df_copy['scale']=='20-99人']['salary_min']
d3=df_copy[df_copy['scale']=='100-499人']['salary_min']
d4=df_copy[df_copy['scale']=='500-999人']['salary_min']
d5=df_copy[df_copy['scale']=='1000-9999人']['salary_min']
d6=df_copy[df_copy['scale']=='10000人以上']['salary_min']
d=[d1,d2,d3,d4,d5,d6]
#设置4个画图模板
fig,axes=plt.subplots(nrows=2,ncols=2,figsize=(8,6),dpi=120)
#设置图间距
fig.tight_layout(h_pad=2.0)
#设置图标题
axes[0,0].set(title='最低工资-学历')
axes[0,1].set(title='最低工资-经验')
axes[1,0].set(title='最低工资-融资情况')
axes[1,1].set(title='最低工资-公司规模')
#画图,设置x标签
axes[0,0].boxplot(a)
axes[0,0].set_xticklabels(['中专/技校','高中','大专','本科','硕士','博士','不限'])
#plt.xticks(rotation=90)

axes[0,1].boxplot(b)
axes[0,1].set_xticklabels(['应届生','<1年','1-3年','3-5年','5-10年','>10年以上','不限'])

axes[1,0].boxplot(c)
axes[1,0].set_xticklabels(['未融资','天使轮','A轮','B轮','C轮','D及以上','已上市','不需要','unknown'])

axes[1,1].boxplot(d)
axes[1,1].set_xticklabels(['0-20人','20-99人','100-499人','500-999人','1000-9999人','10000人以上'])

plt.show()

爬取BOSS直聘信息并进行清理和可视化分析(python小白)

学历越高,最低工资越高,博士的最低工资基本都有20k以上;工作经验越丰富,最低工资越高,5年经验的最低工资基本都有15-25k;未融资及天使轮给的最低工资都比较低,应该是因为缺钱的缘故,已上市企业给的最低工资相对较高;10000人以上的大公司,给的薪水相对比较高。

结论:看来广州的工作机会要不就是要求比较高,要不就是待遇比较低,还是去深圳比较靠谱。要转行真的得穷三年了,继续努力吧!

      **最后,再次对BOSS直聘表示歉意!**