寫在前面:
拉勾網(wǎng)數(shù)據(jù)爬取是一個蠻經(jīng)典的爬蟲案例 架曹,由于被頻繁被爬取的原因 莫杈,網(wǎng)站經(jīng)過不斷更新 ,加入了一些反爬技術(shù) 挎挖。例如:參數(shù)的加密 这敬、AJAX異步加載JSON數(shù)據(jù) 。對于入門爬蟲的新手來說 蕉朵,還是有一些困難 崔涂。這里用到selenium和post請求兩種方式解析網(wǎng)頁 ,希望可以幫到你們 始衅。
分析網(wǎng)頁:
這里我們以 數(shù)據(jù)分析 該職位為例 : 鏈接
數(shù)據(jù)在網(wǎng)頁一般會分為兩種加載方式 : 在原網(wǎng)頁內(nèi)與不在原網(wǎng)頁內(nèi) 冷蚂。判斷的方法可以復(fù)制網(wǎng)頁內(nèi)要爬取的一些數(shù)據(jù) ,然后右擊網(wǎng)頁 ——查看源代碼 觅闽, 看一看是否可以找到 帝雇。:
按ctrl + f 輸入復(fù)制的的數(shù)據(jù)發(fā)現(xiàn)并沒有存在原網(wǎng)頁內(nèi) 。
那么可以推斷出 蛉拙, 我們要爬取的數(shù)據(jù)是通過AJAX異步加載JSON數(shù)據(jù)到網(wǎng)頁的 尸闸。
那我們需要在網(wǎng)頁后臺找到那個json數(shù)據(jù) ,我用的是chrom瀏覽器 孕锄,右擊 ——檢查 :
在picture_1中 選擇 network --- XHR (如果沒有數(shù)據(jù)的話吮廉,重新加載一下網(wǎng)頁) ,可以在左邊看到四個json鏈接 畸肆。因為我們要爬取的是職位 宦芦,很快我們就可以確定目標(biāo)url ,picture_3驗證了準(zhǔn)確性 :
在picture_3中我們可以很清楚的看見這是一個json格式的數(shù)據(jù) 轴脐,通過分析 调卑,可以找到數(shù)據(jù)在result下面 :
通過對比picture_5發(fā)現(xiàn)就是我們要爬取的數(shù)據(jù) 。
編寫爬蟲:
https://www.lagou.com/jobs/positionAjax.json?px=default&city=%E8%8B%8F%E5%B7%9E&needAddtionalResult=false
我們要解析的url在Headers中可以看出是post請求 大咱。
下面我們構(gòu)造headers :
my_headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
'Host':'www.lagou.com',
'Referer':'https://www.lagou.com/jobs/list_{}?labelWords=sug&fromSearch=true&suginput='.format(position_id),
'X-Anit-Forge-Code':'0',
'X-Anit-Forge-Token': 'None',
'X-Requested-With':'XMLHttpRequest'
}
其中的referer可以看到 恬涧,我用format函數(shù)加入了一個參數(shù) ,便于爬取不同城市的數(shù)據(jù) 碴巾, 如果你只打算爬取一個城市這里可以不加 溯捆,只使用瀏覽器上帶的參數(shù) 。
提交的 data:
my_data = {
'first': 'true',
'pn':num,
'kd':position
}
從picture中可以看出需要post數(shù)據(jù)主要有三個 厦瓢,其中 pn:為頁碼數(shù) 提揍,kd:為職位名稱 。因此 煮仇,我將這兩個參數(shù)的值設(shè)置為變量 num和position 劳跃,便于接下來的post頁碼和不同職位的實現(xiàn) 。
def get_json(url,num,position,position_id):
#print(position)
'''''從網(wǎng)頁獲取JSON,使用POST請求,加上頭部信息'''
my_headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
'Host':'www.lagou.com',
'Referer':'https://www.lagou.com/jobs/list_{}?labelWords=sug&fromSearch=true&suginput='.format(position_id),
'X-Anit-Forge-Code':'0',
'X-Anit-Forge-Token': 'None',
'X-Requested-With':'XMLHttpRequest'
}
my_data = {
'first': 'true',
'pn':num,
'kd':position}
res = requests.post(url, headers = my_headers, data = my_data)
res.raise_for_status()
res.encoding = 'utf-8'
# 得到包含職位信息的字典
page = res.json()
return page
這是帶headers和data完整的post請求 浙垫, 其中函數(shù)由四個參數(shù) 刨仑,url為剛剛我們找出的那個鏈接 强重。num是頁碼 ,這里我們先設(shè)置為起始頁碼1 贸人。position為職位名稱 间景,position_id為職位代號 。我們可以從headers的referen中看出 :https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90?labelWords=sug&fromSearch=true&suginput=shujufenxi 在list_到艺智?中的職位名稱被加密出現(xiàn)倘要, 所以我構(gòu)造了一個字典 :
def getCity():
return [
{"蘇州":"%E8%8B%8F%E5%B7%9E"},
{"深圳":"%E6%B7%B1%E5%9C%B3"},
{"上海":"%E4%B8%8A%E6%B5%B7"},
{"杭州":"%E6%9D%AD%E5%B7%9E"},
{"南京":"%E5%8D%97%E4%BA%AC"},
]
def getLanguage():
return [
#"python",
{"數(shù)據(jù)分析":"%E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90"},
{"圖像處理":"%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86"},
{"":""},
{"":""},
{"":""},
]
將需要爬取的城市 、職位所對應(yīng)的加密碼一一對應(yīng) 十拣。
get_json函數(shù)返回了json數(shù)據(jù) 封拧,包括了職位總數(shù) ,這樣我們就可以構(gòu)造一個函數(shù) 夭问,而且拉勾網(wǎng) 一頁最多顯示15個職位 泽西,計算出我們爬取職位的總頁數(shù)了 。
def get_page_num(count):
'''''計算要抓取的頁數(shù)'''
# 每頁15個職位,向上取整
res = math.ceil(count/15)
# 拉勾網(wǎng)最多顯示30頁結(jié)果
if res > 30:
return 30
else:
return res
計算出頁數(shù)之后 缰趋, 我們就可以通過一個循環(huán) 捧杉,帶著可變參數(shù)反復(fù)post數(shù)據(jù):
for n in range(1,num+1):
# 對每個網(wǎng)頁讀取JSON, 獲取每頁數(shù)據(jù)
page = get_json(url,n,position,position_id)
try:
jobs_list = page['content']['positionResult']['result']
except:
continue
page_info = get_info_to_mongodb(jobs_list)
res_list.extend(page_info)
查看返回的結(jié)果 ,這里我通過構(gòu)造一個含有dict的list便于存入mongodb 秘血,看個人需求 :
通過看原網(wǎng)頁的數(shù)據(jù) 味抖, 我們發(fā)現(xiàn)數(shù)據(jù)已經(jīng)被爬取先來了 一共19個職位 ,共分兩頁