談拉鉤網(wǎng)爬蟲的源碼分析勺鸦、爬蟲策略及問題解決
</br>
拉鉤網(wǎng)因其json格式的結構化數(shù)據(jù)并巍,
成為幾乎所有“爬者”必經(jīng)的練手場。
網(wǎng)上許多高手也分享了他們的經(jīng)驗和代碼换途。
上一篇我們簡單分析和展示了數(shù)據(jù)懊渡。
今天分幾塊來深入剖析拉鉤網(wǎng)爬蟲刽射。
</br>
一、一般爬取策略
多說無益剃执,以圖為例誓禁,簡要分析~
已經(jīng)盡量解析的詳細了,
一般爬取思路大概就是這樣忠蝗。
</br>
二 现横、爬蟲新思路
上面我們談了一般思路漓拾,相信很多爬友早就發(fā)現(xiàn)了阁最。然而拉勾網(wǎng)的爬蟲實在太多了,其反爬機制經(jīng)常變動骇两,爬取難度逐漸增加速种。
這一回我用上面的方法,結果返回這樣:
懵了低千。
最初以為是user_agent等問題配阵,又設隨機數(shù)還是不見好。估計是拉鉤修改了反爬機制示血。
試著模擬登錄棋傍,然而,F(xiàn)orm采用復雜的
暗文密碼难审,成功嚇退小白瘫拣。
最后重新構造URL,get方式解決
那我是怎么做到的呢告喊?
最初是盯著network發(fā)呆麸拄,后面留意到URL后面的needAddtionalResult=false
'needAdditionalResult',額外添加?好吧黔姜,那就隨便加點東西拢切。加什么好呢?
那就隨便這個好咯秆吵,然后返回這樣
直接構造URL淮椰,哈哈我簡直聰明~ (_)!
純屬瞎撞,第二天想到onenote中一筆記:
我們用form提交的表單纳寂,其實最終會變成上面那樣的格式主穗。(用不用post基本差不多)
get方式獲取數(shù)據(jù),加個cookies即可烈疚。
代碼如下黔牵,還是放個完整版:
# !usr/bin/env python
# --coding:utf-8 --
author='WYY'
date='2017.03.29'
#實戰(zhàn)小項目:爬取拉鉤網(wǎng)并作小型數(shù)據(jù)分析
import requests
import json
import xlwt
import time
import random
class Spider():
def __init__(self):
self.keyword=raw_input(u'請輸入職位:')
#獲取數(shù)據(jù)
def getData(self,url):
user_agents=['Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20130406 Firefox/23.0',
'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:18.0) Gecko/20100101 Firefox/18.0',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533+ \(KHTML, like Gecko) Element Browser 5.0',
'IBM WebExplorer /v0.94', 'Galaxy/1.0 [en] (Mac OS X 10.5.6; U; en)',
'Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)',
'Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14',
'Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) \Version/6.0 Mobile/10A5355d Safari/8536.25',
'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) \Chrome/28.0.1468.0 Safari/537.36',
'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; TheWorld)']
index=random.randint(0, 9)
user_agent=user_agents[index]
headers={'User_agent':user_agent,
'cookie':'user_trace_token=20170328171202-9af479cf-1396-11e7-a59b-525400f775ce; LGUID=20170328171202-9af4825b-1396-11e7-a59b-525400f775ce; showExpriedIndex=1; showExpriedCompanyHome=1; showExpriedMyPublish=1; hasDeliver=0; index_location_city=%E5%85%A8%E5%9B%BD; JSESSIONID=9E6568091D64AB8515B8E70D354BC10D; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1490692322,1490704679,1490704945,1490746875; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1490748769; _ga=GA1.2.407060577.1490692322; LGSID=20170329082118-a0c3b596-1415-11e7-a659-525400f775ce; LGRID=20170329085249-080c8c0b-141a-11e7-9574-5254005c3644; SEARCH_ID=9bc41c0071964f8c804e9f67a0a5c073'}
html=requests.get(url,headers=headers)
data=json.loads(html.text)
return data
#獲取職位信息并存入列表
def getPosition(self,url):
data=self.getData(url)
position=data['content']['positionResult']['result']
po_list=[]
if position is not None:
for i in position:
main=[]
main.append(i['companyFullName'])
main.append(i['financeStage'])
main.append(i['positionName'])
main.append(i['positionLables'])
main.append(i['salary'])
main.append(i['city'])
main.append(i['education'])
main.append(i['workYear'])
main.append(i['jobNature'])
main.append(i['createTime'])
po_list.append(main)
return po_list
#獲取數(shù)據(jù),存入一個大的list
def saveDetail(self):
self.New=int(raw_input(u'請輸入要爬取的頁數(shù):'))
self.time=time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
print u'\n本地時間:',self.time
print u'\n開始采集數(shù)據(jù)...'
container=[]
for page in range(1,self.New+1):
self.url='https://www.lagou.com/jobs/positionAjax.json?px=new&first=true&pn='+str(page)+'&kd='+str(self.keyword)
po_list=self.getPosition(self.url)
time.sleep(3)
print u'第',page,u'項完畢'
container=container+po_list
return container
#將數(shù)據(jù)存入excel
def saveAll(self):
book=xlwt.Workbook()
sheet =book.add_sheet(str(self.keyword), cell_overwrite_ok=True)
container=self.saveDetail()
print u'\n采集完畢'
print u'\n準備將數(shù)據(jù)存入表格...'
heads=[u'公司全名', u'融資狀況', u'工作名稱', u'標簽', u'薪酬', u'城市', u'學歷要求',u'經(jīng)驗要求',u'工作類型',u'數(shù)據(jù)創(chuàng)建時間']
ii=0
for head in heads:
sheet.write(0,ii,head)
ii+=1
i=1
for list in container:
j=0
for one in list:
sheet.write(i, j, one)
j+=1
i+=1
book.save(str(self.keyword)+'.xls')
print u'\n錄入成功!'
spider=Spider()
spider.saveAll()
有盆友可能會問了:隨便設個New簡單,
可怎么獲得最大頁數(shù)呀爷肝?
好吧猾浦,我坦白:手動試出來的
(先大概定個范圍陆错,每次取中間數(shù),試個5金赦、6次就出來了音瓷,也簡單)
其實我也想過用個if position==[]或者if position=None就break結束循環(huán),可卻不知道為什么行不通夹抗,真是怪了绳慎。可是如果先遍歷獲取最大頁數(shù)漠烧,后面又得遍歷一次杏愤,抓取次數(shù)多了,難保不被網(wǎng)站發(fā)現(xiàn)被封IP已脓。
只好這樣了(這里有待改進)珊楼。
可以看到,整個爬取過程僅用request度液、json厕宗、xlwt等幾個關鍵庫。
總結爬蟲新思路:
直接用pn構造URL實現(xiàn)翻頁堕担,加上cookies偽裝成瀏覽器已慢,get方式獲取####
是不是hin簡單_
</br>
</br>
三、突破IP限制
爬蟲爬到一半時霹购,又出了幺蛾子
再上去一看
原來IP被封 了佑惠,難怪。
(這樣的情況還是第一次)
查了一下厕鹃,網(wǎng)上有說可以用代理池兢仰。
可又得設計爬蟲抓代理,不免麻煩剂碴。
后面想到之前爬圖片網(wǎng)站時把将,注冊的vpn。
vpn不就是代理么忆矛,還可各種線路隨便切換察蹲,哈哈哈我簡直聰明~ (_)!
查了一點資料催训,有關反反爬及突破IP限制洽议,
總結幾個方法:
1、設置代理池(可以網(wǎng)上抓代理漫拭,不過穩(wěn)定性是問題)
2亚兄、使用vpn(原理同上)
3、分布式抓炔勺ぁ(這個我也沒學到>_<)
4审胚、設置等待時間匈勋,放慢抓取速度
5、修改請求頭( user_agent膳叨、cookies)
6洽洁、模擬登錄
當然,最有效當屬123
</br>
四菲嘴、數(shù)據(jù)分析 — 一些感悟
工具用的BDP(奇妙的分析軟件)饿自。
詞云用的標簽一欄,直接丟BDP自動生成龄坪。
后面發(fā)現(xiàn)有欠妥當,因為有些數(shù)據(jù)標簽那一塊什么都沒有城豁。對幾個維度進行了粗略分析抄课,效果還不錯,比如這樣
細心的盆友可能又發(fā)現(xiàn)了雳旅,怎么沒有C# 跟磨?
其實攒盈,我也想的。型豁。僵蛛。
如圖所示搜C#時,會搜出許多C\C++的內(nèi)容迎变,亂而麻煩,只好舍棄驼侠。
第一次親自參與3萬多數(shù)據(jù)的分析谆吴,新鮮。后面一想句狼,其實爬蟲程序不過只是個采集數(shù)據(jù)的手段(或者說工具)。
關鍵還是具體的數(shù)據(jù)分析以及應用轉化 單單抓個幾十萬爛在excel表里腻菇,沒有任何意義苫拍。
</br>
</br>
五绒极、源碼剖析 — 新發(fā)現(xiàn)
爬過拉鉤的朋友肯定會發(fā)現(xiàn)一個現(xiàn)象:
打開一個頁面蔬捷,過一陣子再重新打開
發(fā)現(xiàn)不再是原來頁面了,變成了別的周拐。
可是真的是這樣么?
放幾個圖
get到了么?
只是順序變了下勾给,內(nèi)容是不變的。
換湯不換藥脓钾,特么全是 障眼法 白!4肥唷!
難為了拉鉤的前端工程師 [攤手]
看來也只有我這種** 既無聊又聰明又有耐心**的人才會發(fā)現(xiàn)了
</br>
這個小項目我也放到了github上了:https://github.com/LUCY78765580/Python-web-scraping/blob/master/LaGou/LaGou.py
最后總結本篇 幾個要點:
1谨胞、拉鉤爬蟲一般方法:Post模擬瀏覽器
2长已、新思路:get方式+cookies偽裝,
直接pn構建URL實現(xiàn)翻頁和遍歷
3康聂、突破IP限制(各種方法)
4胞四、程序不過工具,關鍵策略辜伟、數(shù)據(jù)分析
5脊另、源碼剖析新發(fā)現(xiàn):頁面原來障眼法
為了對得起這個"深入剖析"的標題约巷,小白已經(jīng)盡她最大的努力啦~
(學習爬蟲才一月左右,文章可能有不足之處踩麦,個中出入還請各位大神多多指正)
本篇就是這樣啦~