1. 程式人生 > >智聯招聘爬蟲原始碼分析(一)

智聯招聘爬蟲原始碼分析(一)

    最近一直在關注秋招,雖然還沒輪到我,不過提前準備總是好的。近期聽聞今年秋招形勢嚴峻,為了更好的準備將來的實習、工作,我決定在招聘網站上爬取一些與資料有關的崗位資訊,藉以給自己將來的職業道路選擇提供參考。

 

一、原理

    通過Python的requests庫,向網站伺服器傳送請求,伺服器返回相關網頁的原始碼,再通過正則表示式等方式在網頁原始碼中提取出我們想要的資訊。

 

二、網頁分析

    2.1崗位詳情url

        在智聯招聘網站中搜索'大資料',跳轉到大資料崗位頁面,接下來我們點開開發者選項,重新整理頁面,在Network面板的XHR中發現了這樣一個數據包:

XHR: XHR為向伺服器傳送請求和解析伺服器響應提供了流暢的介面,能夠以非同步方式從伺服器取得更多資訊,意味著使用者單擊後,可以不必重新整理頁面也能取得新資料

        在新的頁面開啟後:

        這個頁面裡出現的所有的崗位資訊都在裡面了:崗位名稱、公司名稱、薪水、地區、詳情介面的url都在該json裡。但是這些資訊都不是最重要的,我需要崗位要求以及崗位職責的要求。

        將該json解析,得到如下結構的json資料:

        code的值為HTTP的響應碼,200表示請求成功。而results陣列則是該頁面崗位資訊的資料。點開第一條資料(results的第一個元素):

        頁面中出現的所有資料,以及相關的超連結都在這兒。其中,我們需要的是指向崗位詳情介面的超連結——'positionURL'。點選該連結,進去該崗位資訊詳情頁面:

        好了,我們需要的資訊出現了,不過為了簡化頁面分析的操作,以及儘可能地不被反爬,我決定選擇移動適配的頁面。

        再開啟開發者選項,在該崗位詳情頁面,重新整理:

        在<meta>中找到'mobile-agent',提取後面的url——'url=//m.zhaopin.com/jobs/CZ745244850J00020982209/',開啟:

        真清爽!

    2.2 Xpath定位

        XPath即為XML路徑語言(XML Path Language),它是一種用來確定XML文件中某部分位置的語言

    分析該網頁的原始碼,尋找我們所需資訊的位置:

    崗位名稱、月薪、公司、地區、學歷、年限資訊都在'//*[@id="r_content"]/div[1]/div/div[1]/div[1]/'下。

  1. title = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[1]/h1/text()')  
  2. pay = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[1]/div[1]/text()')  
  3. place = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[3]/div[1]/span[1]/text()')  
  4. campanyName = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[2]/text()')  
  5. edu = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[3]/div[1]/span[3]/text()')  

 

崗位要求與崗位職責在同一個<div>標籤裡:

    也爬出來:

  1. comment = selector.xpath('//*[@id="r_content"]/div[1]/div/article/div/p/text()')  

好了,最複雜的部分搞定。

 

三、JSON資料包地址

    我們將前三頁的資料包地址比對一下就能看出問題:

  1. https://fe-api.zhaopin.com/c/i/sou?pageSize=60&cityId=489&workExperience=-1&education=-1&companyType=-1&employmentType=-1&jobWelfareTag=-1&kw=%E5%A4%A7%E6%95%B0%E6%8D%AE&kt=3&_v=0.14571817&x-zp-page-request-id=ce8cbb93b9ad4372b4a9e3330358fe7c-1541763191318-555474  
  2. https://fe-api.zhaopin.com/c/i/sou?start=60&pageSize=60&cityId=489&workExperience=-1&education=-1&companyType=-1&employmentType=-1&jobWelfareTag=-1&kw=%E5%A4%A7%E6%95%B0%E6%8D%AE&kt=3&_v=0.14571817&x-zp-page-request-id=ce8cbb93b9ad4372b4a9e3330358fe7c-1541763191318-555474  
  3. https://fe-api.zhaopin.com/c/i/sou?start=120&pageSize=60&cityId=489&workExperience=-1&education=-1&companyType=-1&employmentType=-1&jobWelfareTag=-1&kw=%E5%A4%A7%E6%95%B0%E6%8D%AE&kt=3&_v=0.14571817&x-zp-page-request-id=ce8cbb93b9ad4372b4a9e3330358fe7c-1541763191318-555474  
  4. https://fe-api.zhaopin.com/c/i/sou?start=180&pageSize=60&cityId=489&workExperience=-1&education=-1&companyType=-1&employmentType=-1&jobWelfareTag=-1&kw=%E5%A4%A7%E6%95%B0%E6%8D%AE&kt=3&_v=0.14571817&x-zp-page-request-id=ce8cbb93b9ad4372b4a9e3330358fe7c-1541763191318-555474  

1.我們可以看出第一頁的url結構與後面的url結構有明顯的不同。

2.非首頁的url有明顯的規律性。

3.'kw=*&kt'裡的字元為'大資料'的UTF-8編碼。

 

所以我們對資料包有如下的操作:

  1. if __name__ == '__main__':  
  2.     key = '大資料'  
  3.     
  4.     url = 'https://fe-api.zhaopin.com/c/i/sou?pageSize=60&cityId=489&workExperience=-1&education=-1&companyType=-1&employmentType=-1&jobWelfareTag=-1&kw=' + key + '&kt=3&lastUrlQuery=%7B%22pageSize%22:%2260%22,%22jl%22:%22489%22,%22kw%22:%22%E5%A4%A7%E6%95%B0%E6%8D%AE%22,%22kt%22:%223%22%7D'  
  5.     infoUrl(url)  
  6.     
  7.     urls = ['https://fe-api.zhaopin.com/c/i/sou?start={}&pageSize=60&cityId=489&kw='.format(i*60)+key+'&kt=3&lastUrlQuery=%7B%22p%22:{},%22pageSize%22:%2260%22,%22jl%22:%22489%22,%22kw%22:%22java%22,%22kt%22:%223%22%7D'.format(i) for i in range(1,50)]  
  8.     for url in urls:  
  9.         infoUrl(url)  

 

四、原始碼結構

    1、擷取整個結果介面的JSON資料包,從中提取出各個招聘欄的url。

    2、進入招聘詳細資訊頁面,提取移動端url。

    3、進入移動端介面,抓取需要的資訊。

 

五、原始碼

  1. ''''' 
  2.     智聯招聘——爬蟲原始碼————2018.11 
  3. '''  
  4. import requests  
  5. import re  
  6. import time  
  7. from lxml import etree  
  8. import csv  
  9. import random  
  10.     
  11. fp = open('智聯招聘.csv','wt',newline='',encoding='UTF-8')  
  12. writer = csv.writer(fp)  
  13. '''''地區,公司名,學歷,崗位描述,薪資,福利,釋出時間,工作經驗,連結'''  
  14. writer.writerow(('職位','公司','地區','學歷','崗位','薪資','福利','工作經驗','連結'))  
  15.     
  16. def info(url):  
  17.     res = requests.get(url)  
  18.     u = re.findall('<meta name="mobile-agent" content="format=html5; url=(.*?)" />', res.text)  
  19.     
  20.     if len(u) > 0:  
  21.         u = u[-1]  
  22.     else:  
  23.         return  
  24.     
  25.     u = 'http:' + u  
  26.     
  27.     headers ={  
  28.         'User-Agent''Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.116 Safari/537.36'  
  29.     }  
  30.     
  31.     res = requests.get(u,headers=headers)  
  32.     selector = etree.HTML(res.text)  
  33.     
  34.     # # 崗位名稱  
  35.     title = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[1]/h1/text()')  
  36.     # # 崗位薪資  
  37.     pay = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[1]/div[1]/text()')  
  38.     # # 工作地點  
  39.     place = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[3]/div[1]/span[1]/text()')  
  40.     # # 公司名稱  
  41.     companyName = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[2]/text()')  
  42.     # # 學歷  
  43.     edu = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[3]/div[1]/span[3]/text()')  
  44.     # # 福利  
  45.     walfare = selector.xpath('//*[@id="r_content"]/div[1]/div/div[3]/span/text()')  
  46.     # # 工作經驗  
  47.     siteUrl = res.url  
  48.     workEx = selector.xpath('//*[@id="r_content"]/div[1]/div/div[1]/div[3]/div[1]/span[2]/text()')  
  49.     # # 崗位詳細  
  50.     comment = selector.xpath('//*[@id="r_content"]/div[1]/div/article/div/p/text()')  
  51.     writer.writerow((title, companyName, place, edu, comment, pay, walfare, workEx, siteUrl))  
  52.     print(title, companyName, place, edu, comment, pay, walfare, workEx, siteUrl)  
  53.     
  54. def infoUrl(url):  
  55.     res = requests.get(url)  
  56.     selector = res.json()  
  57.     code = selector['code']  
  58.     if code == 200:  
  59.         data = selector['data']['results']  
  60.         for i in data:  
  61.             href = i['positionURL']  
  62.             info(href)  
  63.             time.sleep(random.randrange(1,4))  
  64.     
  65. if __name__ == '__main__':  
  66.     key = '大資料'  
  67.     
  68.     url = 'https://fe-api.zhaopin.com/c/i/sou?pageSize=60&cityId=489&workExperience=-1&education=-1&companyType=-1&employmentType=-1&jobWelfareTag=-1&kw=' + key + '&kt=3&lastUrlQuery=%7B%22pageSize%22:%2260%22,%22jl%22:%22489%22,%22kw%22:%22%E5%A4%A7%E6%95%B0%E6%8D%AE%22,%22kt%22:%223%22%7D'  
  69.     infoUrl(url)  
  70.     
  71.     urls = ['https://fe-api.zhaopin.com/c/i/sou?start={}&pageSize=60&cityId=489&kw='.format(i*60)+key+'&kt=3&lastUrlQuery=%7B%22p%22:{},%22pageSize%22:%2260%22,%22jl%22:%22489%22,%22kw%22:%22java%22,%22kt%22:%223%22%7D'.format(i) for i in range(1,50)]  
  72.     for url in urls:  
  73.         infoUrl(url)  

 

Ps.因為某些原因,我打算每個月爬取智聯招聘、51job的崗位資訊一次,原始碼、優化都會以部落格的形式寫出來,歡迎關注~

 

原始碼地址:智聯招聘_爬蟲原始碼