640?wx_fmt=gif

640?wx_fmt=jpeg

作者 | lowelong

责编 | 郭芮

人工智能的快速发展以及大数据时代的来临,使得 Python 语言不仅在人工智能领域大放异彩,在数据处理上也有着得天独厚的优势,在 Web 开发、网络编程、自动化运维、游戏开发、金融等领域扮演着越来越重要的角色。

百度搜索指数表明,2017 年 7 月份开始,Python 的搜索指数已经超过了 Java。Python 语言的热门由此可见一斑。

640?wx_fmt=png

本文中,笔者决定在拉勾网(一家为互联网从业者提供工作机会的招聘网站)上爬取相关 Python 职位信息,对职位数据(薪酬、学历要求、区域信息、工作经验等)进行图形可视化分析。


640?wx_fmt=png

前期准备


1、网页分析

打开拉勾网网站搜索 Python,可以发现每页有 15 条职位信息数据,最多有 30 页数据可以查看,共 450 条职位信息。我们需要获取的信息包括:职位、公司名称、薪酬范围、所在区域、学历要求、工作经验、公司融资情况、公司人数、工作要求描述。

640?wx_fmt=png 

2、请求数据分析

通过 Chrome 浏览器访问拉勾网,打开 Console 控制台可以发现,当进行翻页的时候,是通过 xhr 的请求方式请求的。通过观察,我们可以发现,URL 里面的 city 代表的是城市,post 参数 kd 代表的是搜索的职位,pn 是 page number,表示页码。

640?wx_fmt=png

3、职位列表JSON返回数据的分析获取

640?wx_fmt=png

通过 JSON 库进行数据的解析,获取相关信息。需要注意的是,我们需要记得保留 positionID,用于下一步获取工作描述信息。

def get_lagou(page,city,kd):
    url = "https://www.lagou.com/jobs/positionAjax.json"
    querystring = {"px": "new", "city": city, "needAddtionalResult": "false", "isSchoolJob": "0"}
    payload = "first=false&pn=" + str(page) + "&kd="+str(kd)
    cookie = "JSESSIONID=" + get_uuid() + ";"\
        "user_trace_token=" + get_uuid() + "; LGUID=" + get_uuid() + "; index_location_city=%E6%88%90%E9%83%BD; " \
        "SEARCH_ID=" + get_uuid() + '; _gid=GA1.2.717841549.1514043316; ' \
        '_ga=GA1.2.952298646.1514043316; ' \
        'LGSID=' + get_uuid() + "; " \
        "LGRID=" + get_uuid() + "; "
    headers = {'cookie': cookie,'origin': "https://www.lagou.com",'x-anit-forge-code': "0",'accept-encoding': "gzip, deflate, br",'accept-language': "zh-CN,zh;q=0.8,en;q=0.6",'user-agent': "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",'content-type': "application/x-www-form-urlencoded; charset=UTF-8",'accept': "application/json, text/javascript, */*; q=0.01",'referer': "https://www.lagou.com/jobs/list_Java?px=new&city=%E6%88%90%E9%83%BD",'x-requested-with': "XMLHttpRequest",'connection': "keep-alive",'x-anit-forge-token': "None",'cache-control': "no-cache",'postman-token': "91beb456-8dd9-0390-a3a5-64ff3936fa63"}
    response = requests.request("POST", url, data=payload.encode('utf-8'), headers=headers, params=querystring)
    # print(response.text)
    hjson = json.loads(response.text)
    for i in range(15):
        positionName=hjson['content']['positionResult']['result'][i]['positionName']
        companyId = hjson['content']['positionResult']['result'][i]['companyId']
        positionId= hjson['content']['positionResult']['result'][i]['positionId']
        salary = hjson['content']['positionResult']['result'][i]['salary']
        city= hjson['content']['positionResult']['result'][i]['city']
        district= hjson['content']['positionResult']['result'][i]['district']
        companyShortName= hjson['content']['positionResult']['result'][i]['companyShortName']
        education= hjson['content']['positionResult']['result'][i]['education']
        workYear= hjson['content']['positionResult']['result'][i]['workYear']
        industryField= hjson['content']['positionResult']['result'][i]['industryField']
        financeStage= hjson['content']['positionResult']['result'][i]['financeStage']
        companySize= hjson['content']['positionResult']['result'][i]['companySize']
        job_desc = get_job_desc(positionId)
        positionName_list.append(positionName)
        salary_list.append(salary)
        city_list.append(city)
        district_list.append(district)
        companyShortName_list.append(companyShortName)
        education_list.append(education)
        workYear_list.append(workYear)
        industryField_list.append(industryField)
        financeStage_list.append(financeStage)
        companySize_list.append(companySize)
        #job_desc_list.append(job_desc)

4、获取工作信息描述

通过观察发现,打开具体职位的详细页面时,URL 里面的数值(例如下图的 URL 里面的 4789029)就是职位的 positionID,该 positionID 可以通过上一步的职位列表 JSON 返回数据获取。

640?wx_fmt=png

通过 requests 请求页面信息,再通过 xpath 获取工作描述信息。

def get_job_desc(id):
    url = "https://www.lagou.com/jobs/"+str(id)+".html"
    cookie = "JSESSIONID=" + get_uuid() + ";"\
        "user_trace_token=" + get_uuid() + "; LGUID=" + get_uuid() + "; index_location_city=%E6%88%90%E9%83%BD; " \
        "SEARCH_ID=" + get_uuid() + '; _gid=GA1.2.717841549.1514043316; ' \
        '_ga=GA1.2.952298646.1514043316; ' \
        'LGSID=' + get_uuid() + "; " \
        "LGRID=" + get_uuid() + "; "
    headers = {'cookie': cookie,'origin'"https://www.lagou.com",'x-anit-forge-code'"0",'accept-encoding'"gzip, deflate, br",'accept-language'"zh-CN,zh;q=0.8,en;q=0.6",'user-agent'"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",'content-type'"application/x-www-form-urlencoded; charset=UTF-8",'accept'"application/json, text/javascript, */*; q=0.01",'referer'"https://www.lagou.com/jobs/list_Java?px=new&city=%E6%88%90%E9%83%BD",'x-requested-with'"XMLHttpRequest",'connection'"keep-alive",'x-anit-forge-token'"None",'cache-control'"no-cache",'postman-token'"91beb456-8dd9-0390-a3a5-64ff3936fa63"}
    response = requests.request("GET", url, headers=headers)
    x = etree.HTML(response.text)
    data = x.xpath('//*[@id="job_detail"]/dd[2]/div/*/text()')
    return ''.join(data)


640?wx_fmt=png

数据获取 —— 爬虫


1、设置 cookies 和 headers

如果不设置相关信息,会不允许爬取,返回提示:“您操作太频繁,请稍后再访问”。所以,我们需要设置 headers 和 cookies 信息。

def get_lagou(page,city,kd):
    url = "https://www.lagou.com/jobs/positionAjax.json"
    querystring = {"px""new""city": city, "needAddtionalResult""false""isSchoolJob""0"}
    payload = "first=false&pn=" + str(page) + "&kd="+str(kd)
    cookie = "JSESSIONID=" + get_uuid() + ";"\
        "user_trace_token=" + get_uuid() + "; LGUID=" + get_uuid() + "; index_location_city=%E6%88%90%E9%83%BD; " \
        "SEARCH_ID=" + get_uuid() + '; _gid=GA1.2.717841549.1514043316; ' \
        '_ga=GA1.2.952298646.1514043316; ' \
        'LGSID=' + get_uuid() + "; " \
        "LGRID=" + get_uuid() + "; "
    headers = {'cookie': cookie,'origin'"https://www.lagou.com",'x-anit-forge-code'"0",'accept-encoding'"gzip, deflate, br",'accept-language'"zh-CN,zh;q=0.8,en;q=0.6",'user-agent'"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36",'content-type'"application/x-www-form-urlencoded; charset=UTF-8",'accept'"application/json, text/javascript, */*; q=0.01",'referer'"https://www.lagou.com/jobs/list_Java?px=new&city=%E6%88%90%E9%83%BD",'x-requested-with'"XMLHttpRequest",'connection'"keep-alive",'x-anit-forge-token'"None",'cache-control'"no-cache",'postman-token'"91beb456-8dd9-0390-a3a5-64ff3936fa63"}

2、延时设置和分页爬取

避免爬取速度过快被封,设置延时时间为 3-5 秒。通过 for 循环进行分页数据的爬取。

def main(pages,city,job):
    for n in range(1, pages+1):
        get_lagou(n,city,job)
        time.sleep(round(random.uniform(35), 2))
    write_to_csv(city,job)


640?wx_fmt=png

数据存储与处理


1、CSV 数据存储

由于数据量不大,最多 450 条数据,采用 CSV 的存储方式。

2、数据处理

  • 薪酬数据处理

后续统计月薪的占比,由于薪酬范围是可以自定义范围,没有一个统一的标准。例如薪酬可以是 10k-20k、5k-8k、11k-18k、10k-16k 等情况,后续不利于薪酬范围的可视化,所以将薪酬归纳分类到这几种:2k 以下、2k-5k、5k-10k、10k-15k、15k-25k、25k-50k、50k 以上。

假如薪酬为 10k-20k, 则认为在 10k-15k、15k-25k 这两种归类里面都包含。采用正则表达式进行归类汇总:

def salary_categorize(salarys):
    dict = {'2k以下': 0, '2k-5k': 0, '5k-10k': 0,'10k-15k':0,'15k-25k':0,'25k-50k':0,'50k以上':0}
    for salary in salarys:
        if re.match('^[0-1]k-*|.*-[0-1]k$',salary)!=None:
            dict['2k以下'] += 1
        if re.match('^[2-4]k-*|.*-[2-4]k$',salary)!=None:
            dict['2k-5k'] +=  1
        if re.match('^[5-9]k-*|.*-[5-9]k$', salary)!=None:
            dict['5k-10k'] += 1
        if re.match('^1[0-4]k-*|.*-1[0-4]k$', salary)!=None:
            dict['10k-15k'] += 1
        if re.match('^1[5-9]k-*|^2[0-4]k-*|.*-1[5-9]k$|.*-2[0-4]k$', salary)!=None:
            dict['15k-25k'] += 1
        if re.match('^2[5-9]k-*|^[3-4][0-9]k-*|.*-2[5-9]k$|.*-[3-4][0-9]k$', salary)!=None:
            dict['25k-50k'] += 1
        if re.match('^[5-9][0-9]k-*|.*-[5-9][0-9]k$|^\d{3,}k-*|.*-\d{3,}k$', salary)!=None:
            dict['50k以上'] += 1
    return dict
  • 行业信息处理

公司所属行业可以是多个,一般以逗号分隔,但存在部分是以顿号和空格分隔的情况,还有可能存在没有写明相关行业的情况。对此,通过 Python 的 re 库可以处理多个分隔符分隔的数据,所属行业为空,则跳过。

640?wx_fmt=png

def industryField_counts(csv_file):
    industryFields = []
    d = pd.read_csv(csv_file, engine='python', encoding='utf-8')
    info = d['industryField']
    for i in range(len(info)):
        try:
             data = re.split('[,、 ]',info[i])
        except:
            continue
        for j in range(len(data)):
            industryFields.append(data[j])
    counts = Counter(industryFields)
    return counts


640?wx_fmt=png

数据可视化与解读

1、公司相关情况分析

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

从行业情况和公司规模来看,移动互联网占有 40% 的需求,数据服务+大数据+人工智能占了 10% 的比例。Python 非常强大,适合的领域包括 Web 开发、网络编程、爬虫、云计算、人工智能、自动化运维等,所以不管公司规模是大还是小,融资情况如何,都普遍需要 Python 相关的职位的人才。

2、城市需求分析

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

从上图分析,可以发现,需求量主要集中在中国三大经济圈:京津冀,长三角,珠三角。主要分布在北京(40%)、上海(16%)、深圳(15%)、广州(6%)、成都(6%)和杭州(6%)这 6 个城市。而北京的互联网创业气氛冠绝中国,注册在北京的互联网公司远远高于在其他城市的公司,需求量也是最大的。

3、薪酬与工作经验分析

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

从工作经验的要求来看,大部分集中在 3-5 年和 1-3 年这两个区间,至于工作经验和薪酬之间的相关性,观察发现,1-3 年工作经验的薪酬普遍在 15-25K,符合正态分布的规律,3-5 年工作经验的薪酬普遍在 15k-25k 和 25k-50k 这两个区间,以 15k-25k 这个区间的居多。达到 5-10 年工作经验的,薪酬在 25k-50K 这个区间的居多。

4、学历要求和工作经验分析

640?wx_fmt=png

640?wx_fmt=png

从学历要求来看,大部分都要求至少本科以上,这部分占了约 80% 的比例。所以不要在相信读书无用论这种观点了,学历至少是工作的敲门砖。

工作经验上,普遍要求是 1-5 年,这部分占了 84% 的比例。1年以下和经验不限的,占了约 9%,5-10 年的占了约 7% 的比例。


640?wx_fmt=png

总结

TIOBE 8 月编程语言指数排行榜已经公布了,排名前三的虽然依旧是 Java、C、C++。但 Python 非常接近 TIOBE 索引的前 3 位。Python 这样的上涨趋势,同样可以在 TIOBE 索引排行中体现,互联网业界也开始普遍采用  Python。Python 编程语言最初是 Perl 的继承者,用于编写构建脚本和各种粘合软件。但后来逐渐进入其他领域。如今,在大型嵌入式系统中运行 Python 是很常见的。因此,Python 完全有可能进入前三名,甚至在未来取代 Java 成为新的第一名。

640?wx_fmt=png

从目前 Python 的就业前景来看,总结如下:

  • Python 就业情况乐观,从 TIOBE 8 月编程语言指数排行榜以及百度指数的搜索数来看,Python 的受欢迎程度越来越高。

  • 在中国地区,Python 相关职位的需求量,依然集中在三大经济圈,特别是在北京、上海、深圳这几个城市。从行业需求来看,主要集中在移动互联网、数据服务、大数据分析等行业。

  • 从拉勾网的数据分析可知,大部分 Python 的相关职位都要求在本科和本科以上,工作经验要求在 1-5 年的居多。因为 Python 在大数据和人工智能领域的爆发性发展, 导致 Python 方向岗位的薪水在水涨船高,从数据分析来看,月薪在 10K-50K 不等。

注,文中源码已上传至 GitHub,地址:https://github.com/liaolongfei/lagou/

作者简介:lowelong,国内某互联网公司测试工程师,目前学习 Python 中。

声明:本文为 CSDN 「技术头条」栏目独家投稿文章。如需转载,请微信联系  God-I-love-u。

一生只为寻欢笑的 Linux 之父 Linus Torvalds 说过一句至理名言 —— 「Talk is cheap. Show me the code」,这正是 CSDN 「技术头条」栏目所秉持的初衷和愿景。针对开发者们所面临的技术痛点,面向所有开发者,一起用代码见真章。如果你有优质的技术文章,从新技术的探索到业务落地实践,均欢迎投稿,一起 Show code!


征稿啦

CSDN 公众号秉持着「与千万技术人共成长」理念,不仅以「极客头条」、「畅言」栏目在第一时间以技术人的独特视角描述技术人关心的行业焦点事件,更有「技术头条」专栏,深度解读行业内的热门技术与场景应用,让所有的开发者紧跟技术潮流,保持警醒的技术嗅觉,对行业趋势、技术有更为全面的认知。

如果你有优质的文章,或是行业热点事件、技术趋势的真知灼见,或是深度的应用实践、场景方案等的新见解,欢迎联系 CSDN 投稿,联系方式:微信(guorui_1118,请备注投稿+姓名+公司职位),邮箱(guorui@csdn.net)。


————— 推荐阅读 —————

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png


640?wx_fmt=gif640?wx_fmt=gif

Logo

20年前,《新程序员》创刊时,我们的心愿是全面关注程序员成长,中国将拥有新一代世界级的程序员。20年后的今天,我们有了新的使命:助力中国IT技术人成长,成就一亿技术人!

更多推荐