Pyhton爬虫实战 - 抓取BOSS直聘职位描述 和 数据清洗

零、致谢

感谢BOSS直聘相对权威的招聘信息,使本人有了这次比较有意思的研究之旅。

由于爬虫持续爬取 www.zhipin.com 网站,以致产生的服务器压力,本人深感歉意,并没有 DDoS 和危害贵网站的意思。

2017-12-14 更新
在跑了一夜之后,服务器 IP 还是被封了,搞得本人现在家里、公司、云服务器三线作战啊

一、抓取详细的职位描述信息

1.1 前提数据

这里需要知道页面的 id 才能生成详细的链接,在 Python爬虫框架Scrapy实战 - 抓取BOSS直聘招聘信息 中,我们已经拿到招聘信息的大部分信息,里面有个 pid 字段就是用来唯一区分某条招聘,并用来拼凑详细链接的。

是吧,明眼人一眼就看出来了。


1.2 详情页分析

详情页如下图所示

在详情页中,比较重要的就是职位描述工作地址这两个

由于在页面代码中岗位职责任职要求是在一个 div 中的,所以在抓的时候就不太好分,后续需要把这个连体婴儿,分开分析。


1.3 爬虫用到的库

使用的库有

  • requests
  • BeautifulSoup4
  • pymongo

对应的安装文档依次如下,就不细说了

  • 安装 Requests - Requests 2.18.1 文档
  • 安装 Beautiful Soup - Beautiful Soup 4.2.0 文档
  • PyMongo安装使用笔记

1.4 Python 代码

"""
@author: jtahstu
@contact: root@jtahstu.com
@site: http://www.jtahstu.com
@time: 2017/12/10 00:25
"""
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
import time
from pymongo import MongoClientheaders = {'x-devtools-emulate-network-conditions-client-id': "5f2fc4da-c727-43c0-aad4-37fce8e3ff39",'upgrade-insecure-requests': "1",'user-agent': "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36",'accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",'dnt': "1",'accept-encoding': "gzip, deflate",'accept-language': "zh-CN,zh;q=0.8,en;q=0.6",'cookie': "__c=1501326829; lastCity=101020100; __g=-; __l=r=https%3A%2F%2Fwww.google.com.hk%2F&l=%2F; __a=38940428.1501326829..1501326829.20.1.20.20; Hm_lvt_194df3105ad7148dcf2b98a91b5e727a=1501326839; Hm_lpvt_194df3105ad7148dcf2b98a91b5e727a=1502948718; __c=1501326829; lastCity=101020100; __g=-; Hm_lvt_194df3105ad7148dcf2b98a91b5e727a=1501326839; Hm_lpvt_194df3105ad7148dcf2b98a91b5e727a=1502954829; __l=r=https%3A%2F%2Fwww.google.com.hk%2F&l=%2F; __a=38940428.1501326829..1501326829.21.1.21.21",'cache-control': "no-cache",'postman-token': "76554687-c4df-0c17-7cc0-5bf3845c9831"
}
conn = MongoClient('127.0.0.1', 27017)
db = conn.iApp  # 连接mydb数据库,没有则自动创建def init():items = db.jobs_php.find().sort('pid')for item in items:if 'detail' in item.keys(): # 在爬虫挂掉再此爬取时,跳过已爬取的行continuedetail_url = "https://www.zhipin.com/job_detail/%s.html?ka=search_list_1" % item['pid']print(detail_url)html = requests.get(detail_url, headers=headers)if html.status_code != 200: # 爬的太快网站返回403,这时等待解封吧print('status_code is %d' % html.status_code)breaksoup = BeautifulSoup(html.text, "html.parser")job = soup.select(".job-sec .text")if len(job) < 1:continueitem['detail'] = job[0].text.strip()  # 职位描述location = soup.select(".job-sec .job-location")item['location'] = location[0].text.strip()  # 工作地点item['updated_at'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())  # 实时爬取时间res = save(item) # 保存数据print(res)time.sleep(40) # 停停停# 保存数据到 MongoDB 中
def save(item):return db.jobs_php.update_one({"_id": item['_id']}, {"$set": item})if __name__ == "__main__":init()

代码 easy,初学者都能看懂。


1.5 再啰嗦几句

在 上一篇文章 中只是爬了 上海-PHP 近300条数据,后续改了代码,把12个城市的 PHP 相关岗位的数据都抓下来了,有3500+条数据,慢慢爬吧,急不来。

像这样

二、数据清洗

2.1 校正发布日期

"time" : "发布于03月31日",
"time" : "发布于昨天",
"time" : "发布于11:31",

这里拿到的都是这种格式的,所以简单处理下

import datetimefrom pymongo import MongoClientdb = MongoClient('127.0.0.1', 27017).iAppdef update(data):return db.jobs_php.update_one({"_id": data['_id']}, {"$set": data})# 把时间校正过来
def clear_time():items = db.jobs_php.find({})for item in items:if not item['time'].find('布于'):continueitem['time'] = item['time'].replace("发布于", "2017-")item['time'] = item['time'].replace("月", "-")item['time'] = item['time'].replace("日", "")if item['time'].find("昨天") > 0:item['time'] = str(datetime.date.today() - datetime.timedelta(days=1))elif item['time'].find(":") > 0:item['time'] = str(datetime.date.today())update(item)print('ok')

2.2 校正薪水以数字保存

"salary" : "5K-12K",#处理成下面的格式
"salary" : {"low" : 5000,"high" : 12000,"avg" : 8500.0
},
# 薪水处理成数字
def clear_salary():items = db.jobs_php.find({})for item in items:if type(item['salary']) == type({}):continuesalary_list = item['salary'].replace("K", "000").split("-")salary_list = [int(x) for x in salary_list]item['salary'] = {'low': salary_list[0],'high': salary_list[1],'avg': (salary_list[0] + salary_list[1]) / 2}update(item)print('ok')

2.3 根据 工作经验年限 划分招聘等级

# 设置招聘的水平
def set_level():items = db.jobs_php.find({})for item in items:if item['workYear'] == '应届生':item['level'] = 1elif item['workYear'] == '1年以内':item['level'] = 2elif item['workYear'] == '1-3年':item['level'] = 3elif item['workYear'] == '3-5年':item['level'] = 4elif item['workYear'] == '5-10年':item['level'] = 5elif item['workYear'] == '10年以上':item['level'] = 6elif item['workYear'] == '经验不限':item['level'] = 10update(item)print('ok')

这里有点坑的就是,一般要求经验不限的岗位,需求基本都写在任职要求里了,所以为了统计的准确性,这个等级的数据,后面会被舍弃掉。

2017-12-14 更新:
从后续的平均数据来看,这里的经验不限,一般要求的是1-3年左右,但是还是建议舍弃掉。


2.4 区分开<岗位职责>和<任职要求>

对于作者这个初学者来说,这里还没有什么好的方法,知道的同学,请务必联系作者,联系方式在个人博客里

so , i’m sorry.

为什么这两个不好划分出来呢?

因为这里填的并不统一,可以说各种花样,有的要求在前,职责在后,有的又换个名字区分。目前看到的关于要求的有['任职条件', '技术要求', '任职要求', '任职资格', '岗位要求']这么多说法。然后顺序还不一样,有的要求在前,职责在后,有的又反之。

举个栗子

会基本的php编程!能够修改简单的软件!对云服务器和数据库能够运用!懂得微信公众账号对接和开放平台对接!我们不是软件公司,是运营公司!想找好的公司学习的陕西基本没有,要到沿海城市去!但是我们是实用型公司,主要是软件应用和更适合大众!

啥也不说的,这里可以认为这是一条脏数据了。

不行,再举个栗子

PHP中级研发工程师(ERP/MES方向)
1、计算机或相关学科本科或本科以上学历;
2、php和Java script的开发经验。
3、Linux和MySQL数据库的开发经验;
5、有ERP、MES相关开发经验优先;
6、英语的读写能力;
7、文化的开放性;
我们提供
1、有趣的工作任务;
2、多元的工作领域;
3、与能力相关的收入;
4、年轻、开放并具有创造力的团队和工作氛围;
5、不断接触最新科技(尤其是工业4.0相关);
6、可适应短期出差(提供差补);

这个只有要求,没职责,还多了个提供,我乐个趣 ╮(╯▽╰)╭

所以,气的想骂人。


ok ,现在我们的数据基本成这样了

{"_id" : ObjectId("5a30ad2068504386f47d9a4b"),"city" : "苏州","companyShortName" : "蓝海彤翔","companySize" : "100-499人","education" : "本科","financeStage" : "B轮","industryField" : "互联网","level" : 3,"pid" : "11889834","positionLables" : [ "PHP", "ThinkPHP"],"positionName" : "php研发工程师","salary" : {"avg" : 7500.0,"low" : 7000,"high" : 8000},"time" : "2017-06-06","updated_at" : "2017-12-13 18:31:15","workYear" : "1-3年","detail" : "1、处理landcloud云计算相关系统的各类开发和调研工作;2、处理coms高性能计算的各类开发和调研工作岗位要求:1、本科学历,两年以上工作经验,熟悉PHP开发,了解常用的php开发技巧和框架;2、了解C++,python及Java开发;3、有一定的研发能力和钻研精神;4、有主动沟通能力和吃苦耐劳的精神。","location" : "苏州市高新区科技城锦峰路158号101park8幢"
}

由于还没到数据展示的时候,所以现在能想到的就是先这样处理了

项目开源地址:http://git.jtahstu.com/jtahstu/Scrapy_zhipin

三、展望和设想

首先这个小玩意数据量并不够多,因为爬取时间短,站点唯一,再者广度局限在 PHP 这一个岗位上,以致存在一定的误差。

所以为了数据的丰富和多样性,这个爬虫是一定要持续跑着的,至少要抓几个月的数据才算可靠吧。

然后准备再去抓下拉勾网的招聘数据,这也是个相对优秀的专业 IT 招聘网站了,数据也相当多,想当初找实习找正式工作,都是在这两个 APP 上找的,其他的网站几乎都没看。

最后,对于科班出身的学弟学妹们,过来人说一句,编程相关的职业就不要去志连、钱尘乌有、five eight桐城了,好吗?那里面都发的啥呀,看那些介绍心里没点数吗?

四、help

这里完全就是作者本人依据个人微薄的见识,主观臆断做的一些事情,所以大家有什么点子和建议,都可以联系作者,多交流交流嘛。

后续会公开所有数据,大家自己可以弄着玩玩吧。

我们太年轻,以致都不知道以后的时光,竟然那么长,长得足够让我们把一门技术研究到顶峰,乱花渐欲迷人眼,请不要忘了根本好吗。

生活总是让我们遍体鳞伤,但到后来,那些受伤的地方一定会变成我们最强壮的地方。 —海明威 《永别了武器》

Pyhton爬虫实战 - 抓取BOSS直聘职位描述 和 数据清洗相关推荐

  1. python爬取boss直聘招聘信息_Python爬虫实战-抓取boss直聘招聘信息

    Python Python开发 Python语言 Python爬虫实战-抓取boss直聘招聘信息 实战内容:爬取boss直聘的岗位信息,存储在数据库,最后通过可视化展示出来 PS注意:很多人学Pyth ...

  2. python爬虫招聘-Python爬虫实战-抓取boss直聘招聘信息

    实战内容:爬取boss直聘的岗位信息,存储在数据库,最后通过可视化展示出来 PS注意:很多人学Python过程中会遇到各种烦恼问题,没有人帮答疑容易放弃.为此小编建了个Python全栈免费答疑.裙 : ...

  3. Python爬虫实战之二 - 基于Scrapy框架抓取Boss直聘的招聘信息

    Python爬虫实战之三 - 基于Scrapy框架抓取Boss直聘的招聘信息 ---------------readme--------------- 简介:本人产品汪一枚,Python自学数月,对于 ...

  4. python抓取boss直聘招聘信息

    1.目前测试情况看只能抓取头3页,后续得重新换cookie抓取. 2.如果登录自己boss账户,有可能导致账户临时被封,测试情况是个人账户被封了一个小时. #!/usr/bin/python # -* ...

  5. 爬虫之爬取Boss直聘

    爬取Boss直聘主要有以下难点: 在不登陆的情况下最多爬十页就会出现手动打码验证 出现大概五六次手动打码后就会封禁ip地址,封禁1天的时间 解决办法 1.切换ip 这里我尝试过很多收费代理,免费代理, ...

  6. Python爬虫:爬取“Boss直聘”招聘数据

    hello 大家好~ 又是元气满满的一天呢~ 既然元气满满,要不要搞点事情,譬如说,爬取"Boss直聘"(此处模仿歪果仁讲话更带感)的招聘数据~ 说走咱就走,说干咱就干~" ...

  7. 爬虫进阶:Scrapy 抓取 boss 直聘、拉勾心得经验

    关于使用Scrapy的体会,最明显的感受就是这种模板化.工程化的脚手架体系,可以说是拿来即可开箱便用,大多仅需按一定的规则套路配置,剩下的就是专注于编写跟爬虫业务有关的代码.绝大多数的反反爬虫策略,大 ...

  8. 实战:利用requests库、lxml库的etree,采用xpath方法抓取boss直聘网岗位信息

    编写思路: 获取每个岗位的页面url. 进入url,获取需要的各项信息(岗位.工资.待遇). 保存成csv(保存的csv文件若想用excel打开且不出现乱码,需要在with open 中加入参数:en ...

  9. python爬取boss直招_简易python爬虫爬取boss直聘职位,并写入excel

    1,默认城市是杭州,代码如下 #! -*-coding:utf-8 -*- from urllib import request, parse from bs4 import BeautifulSou ...

  10. boss直聘python_使用python抓取boss直聘岗位信息

    此文档,需要提前设置好google的webdriver. 抓取的信息会保存为xls表 可以替换url=参数来寻找不同岗位和地区:先打开boss直聘网站,然后根据自己想要查询的岗位进行搜索,再复制url ...

最新文章

  1. 使用KMeanCluster对多个区域进行聚类,并结合Matplotlib绘制中心点、最大最小距离点
  2. 北大高材生割美国韭菜被FBI通缉?本人回应予以否认
  3. vs2015下载 简体中文版/企业版 附邀请码
  4. mongodb数据合并设计_MongoDB:如何将来自多个集合的数据合并成一个.?
  5. web前端入门学习 html5(1)
  6. 因为一个循环,CPU搞了个新技术
  7. node生成uuid
  8. AndroidStudio_解决butterknife在module中使用BindView Attribute value must be constant---Android原生开发工作笔记229
  9. 十二、实战底部(二)
  10. 镜头对摄像机性能的影响
  11. delphi xe6 让 ListView 在 Android 可回弹[根据龟山阿卍原创修改为xe6版本]
  12. 求生之路2服务器无线跳,求生之路连跳宏 | 手游网游页游攻略大全
  13. PHP验证码代码_php验证码类
  14. 偏见:人工智能辅助决策的隐患
  15. 部署Extmail邮件服务器教程——适用于小白
  16. java ip搜索功能_局域网ip搜索工具扫描设备的简单Java实现
  17. 剪切文件丢失如何恢复
  18. 如何自己制作装机工具装系统,硬装系统
  19. 微信小程序|飞翔的圣诞老人
  20. android app防止锁屏_android 屏幕保持不锁屏的实现方式

热门文章

  1. 【Wing Loss】《Wing Loss for Robust Facial Landmark Localisation with Convolutional Neural Networks》
  2. 如此沙雕的代码注释,原来程序员都是段子手
  3. 程序员编程规范之注释
  4. 计算机网络:从入门到放弃
  5. html5禁用右侧滚轮条,鼠标滚轮终于不乱跳了,自己动手更换鼠标滚轮编码器 雷柏7100=================...
  6. 一小时人生服务器维护,TapTap《一小时人生》手游:说好的一小时人生模拟,我却只能活6分钟...
  7. 2021年又一深圳程序员猝死,7大信号助你提前预警《打工人的那些事》
  8. Python开发——8.模块
  9. windows 无法停止ics_Windows10系统不能启动ICS服务致无法连接WiFi热点的三种解决方法...
  10. 优酷屏幕录制在哪里_手机优酷怎么录制视频