原文地址:http://www.jtahstu.com/blog/s...Pyhton爬虫实战-抢BOSS直聘职位描述及数据清洗0.致谢感谢BOSS提供了比较权威的招聘信息,让我有了这次有趣的研学之旅。由于爬虫不断爬取www.zhipin.com网站,对服务器造成的压力深表歉意,无意DDoS或危害您的网站。[2017-12-14更新]跑了一晚上,服务器IP还是被封了,现在家里、公司、云服务器三线作战。抓取,添加1.抓取详细职位描述信息1.1前提数据这里需要知道页面的id,才能生成详细链接。在Python爬虫框架Scrapy实战——抓BOSS直招招聘信息中,我们已经得到了大部分的招聘信息,里面都有一个pid字段,用来唯一区分某次招聘,拼凑详细链接.是的,明眼人一眼就能看出来。1.2详情页分析详情页如下图所示。在详情页中,职位描述和工作地址是最重要的两个。由于页面代码中的工作职责和工作要求都在一个div中,所以不好划分,后续需要单独分析连体双胞胎。1.3爬虫使用的库使用的库是requestsBeautifulSoup4pymongo对应的安装文档如下,不再赘述InstallRequests-Requests2.18.1DocumentInstallBeautifulSoup-BeautifulSoup4.2.0DocumentPyMongo安装注意事项1.4Python代码"""@author:jtahstu@contact:root@jtahstu.com@site:http://www.jtahstu.com@time:2017/12/1000:25"""#-*-编码:utf-8-*-importrequestsfrombs4importBeautifulSoupimporttimefrompymongoimportMongoClientheaders={'x-devtools-emulate-network-conditions-client-id':"5f2fc4da-c727-43c0-aad4-37fce8e3ff39",'upgrade-insecure-requests':"1",'user-agent':"Mozilla/5.0(Macintosh;IntelMacOSX10_12_6)AppleWebKit/537.36(KHTML,likeGecko)Chrome/60.0.3112.90Safari/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",'接受语言':"zh-CN,zh;q=0.8,en;q=0.6",'cookie':“__c=1501326829;最后城市=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;最后城市=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数据库,如果没有,会自动创建definit():items=db.jobs_php.find().sort('pid')foriteminitems:if'detail'initem.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)ifhtml.status_code!=200:#抓取太快的网站返回403,现在等待解封print('status_codeis%d'%html.status_code)breaksoup=BeautifulSoup(html.text,"html.parser")job=soup.select(".job-sec.text")如果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())#实时爬取timeres=save(item)#保存数据print(res)time.sleep(40)#stopstop#将数据保存到MongoDBdefsave(item):returndb.jobs_php.update_one({"_id":item['_id']},{"$set":item})if__name__=="__main__":init()代码很简单,即使是初学者也能看懂PHP有近300条数据,后来改了代码抓取12个城市PHP相关岗位数据。有3500+条数据。让我们慢慢爬,不要着急。像这样2.数据清洗2.1修正发布日期"time":"3月31日发布","time":"昨天发布","time":"11:31发布",这里获取的都是这种格式,所以只需从pymongo导入日期时间importMongoClientdb=MongoClient('127.0.0.1',27017).iAppdefupdate(data):returndb.jobs_php.update_one({"_id":data['_id']},{"$set":data})#修正时间defclear_time():items=db.jobs_php.find({})foriteminitems:ifnotitem['time'].find('Publishedin'):continueitem['time']=item['time'].replace("发表于","2017-")item['time']=item['time'].replace("月","-")item['time']=item['time'].replace("day","")如果item['time'].find("yesterday")>0:item['time'']=str(datetime.date.today()-datetime.timedelta(days=1))elifitem['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},#工资处理成数字,符合xk-yk的数据处理,不匹配则跳过defclear_salary():items=db.jobs_lagou_php.find({})foriteminitems:iftype(item['salary'])==type({}):continuesalary_list=item['salary'].lower().replace("k","000").split("-")iflen(salary_list)!=2:print(salary_list)继续try:salary_list=[int(x)forxinsalary_list]except:print(salary_list)continueitem['salary']={'low':salary_list[0],'high':salary_list[1],'avg':(salary_list[0]+salary_list[1])/2}update(item)print('ok')[2017-12-19update]这里处理Boss直接聘用的数据比较简单正常,但是来自boss的数据Lagou.com被抓后,lagou.com的数据不规范比如有'20k以上'的描述2.3根据工作年限划分招聘等级#更正拉勾网工作年限的描述,使用Boss直接就业的描述defupdate_lagou_workyear():items=db.jobs_lagou_php.find({})foriteminitems:ifitem['workYear']=='Graduate':item['workYear']='Graduate'elif项目['workYear']=='1年以下':item['workYear']='1年以内'elifitem['workYear']=='不限':item['workYear']='不限经验'update_lagou(item)print('ok')#设置招聘等级,分两次执行defset_level():items=db.jobs_zhipin_php.find({})#items=db.jobs_lagou_php.find({})foriteminitems:ifitem['workYear']=='新生':item['level']=1elifitem['workYear']=='1年内':item['level']=2elifitem['workYear']=='1-3岁':item['level']=3elifitem['workYear']=='3-5years':item['level']=4elifitem['workYear']=='5-10年':item['level']=5elifitem['workYear']=='10年以上':item['level']=6elifitem['workYear']=='Unlimitedexperience':item['level']=10update(item)print('ok')这里比较棘手的是一般需要无限经验的岗位,要求职位要求里面基本都写了,所以为了统计的准确性,这个级别的数据后面会舍弃[2017-12-14更新]从后续的平均数据来看,这里的经验不限,一般的要求大概1-3年,但还是建议放弃。[更新于2017-12-19]拉勾网职位描述与Boss直聘略有不同。需要先修正,然后设置level2.4区分<岗位职责>和<岗位要求>。对于像作者这样的初学者,这里没有什么好的方法,知道的同学请务必联系作者,联系方式在个人博客里所以,不好意思。为什么这两者很难区分?因为这里的填写不统一,可以说是花样百出,有的是需求在前,职责在后,还有的是用不同的名字来区分。到目前为止,关于要求的说法有很多['就业条件','技术要求','就业要求','就业资格','职位要求']。那么顺序就不一样了,有的需求在前,职责在后,有的反之。例如,我会了解基本的php编程!能够修改简单的软件!可用于云服务器和数据库!知道如何对接微信公众号和开放平台!我们不是软件公司,而是运营公司!陕西基本没有人想找个好公司学习,只好去沿海城市!但我们是一家实用型公司,主要是软件应用,更适合大众!话不多说,这里也算是脏数据了。另栗PHP中级研发工程师(ERP/MES方向)1、计算机或相关专业本科及以上学历;2.有php和Javascript开发经验。3、有Linux、MySQL数据库开发经验;5、有ERP、MES开发经验者优先;6、英语读写能力;七、文化开放;我们提供1.有趣的任务;2.多元化的工作领域;3、与能力相关的收入;4、年轻、开放、富有创造力的团队和工作氛围;5.不断接触最新技术(尤其是工业4.0相关);6.能适应短期出差(提供补偿);这只是请求,不承担责任,还有额外的offer,我玩的开心╮(╯▽╰)╭所以,气得想骂人。2.5缺失值分析[2017-12-19]更新老板直聘。有些招聘没有industryField、financeStage和companySize值。这个可以在上一篇的爬虫代码中看到。拉勾网的数据基本没问题。2.6异常值分析[2017-12-19]更新职位要求的工作年限与职位描述要求不一致。比如joblist要求1年以内,但是jobdescription显示2年以上的工作经验。这是因为HR填写不规律造成的错误。第1点带来的另一个问题是不符合工作年限要求的工资,导致计算出的平均工资过高。比如一个记录,年龄要求在一年以内,所以level是2,但是薪资是20k-30k。其实这是一个level为3的salary,这里要对level字段进行修正。目前只有少数较高的是手动设置的。记录是人工修改的,很难全部改正。有必要对文中的招聘要求进行分析。2.7无效值剔除[2017-12-19]更新首先,需要一个方法来判断某个职位是否还在网站上发布。这个暂时想到了,还没做。两个月前发布的数据,没有统计计算就ok了,现在我们的数据基本是这样的Tongxiang","companySize":"100-499人","education":"本科","financeStage":"B轮","industryField":"Internet","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-1318: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/jtahst...三、展望和假设首先这个小工具的数据量不够,因为爬取时间总之,站点是独一无二的,广度受限于PHP的位置,所以存在一定的误差。因此,为了丰富和多样化数据,这个爬虫必须持续运行。它至少必须抓取几个月的数据才算靠谱,然后准备抓拉勾网的招聘数据,也是比较优秀的,有专业的IT招聘网站,数据也挺多的,我看的时候觉得实习和正式工作,我都是在这两个app上找的,有去过的人可以告诉你,y编程相关的职业不要去智联、千辰无忧、五八同城,好吗?里面贴的是什么,你看那些介绍有什么要点吗?四、这里的帮助完全是作者本人根据自己的浅薄知识,做了一些主观臆断,大家有什么想法和建议可以多多评论交流。以后所有数据都会公开,大家可以自行分析分析。我们太年轻了,我们都不知道未来要多久,时间足够我们把一项技术研究到巅峰,花朵也会渐渐迷人。请不要忘记基础知识。生活总是让我们遍体鳞伤,但最终,那些受伤的地方,我们总是最坚强。-欧内斯特·海明威《永别了武器》
