原文地址:http://www.jtahstu.com/blog/s...php
感謝BOSS直聘相對權威的招聘信息,使本人有了此次比較有意思的研究之旅。html
因爲爬蟲持續爬取 www.zhipin.com 網站,以至產生的服務器壓力,本人深感歉意,並無 DDoS 和危害貴網站的意思。python
[2017-12-14更新]
在跑了一晚上以後,服務器 IP 仍是被封了,搞得本人如今家裏、公司、雲服務器三線做戰啊
[2017-12-19更新]
後續把拉勾網的數據也爬到,加了進來
這裏須要知道頁面的 id 才能生成詳細的連接,在 Python爬蟲框架Scrapy實戰 - 抓取BOSS直聘招聘信息 中,咱們已經拿到招聘信息的大部分信息,裏面有個 pid
字段就是用來惟一區分某條招聘,並用來拼湊詳細連接的。git
是吧,明眼人一眼就看出來了。web
詳情頁以下圖所示數據庫
在詳情頁中,比較重要的就是職位描述
和工做地址
這兩個編程
因爲在頁面代碼中崗位職責
和任職要求
是在一個 div 中的,因此在抓的時候就不太好分,後續須要把這個連體嬰兒,分開分析。服務器
使用的庫有微信
對應的安裝文檔依次以下,就不細說了cookie
""" @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 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,初學者都能看懂。
在 上一篇文章 中只是爬了 上海-PHP
近300條數據,後續改了代碼,把12個城市的 PHP 相關崗位的數據都抓下來了,有3500+條數據,慢慢爬吧,急不來。
像這樣
"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')
"salary" : "5K-12K", #處理成下面的格式 "salary" : { "low" : 5000, "high" : 12000, "avg" : 8500.0 },
# 薪水處理成數字,符合 xk-yk 的數據處理,不符合的跳過 def clear_salary(): items = db.jobs_lagou_php.find({}) for item in items: if type(item['salary']) == type({}): continue salary_list = item['salary'].lower().replace("k", "000").split("-") if len(salary_list) != 2: print(salary_list) continue try: salary_list = [int(x) for x in salary_list] except: print(salary_list) continue item['salary'] = { 'low': salary_list[0], 'high': salary_list[1], 'avg': (salary_list[0] + salary_list[1]) / 2 } update(item) print('ok')
[2017-12-19更新]
這裏在處理 Boss 直聘的數據時,比較簡單正常,可是後續抓到拉勾網的數據,拉勾網的數據有些不太規範。好比有‘20k以上’這種描述
# 校訂拉勾網工做年限描述,以 Boss直聘描述爲準 def update_lagou_workyear(): items = db.jobs_lagou_php.find({}) for item in items: if item['workYear'] == '應屆畢業生': item['workYear'] = '應屆生' elif item['workYear'] == '1年如下': item['workYear'] = '1年之內' elif item['workYear'] == '不限': item['workYear'] = '經驗不限' update_lagou(item) print('ok') # 設置招聘的水平,分兩次執行 def set_level(): items = db.jobs_zhipin_php.find({}) # items = db.jobs_lagou_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年
左右,可是仍是建議捨棄掉。
[2017-12-19更新]
拉勾網的職位描述和 Boss直聘稍有不一樣,須要先校訂,而後再設置等級
對於做者這個初學者來講,這裏尚未什麼好的方法,知道的同窗,請務必聯繫做者,聯繫方式在我的博客裏
so , i'm sorry.
爲何這兩個很差劃分出來呢?
由於這裏填的並不統一,能夠說各類花樣,有的要求在前,職責在後,有的又換個名字區分。目前看到的關於要求的有['任職條件', '技術要求', '任職要求', '任職資格', '崗位要求']
這麼多說法。而後順序還不同,有的要求在前,職責在後,有的又反之。
舉個栗子
會基本的php編程!可以修改簡單的軟件!對雲服務器和數據庫可以運用!懂得微信公衆帳號對接和開放平臺對接!咱們不是軟件公司,是運營公司!想找好的公司學習的陝西基本沒有,要到沿海城市去!可是咱們是實用型公司,主要是軟件應用和更適合大衆!
啥也不說的,這裏能夠認爲這是一條髒數據
了。
再舉個栗子
PHP中級研發工程師(ERP/MES方向)
一、計算機或相關學科本科或本科以上學歷;
二、php和Java script的開發經驗。
三、Linux和MySQL數據庫的開發經驗;
五、有ERP、MES相關開發經驗優先;
六、英語的讀寫能力;
七、文化的開放性;
咱們提供
一、有趣的工做任務;
二、多元的工做領域;
三、與能力相關的收入;
四、年輕、開放並具備創造力的團隊和工做氛圍;
五、不斷接觸最新科技(尤爲是工業4.0相關);
六、可適應短時間出差(提供差補);
這個只有要求,沒職責,還多了個提供,我樂個趣 ╮(╯▽╰)╭
因此,氣的想罵人。
[2017-12-19]更新
Boss直聘這裏有部分招聘沒有industryField、financeStage和companySize值,這個能夠看前一篇的爬蟲代碼,拉勾網的數據基本沒問題。
[2017-12-19] 更新
1年之內
,可是職位描述裏倒是2年以上工做經驗
,這是因爲 HR 填寫不規範引發的偏差。一年之內
,因此等級爲2,可是薪水倒是20k-30k
,實際上這是等級爲3的薪水,這裏就得校訂 level 字段,目前只是手動的把幾個較高的記錄手動改了,都校訂過來很困難,得文本分析招聘要求。[2017-12-19] 更新
首先這裏須要一個判斷某條招聘是否還掛在網站上的方法,這個暫時想到了還沒弄
而後對於發佈時間在兩個月以前的數據,就不進行統計計算
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" : "一、處理landcloud雲計算相關係統的各種開發和調研工做;二、處理coms高性能計算的各種開發和調研工做崗位要求:一、本科學歷,兩年以上工做經驗,熟悉PHP開發,瞭解經常使用的php開發技巧和框架;二、瞭解C++,python及Java開發;三、有必定的研發能力和鑽研精神;四、有主動溝通能力和吃苦耐勞的精神。", "location" : "蘇州市高新區科技城錦峯路158號101park8幢" }
因爲還沒到數據展現的時候,因此如今能想到的就是先這樣處理了
項目開源地址:http://git.jtahstu.com/jtahst...
首先這個小玩意數據量並不夠多,由於爬取時間短,站點惟一,再者廣度侷限在 PHP 這一個崗位上,以至存在必定的偏差。
因此爲了數據的豐富和多樣性,這個爬蟲是必定要持續跑着的,至少要抓幾個月的數據
纔算可靠吧。
而後準備再去抓下拉勾網
的招聘數據,這也是個相對優秀的專業 IT 招聘網站了,數據也至關多,想當初找實習找正式工做,都是在這兩個 APP 上找的,其餘的網站幾乎都沒看。
最後,對於科班出身的學弟學妹們,過來人說一句,編程相關的職業就不要去志連、錢塵烏有、five eight桐城了,好嗎?那裏面都發的啥呀,看那些介紹內心沒點數嗎?
這裏徹底就是做者本人依據我的微薄的見識,主觀臆斷作的一些事情,因此你們有什麼點子和建議,均可以評論一下,多交流交流嘛。
後續會公開全部數據,你們本身能夠本身分析分析。
咱們太年輕,以至都不知道之後的時光,居然那麼長,長得足夠讓咱們把一門技術研究到頂峯,亂花漸欲迷人眼,請不要忘了根本好嗎。
生活老是讓咱們遍體鱗傷,但到後來,那些受傷的地方必定會變成咱們最強壯的地方。 —海明威 《永別了武器》