Python | 爬蟲-數據分析實戰Ⅰ

「Talk is cheap,Show me the code.」翻譯為中文是「廢話少說,放碼過來。」我覺得可謂信達雅。
在編程之路上,實踐的重要性無可比擬。這也是很多同學感覺學了很多,但還是不會寫代碼的原因;也是很多有意轉行的人士,自學了大半年,仍不見起色的緣故。
leoxin在知識星球發起一項活動:目標是爬取拉鉤網的招聘信息以及鏈家的房產信息,然後對數據進行清洗和存儲,並分析其數據下的價值,最後用可視化的形式表現出來。
我覺得難度適中,循序漸進,對於不同身份角色的學習人群都大有裨益。
下面我來寫一寫在第一階段的一些學習操作總結和感受。
爬蟲
構思/準備部分
首先打開
找工作-互聯網招聘求職網-拉勾網
我初步選擇的是Java-上海

Step1
打開瀏覽器開發者工具,觀察Network部分的內容,首先點進Doc部分,看看伺服器給我們返回了哪些文本內容。
在Preview預覽中,我們可以看到,大部分都是一些公共視圖框架和公共JS代碼,沒有核心數據。
那麼這時我們就應該猜測,網站可能是首先渲染一個公共框架,然後再通過Ajax發送請求去獲得數據,再在頁面上顯示獲取的數據。

Step2
通過Step1的思考和猜測,大致確定了數據是非同步獲取的。做過一點web的應該都想得到這一點,因為即使是反爬,也要按照基本法啊!應該不會使用多麼多麼匪夷所思的黑科技(如果真的出現了,那是我太菜了的原因(っ °Д °;)っ)
這時點開XHR按鈕,XHR全稱XMLHttpRequest,有什麼作用呢?Ajax通過XMLHttpRequest對象發出HTTP請求,得到伺服器返回的數據。
通過預覽我們可以發現,我們需要的數據都出現在positionAjax請求下返回的數據中,參見content-positionResult-result中。
那麼該如何偽造請求?
點進Headers,首先發現 RequestMethod的值是 POST,確定了我們提交請求的方式。然後看看 RequestHeaders中的欄位。
發現有好多條。
Accept:application/json, text/javascript,*/*; q=0.01Accept-Encoding:gzip, deflate, brAccept-Language:zh-CN,zh;q=0.9Connection:keep-aliveContent-Length:23Content-Type:application/x-www-form-urlencoded; charset=UTF-8Cookie:XXXHost:www.lagou.comOrigin:https://www.lagou.comReferer:https://www.lagou.com/jobs/list_Java?px=default&city=%E4%B8%8A%E6%B5%B7User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36X-Anit-Forge-Code:0X-Anit-Forge-Token:NoneX-Requested-With:XMLHttpRequest
通過篩選,我們選取其中有用的幾條,構建自己的請求頭。(那麼怎麼知道哪些是有用的呢?首先篩除語言,編碼之類的,這些的影響一般都是比較小的;接著在剩下的欄位中進行嘗試,等以後有經驗了,自然能準確選取有價值的欄位)
由於是POST的請求方式,那麼勢必會向伺服器提交一些數據,可以看到表單信息:
first:truepn:1kd:Java


實現/代碼部分
Step1
在進行上述分析後,基本已經準備得差不多了。這時可以先簡單構建一下我們的Proxy類。
classProxy():def __init__(self):self.MAX=5#最大嗅探次數self.headers={"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36","Referer":"https://www.lagou.com/jobs/list_Java?px=default&city=%E4%B8%8A%E6%B5%B7","X-Anit-Forge-Code":"0","X-Anit-Forge-Token":"None","X-Requested-With":"XMLHttpRequest"}def getPage(self,url,data):FAILTIME=0#訪問失敗次數try:result=requests.post(url,headers=self.headers,data=data)result.encoding ="utf-8"return resultexcept:FAILTIME+=1if FAILTIME==self.MAX:print("訪問錯誤")return
上文中提到,發現Ajaxposition返回的content-positionResult-result數據,數據格式是一個數組裡有15條數據,每條數據的格式是一個字典,具體如下:
adWord:9appShow:0approve:1businessZones:["唐鎮","唐鎮","曹路","曹路"]city:"上海"companyFullName:"招商銀行股份有限公司信用卡中心"companyId:6796companyLabelList:["金融科技銀行","技術創新驅動","奮鬥獨立改變","一年兩次調薪"]companyLogo:"i/image2/M00/25/D7/CgoB5lodmL2AJHxrAABieRjcJjU514.png"companyShortName:"招商銀行信用卡中心"companySize:"2000人以上"createTime:"2018-03-09 09:14:30"deliver:0district:"浦東新區"education:"本科"explain:nullfinanceStage:"上市公司"firstType:"開發/測試/運維類"formatCreateTime:"09:14發布"gradeDescription:nullhitags:nullimState:"today"industryField:"移動互聯網,金融"industryLables:[]isSchoolJob:0jobNature:"全職"lastLogin:1520581074000latitude:"31.247248"linestaion:nulllongitude:"121.673868"pcShow:0plus:nullpositionAdvantage:"五險一金,職位晉陞,各類補貼"positionId:2762378positionLables:["項目管理","j2ee","架構"]positionName:"Java技術經理"promotionScoreExplain:nullpublisherId:73936resumeProcessDay:1resumeProcessRate:100salary:"30k-50k"score:0secondType:"管理崗"stationname:nullsubwayline:nullworkYear:"5-10年"
可見返回了大量的信息,那麼我們如何去獲得這些數據?此時可以寫一個簡單的Job類:
classJob:def __init__(self):self.datalist=[]def getJob(self,url,data):p=Proxy()result=p.getPage(url,data)result.encoding ="utf-8"result_dict=result.json()try:job_info = result_dict[content][positionResult][result]for info in job_info:print(info)return job_infoexcept:print("發生解析錯誤")
使用getJob方法獲取的是所有的信息,這其實是不必要的,應該也有所選擇,否則將給自己帶來壓力,對於後續步驟也將帶來不便。
Step2
此時,一個簡單的爬蟲已經編寫得差不多了,我們可以進行測試一下。
編寫主函數if __name__ ==__main__:url="https://www.lagou.com/jobs/positionAjax.json?px=default&city=%E4%B8%8A%E6%B5%B7&needAddtionalResult=false&isSchoolJob=0"job =Job()all_page_info=[]for x in range(1,31):data ={"first":"false","pn": x,"kd":"Java"}current_page_info=job.getJob(url,data)all_page_info.extend(current_page_info)print("第%d頁已經爬取成功"%x)time.sleep(5)
可以看到控制台顯示:

總結
到這裡,一個簡單的爬蟲已經編寫完畢了,數據以json格式返回,似乎已經大功告成。而事實是,對於為後面的數據分析做準備工作還差得遠,對於爬取海量數據,下面有幾點思考。
- 拉鉤網對於同一ip的大量請求行為肯定會進行封禁,所以需要準備代理池。
- 為了實現高自動化,需要對一系列可能出現的異常情況進行處理,斷點處理,確保程序不掛。
- 為了提高效率,加入多線程。
- 數據持久化,在持久化之前需要先進行清洗。
- ......
針對以上問題,需要進一步學習。
公眾號:「果核里的圖靈」
一條小白的探索之路
推薦閱讀:
※怎樣用五十行Python代碼自造比特幣?
※P 站非會員查看人氣作品
※關於 "ImportError: cannot import name cbook" 的解決
※Pipeline語法支持,還是flowpython
