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


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

 

一、原理

    通過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的崗位信息一次,源碼、優化都會以博客的形式寫出來,歡迎關注~

 

源碼地址:智聯招聘_爬蟲源碼


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM