天天看點

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

一、網頁分析

    1.1 關鍵字頁面(url入口)

        首先在前程無憂網站上檢索關鍵詞"大資料":

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        跳轉到如下url: https://search.51job.com/list/000000,000000,0000,00,9,99,%25E5%25A4%25A7%25E6%2595%25B0%25E6%258D%25AE,2,1.html?lang=c&stype=&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&providesalary=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare=

        在這個url中,'%25E5%25A4%25A7%25E6%2595%25B0%25E6%258D%25AE'很明顯為某種編碼格式,我們知道'大資料'的UTF-8為'E5A4A7 E695B0 E68DAE',加上'%'變為16進制編碼,即'%E5%A4%A7%E6%95%B0%E6%8D%AE',這'25'又是什麼鬼?百度得到到關鍵詞'二次編碼',%25的url編碼即為符号'%',是以'%25E5'即為'%E5'。不過我好奇的是,既然'%'已經是URI中的特殊轉義字元,為啥還要多此一舉地進行二次編碼呢。再查,發現'%'在URI中可能會引起程式解析的歧義,百分号本身就用作對不安全字元進行編碼時使用的特殊字元,是以本身需要編碼。

        做一個實驗,我們将該url截取下來,用'銷售'中文的utf-8編碼代替其中的編碼,看看發生了什麼。

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        再回過頭去看在網站入口搜尋框進去的'大資料'頁面:

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        這是二次編碼過的,再在url裡改成中文名:

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        好吧,二次編碼與否并不影響效果。

        接下來來比較不同頁數URL之間的聯系。提取'大資料'關鍵詞前三頁url:

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        将前兩頁進行對比:

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        隻有一個符号不同,再比較二、三頁:

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        也是一個數字的差異,改數字即為頁碼。是以對于頁數url我們可以得出如下結論:

'https://search.51job.com/list/000000,000000,0000,00,9,99,關鍵詞 ,2,頁數.html?lang=c&stype=1&postchannel=0000&workyear=99&cotype=99&degreefrom=99&jobterm=99&companysize=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare='

        是以入口url子產品代碼如下:

  1. if __name__ == '__main__':  
  2.     key = '銷售'  
  3.     urls = ['https://search.51job.com/list/000000,000000,0000,00,9,99,'+ key + ',2,{}.html?lang=c&stype=1&postchannel=0000&workyear=99&cotype=99°reefrom=99&jobterm=99&companysize=99&lonlat=0%2C0&radius=-1&ord_field=0&confirmdate=9&fromType=&dibiaoid=0&address=&line=&specialarea=00&from=&welfare='.format(i) for i in range(1,50)]  
  4.     for url in urls:  
  5.         getUrl(url)  

    1.2 崗位詳情url

        由于我們需要的是崗位詳情頁面的資訊,是以我們要找出頁面所有崗位的url。

        打開開發者工具,找到崗位名稱所在标簽,在屬性裡發現了該頁面的url:

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        又發現每一條招聘資訊都在<div class="el">…</div>裡:

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

是以通過如下xpath将url提取出來:

  1. //*[@id="resultList"]/div/p/span/a/@href  

    1.3 崗位資訊提取

        進入某一崗位具體資訊url,打開開發者選項,在資訊所在标簽上右擊,提取所需資訊的xpath。

  1. title = selector.xpath('/html/body/div[3]/div[2]/div[2]/div/div[1]/h1/text()')  
  2. salary = selector.xpath('/html/body/div[3]/div[2]/div[2]/div/div[1]/strong/text()')  
  3. company = selector.xpath('/html/body/div[3]/div[2]/div[2]/div/div[1]/p[1]/a[1]/text()')  
  4. place = selector.xpath('/html/body/div[3]/div[2]/div[2]/div/div[1]/p[2]/text()[1]')  
  5. exp = selector.xpath('/html/body/div[3]/div[2]/div[2]/div/div[1]/p[2]/text()[2]')  
  6. edu = selector.xpath('/html/body/div[3]/div[2]/div[2]/div/div[1]/p[2]/text()[3]')  
  7. num = selector.xpath('/html/body/div[3]/div[2]/div[2]/div/div[1]/p[2]/text()[4]')  
  8. time = selector.xpath('/html/body/div[3]/div[2]/div[2]/div/div[1]/p[2]/text()[5]')  
  9. comment = selector.xpath('/html/body/div[3]/div[2]/div[3]/div[1]/div/p/text()')  
  10. url = res.url  

    跑一遍看看,

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        咦,怎麼崗位要求這麼多null?點一個進去看看

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        嗯,<div>标簽下咋又出現了<div>,真是亂來(笑)。看來得換個法子了,把這個父<div>标簽下的中文全部帶走。這兒需要用到xpath的steing()函數。将上述方法改造,得到新的xpath:

  1. string(/html/body/div[3]/div[2]/div[3]/div[1]/div)  

    又能跑起來了,不過把該<div>裡一些其他資訊也帶進來了,比如崗位分類等。

二、一些細節

    2.1 編碼問題

        雖然沒有系統的學過編碼,但是在與不同網頁、不同的作業系統打交道的過程中也略知一二了。與

前些天爬過的智聯招聘

不同,前程無憂網頁用的是GBK編碼,是以需要注意編碼格式。而且還有一個小問題:

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

        對,報錯了,'\ufffd'無法被轉碼。從網上找來的解釋稱:

在通過GBK從字元串擷取位元組數組時,由于一個Unicode轉換成兩個byte,如果此時用ISO-8859-1或用UTF-8構造字元串就會出現兩個問号。

若是通過ISO-8859-1構造可以再通過上面所說的錯上加錯恢複(即再通過從ISO-8859-1解析,用GBK構造);

若是通過UTF-8構造則會産生Unicode字元"\uFFFD",不能恢複,若再通過String-UTF-8〉ByteArray-GBK〉String,則會出現雜碼,如a锟斤拷锟斤拷

        而在Unicode中,\uFFFD為占位符,當從某語言向Unicode轉化時,如果在某語言中沒有該字元,得到的将是Unicode的代碼"\uffffd"。

        針對這種情況,在打開檔案時可設定一個參數——errors:設定不同錯誤的處理方案,預設為 'strict',意為編碼錯誤引起一個UnicodeError。是以我們需要為該參數換一個值:ignore,當遇到編碼問題市直接無視。

  1. fp = open('51job.csv','wt',newline='',encoding='GBK',errors='ignore')  
  2. writer = csv.writer(fp)  
  3. '''''title,salary,company,place,exp,edu,num,time,comment,url'''  
  4. writer.writerow(('職位','薪水','公司','地區','經驗','學曆','數量','時間','要求','url'))  

    2.2 網頁結構問題

        電腦端的結構太多了…資料抓取率也低,代碼還得改改,還是移動适配又好看又好爬。

前程無憂爬蟲源碼及分析(一)一、網頁分析二、一些細節三、源代碼

三、源代碼

    因為在寫這篇部落格的時候,發現了一些之前沒發現的問題,并且有了優化的想法,是以就不把代碼貼過來了,就留github 吧,這些天再把這個項目改進一下。

    源代碼位址:

51job源代碼位址

    相關:

智聯招聘源代碼講解

繼續閱讀