小猪的Python学习之旅 —— 16.再尝Python数据分析:采集拉勾网数据分析Android就业行情...
一句话概括本文:
爬取拉钩Android职位相关数据,利用numpy,pandas和matplotlib对招人公司
情况和招聘要求进行数据分析。
引言:
在写完上一篇《浅尝Python数据分析:分析2018政府工作报告中的高频词》,
一直都处于一种亢奋的状态,满脑子都想着数据分析,膜一下当然很开心,
更重要的是感受到了Python数据分析的好玩,迫不及待地想写个新的东西玩玩,
这不,给我翻到一个好玩的东西:《Python拉钩数据采集与可视化》
就是采集拉钩上关于Python岗位的相关信息,然后做数据分析,通过
图表的形式把分析结果展示给别人看;在我潜水的很多个Android群里
普遍有这样的反馈:尽管是现在是招聘的金三银四,但是Android的工作
真不好找?原因是Android岗位稀缺?要求过高?薪资问题?又或者其他
因素,我决定通过Python来采集相关数据,利用numpy,pandas,matplotlib
数据分析基础三件胡乱分析一波:
试图从分析结果中获取点什么有用的信息,以便了解方便自己更好的了解
市场行情,不逼逼,开始本节内容~
1.知道下数据分析三件套
在开始之前你可能需要大概了解下这三个库:numpy,pandas和matplotlib,
数据分析必备三件套,考虑如果要把文档吃透需要不少时间,还有文章篇幅
等原因,这里不慢慢去啃了,后续可能会写单独的教学章节,本节给出相关
的参考链接,有兴趣可先行自己研究~
书:《Python for Data Analysis, 2nd Edition》
PDF下载:Python for Data Analysis, 2nd Edition.pdf
中文翻译:利用Python进行数据分析·第2版
numpy库:
科学计算基础包,为Python提供快速的数组处理能力,
作为在算法和库之间传递数据的容器。
NumPy是在在一个连续的内存块中存储数据,独立于其他Python内置对象。
NumPy的C语言编写的算法库可以操作内存,而不必进行类型检查或其它
前期工作。比起Python的内置序列,NumPy数组使用的内存更少。
学习链接:
pandas库:
提供了快速便捷处理结构化数据的大量数据结构和函数,有两种数据
常见的数据结构,分别为:Series
(一维的标签化数组对象)和
DataFrame
(面向列的二维表结构)
学习链接:
- 十分钟上手pandas:pandas.pydata.org/pandas-docs…
- 更多内容:pandas.pydata.org/pandas-docs…
matplotlib库
用于绘制图表和其它二维数据可视化的Python库
学习链接:
2.数据爬取
打算分析一波深圳区的,打开首页www.lagou.com/
进去后选择深圳站,搜索栏输入 android点进去后,发现有30页:
随手点下一页,页面没有整个刷新,基本都是Ajax了,
F12开发者选项,打开抓包,Network选项卡clear一下,
选中**XHR
**,点下一页,哟,有两个:
点击preview看下具体的json内容:
不知道是什么东西,随手复制个451,然后切换到Element搜索,
哟,原来是公司id,拼接下可以获得一个跳到公司详细信息的url,
这里暂时没用,approve,译作认证,就是认证公司id列表,
跟着一个true,猜测是企业是否认证的标识,可能是页面上
不显示未认证企业或者显示不一样的UI吧,接着看下一个接口:
明显就是我们想Get的数据,hrInfoMap字段是和HR相关的信息,没用
跳过,最下面的result数组则是我们最关注的招聘信息了,点开一个
确认下:
知道了要爬哪里的数据,接着就是到怎么模拟请求了:
先是请求头,因为没登录就可以访问了,Cookies就不用传了,
其他的能带上就带上,多了也没什么,然后是链接后面附带
的参数,固定的不用改:
- city: 深圳
- needAddtionalResult: false
- isSchoolJob: 0
然后是Post提交的表单数据:
- first: false
- pn: 2
- kd: android
pn是页码,其他的都不用动!都清楚了,接着就写下代码
模拟下了,流程都一清二楚了,不难写出下面的代码:
执行下,把结果贴到Json格式化工具里:
可以,另外这里还有个点可以get以下,就是总共有多少页,总共有738条数据,
每页显示15个,738/15=49,测了下确实是最后一页!
接着捋一捋想要采集的字段:
公司id
,招聘岗位
id,公司全名
,招聘职位名
,工作年限
,
学历
,性质
,行业领域
,公司优势
, 薪资范围
,公司规模
,
技能标签
,融资状态
,公司标签
,所在区域
,公司经度
,
公司纬度
因为我自己买的代理很多都是连接超时或者拒绝连接等各种问题,
所以直接用本机ip爬,随机5-15s避免ip被封,趁着去吃饭的空档,
让他自己慢慢爬。一开始是打算写正则来抠数据的,按照返回的
Json结构,我试着写了这样的正则:
运行后,看到爬取了4,5页没什么问题,于是乎安心去吃饭了,后来
发现部分数据都乱套了,原来是有些页面的Json字段顺序不一样,我服...
还是回归Json按照字段取稳妥,手动抠字段,拼成一个列表,
最后塞一个数组里,最后通过**pandas库的to_csv()**方法转换
为一个列表。
3.用pandas的to_csv方法把数据都塞Excel里
代码如下:
执行完后会在当前工程下生成一个result.csv文件,打开检查下数据是否
都正确,处理下脏数据,发现有五个数据位置是错乱的:
依次查看错乱的原因:
Android高级开发工程师 
最新iMAC 
双休 
待遇丰厚 
Android系统&
移动开发经理 (Android &
移动App开发工程师(Android&
复制代码
这里简直是巨坑,上面的 
和&
是Html里的转义字符,需要调用
html.unescape
()方法转义一波,对应相反的方法**escape
**()
当爬取的内容是字符串的时候要小心这个坑!!!修改后的代码:
总共采集到736条数据,不算多,但也可以开始做数据分析了。
4.数据分析前可能遇到的一些问题
1)matplotlib中文乱码问题
主要使用条形图,饼图和词云来展示数据分析结果!
使用matplotlib进行图标绘制,基本都会遇到的一个问题,中文乱码,
解决流程如下:
打开终端,cd到路径下,然后准备一枚中文ttf,接着命令行sudo mv
把ttf文件拷贝到该路径下:
接着双击安装,安装后修改配置文件,对如图三处做相应修改:
修改完毕后,执行下述命令删除一波缓存文件
接着再运行就可以了:
其他系统处理matplotlib中文乱码问题自行参见:matplotlib图例中文乱码
2)matplotlib绘制显示不全
如图所示,在绘制的时候可能会出现显示不全的情况:
顺道介绍下按钮,依次是:
重置回主视图,上一步视图,下一步视图,拖拽页面,
局部放大,设置,保存成图片
然后的话,可以点下设置,会出现:
拖拉调整下,直到差不多能显示完全
接着记录下对应的参数,代码中设置下:
5.开始数据分析
一.分析招聘公司的一些情况
行业领域
从词云可以看出,Android招聘大部分还是移动互联网公司,接着依次是金融,
硬件,电子商务,电子商务?都是干嘛的,利用pandas做下简单筛选,
随手搜了几个百度下,这种从事电子商务大概是:
电商(有自己的购物APP,平台),外包,支付,POS机等
接着是游戏,数据服务,企业服务,o2o等等。
公司规模
融资状态
PS:卧槽,15-50人和未融资公司的百分比竟然异常接近,应该大部分都是
小型的创业公司吧,基本都很坑...
所在区域
大部分招Android的公司还是集中在南山区,其次是福田区和宝安区,
小部分在龙华新区和龙岗区。
公司标签
看下公司都打着怎么样的标签招人
公司优势
和上面一个样,假如你公司要你写招聘条件的时候,就不愁写什么啦~
二.分析对招聘者的一些要求
工作年限
招最多的是3-5年工作经验,其次是1-3年,再接着是5-10年
学历要求
以前以为学历不重要,然而图中本科要求占比71.8%,没有本科学历意味着:
可能失去七成的机会,哭哭/(ㄒoㄒ)/~~,我这种渣渣还是继续当咸鱼吧...
薪资情况
拉钩标的薪酬都是有个范围的,其实一般最小值就是你实际进公司后的
薪资,直接以最小值作为参考,图中明显的三个小高峰,10k,15k,8k。
猜测对应:
10k - 3年经验左右的一般的中初级工程师
15k - 3-5年经验的技术较好的中高级工程师
8k - 1到3年内的初中级工程师
当然土豪公司不在范围内,看完自己找工作的时候开口要多少钱,
心里应该有点B数啦。(哭哭,又拖后腿了/(ㄒoㄒ)/~~)
技能标签
Java, iOS,架构,C++,系统开发,中级,高级,资深,视频,信息安全...
要求Java我能理解,这要求iOS是什么鬼?现在找个Android岗都要会iOS了?
后来才发现并没那么夸张,只是招聘职位那里Android/iOS,所以才有iOS
的标签,还有些瞎几把填的标签,进去招聘要求里一个iOS的字眼也没有。
到此就分析完啦~
6.小结
本节依次抓取了一波拉勾网和Android职位相关的数据,利用这些数据对
公司情况和招聘要求进行了分析,通过图表以及词云的形式,尽管没有
得出非常有用的信息,不过应该也get了不少东西,上上周周一就立flag
出的,结果因为项目发新版本,自己感冒凉了几天,一直拖到现在...
因为篇幅和时间关系,有两个遗憾:Jupyter Notebook 和 geopandas,
前者是用作数据可视化展示的一个很强大的工具,而后者则是生成
地图类的一个库,还记得我们采集到的经纬度么?弄一个类似于热力
图的东东不是很酷么?学习成本有点高,后面再了试试吧!
附:最终代码(都可以在:github.com/coder-pig/R… 找到):
# 拉勾网Android招聘数据分析
import urllib.parse
import requests
import xlwt
import xlrd
import tools as t
import pandas as pd
import geopandas as gp
import re
import random
import time
import html
import matplotlib.pyplot as plt
import numpy as np
from wordcloud import WordCloud, STOPWORDS, ImageColorGenerator
from collections import Counter
from scipy.misc import imread
import config as c
from shapely.geometry import Point, Polygon
max_page = 1
result_save_file = c.outputs_logs_path + 'result.csv'
pic_save_path = c.outputs_pictures_path + 'LaGou/'
default_font = c.res_documents + 'wryh.ttf' # 生成词云用的默认字体
default_mask = c.res_pictures + 'default_mask.jpg' # 默认遮罩图片
# Ajax加载url
ajax_url = "https://www.lagou.com/jobs/positionAjax.json?"
# url拼接参数
request_params = {'px': 'default', 'city': '深圳', 'needAddtionalResult': 'false', 'isSchoolJob': '0'}
# post提交参数
form_data = {'first': 'false', 'pn': '1', 'kd': 'android'}
# 获得页数的正则
page_pattern = re.compile('"totalCount":(\d*),', re.S)
# csv表头
csv_headers = [
'公司id', '职位名称', '工作年限', '学历', '职位性质', '薪资',
'融资状态', '行业领域', '招聘岗位id', '公司优势', '公司规模',
'公司标签', '所在区域', '技能标签', '公司经度', '公司纬度', '公司全名'
]
# 模拟请求头
ajax_headers = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Connection': 'keep-alive',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Host': 'www.lagou.com',
'Origin': 'https://www.lagou.com',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 '
'Safari/537.36',
'X-Anit-Forge-Code': '0',
'X-Anit-Forge-Token': 'None',
'X-Requested-With': 'XMLHttpRequest',
'Referer': 'https://www.lagou.com/jobs/list_android?labelWords=&fromSearch=true&suginput='
}
# 获取每页招聘信息
def fetch_data(page):
fetch_url = ajax_url + urllib.parse.urlencode(request_params)
global max_page
while True:
try:
form_data['pn'] = page
print("抓取第:" + str(page) + "页!")
resp = requests.post(url=fetch_url, data=form_data, headers=ajax_headers)
if resp.status_code == 200:
if page == 1:
max_page = int(int(page_pattern.search(resp.text).group(1)) / 15)
print("总共有:" + str(max_page) + "页")
data_json = resp.json()['content']['positionResult']['result']
data_list = []
for data in data_json:
data_list.append((data['companyId'],
html.unescape(data['positionName']),
data['workYear'],
data['education'],
data['jobNature'],
data['salary'],
data['financeStage'],
data['industryField'],
data['positionId'],
html.unescape(data['positionAdvantage']),
data['companySize'],
data['companyLabelList'],
data['district'],
html.unescape(data['positionLables']),
data['longitude'],
data['latitude'],
html.unescape(data['companyFullName'])))
result = pd.DataFrame(data_list)
if page == 1:
result.to_csv(result_save_file, header=csv_headers, index=False, mode='a+')
else:
result.to_csv(result_save_file, header=False, index=False, mode='a+')
return None
except Exception as e:
print(e)
# 生成词云文件
def make_wc(content, file_name, mask_pic=default_mask, font=default_font):
bg_pic = imread(mask_pic)
pic_colors = ImageColorGenerator(bg_pic)
wc = WordCloud(font_path=font, background_color='white', margin=2, max_font_size=250,
width=2000, height=2000,
min_font_size=30, max_words=1000)
wc.generate_from_frequencies(content)
wc.to_file(file_name)
# 数据分析方法(生成相关文件)
def data_analysis(data):
# 1.分析招聘公司的相关信息
# 行业领域
industry_field_list = []
for industry_field in data['行业领域']:
for field in industry_field.strip().replace(" ", ",").replace("、", ",").split(','):
industry_field_list.append(field)
counter = dict(Counter(industry_field_list))
counter.pop('')
make_wc(counter, pic_save_path + "wc_1.jpg")
# 公司规模
plt.figure(1)
data['公司规模'].value_counts().plot(kind='pie', autopct='%1.1f%%', explode=np.linspace(0, 0.5, 6))
plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
bottom=0.17, top=0.84)
plt.savefig(pic_save_path + 'result_1.jpg')
plt.close(1)
# 融资状态
plt.figure(2)
data['融资状态'].value_counts().plot(kind='pie', autopct='%1.1f%%')
plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
bottom=0.17, top=0.84)
plt.savefig(pic_save_path + 'result_2.jpg')
plt.close(2)
# 所在区域
plt.figure(3)
data['所在区域'].value_counts().plot(kind='pie', autopct='%1.1f%%', explode=[0, 0, 0, 0, 0, 0, 0, 1, 1.5])
plt.subplots_adjust(left=0.31, right=0.74, wspace=0.20, hspace=0.20,
bottom=0.26, top=0.84)
plt.savefig(pic_save_path + 'result_3.jpg')
plt.close(3)
# 公司标签
tags_list = []
for tags in data['公司标签']:
for tag in tags.strip().replace("[", "").replace("]", "").replace("'", "").split(','):
tags_list.append(tag)
counter = dict(Counter(tags_list))
counter.pop('')
make_wc(counter, pic_save_path + "wc_2.jpg")
# 公司优势
advantage_list = []
for advantage_field in data['公司优势']:
for field in advantage_field.strip().replace(" ", ",").replace("、", ",").replace(",", ",").replace("+", ",") \
.split(','):
industry_field_list.append(field)
counter = dict(Counter(industry_field_list))
counter.pop('')
counter.pop('移动互联网')
make_wc(counter, pic_save_path + "wc_3.jpg")
# 2.分析招聘需求
# 工作年限要求
# 横向条形图
plt.figure(4)
data['工作年限'].value_counts().plot(kind='barh', rot=0)
plt.title("工作经验直方图")
plt.xlabel("年限/年")
plt.ylabel("公司/个")
plt.savefig(pic_save_path + 'result_4.jpg')
plt.close(4)
# 饼图
plt.figure(5)
data['工作年限'].value_counts().plot(kind='pie', autopct='%1.1f%%', explode=np.linspace(0, 0.75, 6))
plt.title("工作经验饼图")
plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
bottom=0.17, top=0.84)
plt.savefig(pic_save_path + 'result_5.jpg')
plt.close(5)
# 学历要求
plt.figure(6)
data['学历'].value_counts().plot(kind='pie', autopct='%1.1f%%', explode=(0, 0.1, 0.2))
plt.title("学历饼图")
plt.subplots_adjust(left=0.22, right=0.74, wspace=0.20, hspace=0.20,
bottom=0.17, top=0.84)
plt.savefig(pic_save_path + 'result_6.jpg')
plt.close(6)
# 薪资(先去掉后部分的最大工资,过滤掉kK以上词汇,获取索引按照整数生序排列)
plt.figure(7)
salary = data['薪资'].str.split('-').str.get(0).str.replace('k|K|以上', "").value_counts()
salary_index = list(salary.index)
salary_index.sort(key=lambda x: int(x))
final_salary = salary.reindex(salary_index)
plt.title("薪资条形图")
final_salary.plot(kind='bar', rot=0)
plt.xlabel("薪资/K")
plt.ylabel("公司/个")
plt.savefig(pic_save_path + 'result_7.jpg')
plt.close(7)
# 技能标签
skill_list = []
for skills in data['技能标签']:
for skill in skills.strip().replace("[", "").replace("]", "").replace("'", "").split(','):
skill_list.append(skill)
counter = dict(Counter(skill_list))
counter.pop('')
counter.pop('Android')
make_wc(counter, pic_save_path + "wc_4.jpg")
# 处理数据
if __name__ == '__main__':
t.is_dir_existed(pic_save_path)
if not t.is_dir_existed(result_save_file, mkdir=False):
fetch_data(1)
for cur_page in range(2, max_page + 1):
# 随缘休息5-15s
time.sleep(random.randint(5, 15))
fetch_data(cur_page)
else:
raw_data = pd.read_csv(result_save_file)
# data_analysis(raw_data)
# 筛选电子商务公司
dzsw_result = raw_data.loc[raw_data["行业领域"].str.find("电子商务") != -1, ["行业领域", "公司全名"]]
dzsw_result.to_csv(c.outputs_logs_path + "dzsw.csv", header=False, index=False, mode='a+')
# 筛选人15-50人的公司
p_num_result = raw_data.loc[raw_data["所在区域"] == "龙华新区", ["所在区域", "公司全名"]]
p_num_result.to_csv(c.outputs_logs_path + "lhxq.csv", header=False, index=False, mode='a+')
复制代码
来啊,Py交易啊
想加群一起学习Py的可以加下,智障机器人小Pig,验证信息里包含:
Python,python,py,Py,加群,交易,屁眼 中的一个关键词即可通过;
验证通过后回复 加群 即可获得加群链接(不要把机器人玩坏了!!!)~~~
欢迎各种像我一样的Py初学者,Py大神加入,一起愉快地交流学♂习,van♂转py。
小猪的Python学习之旅 —— 16.再尝Python数据分析:采集拉勾网数据分析Android就业行情...的更多相关文章
- Python学习之旅--第二周--python基础
一.什么是pyc? 1.Python是解释性语言,那么.pyc是什么文件? 2.解释性语言和编译型语言区别: 计算机是不能够识别高级语言的,所以当我们运行一个高级别语言程序时,就需要一个&quo ...
- Python学习之旅:使用Python实现Linux中的ls命令
一.写在前面 前几天在微信上看到这样一篇文章,链接为:https://mp.weixin.qq.com/s/rl6Sgv3uk_IpoFAx6cWa8w,在这篇文章中,有这样一段话,吸引了我的注意: ...
- Python学习之旅:用Python制作一个打字训练小工具
一.写在前面 说道程序员,你会想到什么呢?有人认为程序员象征着高薪,有人认为程序员都是死肥宅,还有人想到的则是996和 ICU. 别人眼中的程序员:飞快的敲击键盘.酷炫的切换屏幕.各种看不懂的字符代码 ...
- 180分钟的python学习之旅
最近在很多地方都可以看到Python的身影,尤其在人工智能等科学领域,其丰富的科学计算等方面类库无比强大.很多身边的哥们也提到Python非常的简洁方便,比如用Django搭建一个见得网站只需要半天时 ...
- Python学习入门基础教程(learning Python)--5.6 Python读文件操作高级
前文5.2节和5.4节分别就Python下读文件操作做了基础性讲述和提升性介绍,但是仍有些问题,比如在5.4节里涉及到一个多次读文件的问题,实际上我们还没有完全阐述完毕,下面这个图片的问题在哪呢? 问 ...
- Python学习系列(四)Python 入门语法规则2
Python学习系列(四)Python 入门语法规则2 2017-4-3 09:18:04 编码和解码 Unicode.gbk,utf8之间的关系 2.对于py2.7, 如果utf8>gbk, ...
- Python学习课程零基础学Python
python学习课程,零基础Python初学者应该怎么去学习Python语言编程?python学习路线这里了解一下吧.想python学习课程?学习路线网免费下载海量python教程,上班族也能在家自学 ...
- Python学习之旅(十七)
Python基础知识(16):面向对象编程(Ⅰ) 类和实例 类是抽象的模板 实例是根据类创建出来的一个个具体的对象,每个对象都拥有相同的方法,但各自的数据可能不同. 类可以在创建实例的时候,把一些我们 ...
- python学习之旅
python学习分类 python基础 +- day01——python初始.变量.常量.注释.基础数据类型.输入.if day02——while.字符串格式化.运算符.编码初识 day03—— ...
随机推荐
- laravel使用创建的request作为表单验证类
1.使用命令行工具创建request php artisan make request:validateLoginRequest 2.创建后进入app/Http/Requests目录下找到创建的文件 ...
- Python设计模式(1)-简单工厂模式
为操作数据库设计增删改查操作 # coding=utf-8class DbManager: def __init__(self): pass def operate_db(self): pass cl ...
- IntelliJ IDEA 在方法大括号中{}点击回车多出一个},如何取消
在 File - settings - Editor - General- Smart Keys - Enter 去掉 Insert pair '}' 的对勾就可以了
- 查看jdk 线程 日志
命令:jstack(查看线程).jmap(查看内存)和jstat(性能分析)命令 这些命令 必须 在 linux jdk bin 路径 下执行 eq: ./jstack 10303 即可 如果想把 ...
- 数据结构和算法(Golang实现)(25)排序算法-快速排序
快速排序 快速排序是一种分治策略的排序算法,是由英国计算机科学家Tony Hoare发明的, 该算法被发布在1961年的Communications of the ACM 国际计算机学会月刊. 注:A ...
- 练习,自定义TextView(1.1)
重新自定义TextView是非常有趣的事情,跟着Android4高级编程,通过自定义TextView,来敲一下代码: 这个是那么的简单,自定义TextView,新建CustomTextView继承Te ...
- python脚本如何同时运行多个
当我们想一次运行多个py脚本的时候你想到了什么应用场景了吗?当你想同时并行的处理一些对象时你有什么好方法吗?下面我就简单的总结一些这方面的小技巧,方便大家根据情况灵活处理. 1 用一个py脚本运行多个 ...
- MySQL 归纳总结
1.MySQL存储引擎 主要使用的就是两个存储引擎,分别是InnoDB和MyISAM. InnoDB InnoDB是MySQL的默认存储引擎.InnoDB采用MVCC来支持高并发,并且实现了四个标准的 ...
- C - N皇后问题 DFS
在N*N的方格棋盘放置了N个皇后,使得它们不相互攻击(即任意2个皇后不允许处在同一排,同一列,也不允许处在与棋盘边框成45角的斜线上. 你的任务是,对于给定的N,求出有多少种合法的放置方法. Inpu ...
- 图2-4TCP状态转换图
这张图中描述了TCP中11个状态的转换. 光看这个图我一开始是蒙蔽的,也没有写服务器和客户端的操作流程.不过回头一想,是状态转换,也就是从一个状态到另外一个状态发生了什么,什么条件触发的.这样是不是好 ...