1.1 前提数据这里需要知道页面的 id 才能生成详细的链接,在 文章《Python爬虫框架Scrapy实战 - 抓取BOSS直聘招聘信息》 (链接:http://www./blog/scrapy_zhipin_spider.html)中,我们已经拿到招聘信息的大部分信息,里面有个 pid 字段就是用来唯一区分某条招聘,并用来拼凑详细链接的。 是吧,明眼人一眼就看出来了。 1.2 详情页分析
详情页如下图所示

在详情页中,比较重要的就是职位描述 和工作地址 这两个 由于在页面代码中岗位职责 和任职要求 是在一个 div 中的,所以在抓的时候就不太好分,后续需要把这个连体婴儿,分开分析。 1.3 爬虫用到的库
requests BeautifulSoup4 pymongo
对应的安装文档依次如下,就不细说了 安装 Requests - Requests 2.18.1 文档(http://docs./zh_CN/latest/user/install.html) 安装 Beautiful Soup - Beautiful Soup 4.2.0 文档(https://www./software/BeautifulSoup/bs4/doc/index.zh.html#id5) PyMongo安装使用笔记(http://www.jb51.net/article/64996.htm)
1.4 Python 代码''' @author: jtahstu @contact: root@ @site: http://www. @time: 2017/12/10 00:25 ''' # -*- coding: utf-8 -*- import requests from bs4 import BeautifulSoup import time from pymongo import MongoClient
headers = { '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(): # 在爬虫挂掉再此爬取时,跳过已爬取的行 continue detail_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) break soup = BeautifulSoup(html.text, 'html.parser') job = soup.select('.job-sec .text') if len(job) <>1: continue item['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 再啰嗦几句
在文章《Python爬虫框架Scrapy实战 - 抓取BOSS直聘招聘信息》 (链接:http://www./blog/scrapy_zhipin_spider.html)中,只是爬了 上海-PHP 近300条数据,后续改了代码,把12个城市的 PHP 相关岗位的数据都抓下来了,有3500+条数据,慢慢爬吧,急不来。 像这样


二、数据清洗
2.1 校正发布日期'time' : '发布于03月31日', 'time' : '发布于昨天', 'time' : '发布于11:31',
这里拿到的都是这种格式的,所以简单处理下 import datetime from pymongo import MongoClient db = MongoClient('127.0.0.1', 27017).iApp def 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('布于'): continue item['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({}): continue salary_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'] = 1 elif item['workYear'] == '1年以内': item['level'] = 2 elif item['workYear'] == '1-3年': item['level'] = 3 elif item['workYear'] == '3-5年': item['level'] = 4 elif item['workYear'] == '5-10年': item['level'] = 5 elif item['workYear'] == '10年以上': item['level'] = 6 elif item['workYear'] == '经验不限': item['level'] = 10 update(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/Scrapy_zhipin 三、展望和设想 首先这个小玩意数据量并不够多,因为爬取时间短,站点唯一,再者广度局限在 PHP 这一个岗位上,以致存在一定的误差。 所以为了数据的丰富和多样性,这个爬虫是一定要持续跑着的,至少要抓几个月的数据 才算可靠吧。 然后准备再去抓下拉勾网 的招聘数据,这也是个相对优秀的专业 IT 招聘网站了,数据也相当多,想当初找实习找正式工作,都是在这两个 APP 上找的,其他的网站几乎都没看。 最后,对于科班出身的学弟学妹们,过来人说一句,编程相关的职业就不要去志连、钱尘乌有、five eight桐城了,好吗?那里面都发的啥呀,看那些介绍心里没点数吗? 四、help 这里完全就是作者本人依据个人微薄的见识,主观臆断做的一些事情,所以大家有什么点子和建议,都可以联系作者,多交流交流嘛。 后续会公开所有数据,大家自己可以弄着玩玩吧。 我们太年轻,以致都不知道以后的时光,竟然那么长,长得足够让我们把一门技术研究到顶峰,乱花渐欲迷人眼,请不要忘了根本好吗。 生活总是让我们遍体鳞伤,但到后来,那些受伤的地方一定会变成我们最强壮的地方。 —海明威 《永别了武器》 
|