最近真的好累啊,心累,很多事想快點做完,但是每個人都有拖延癥,疊加到我這一層都不知道拖延到什么時候了。好多事總想著要是可以我自己全部搞定就好了。為什么有些人就是不能早定啟動計劃呢?心累。
寫代碼吧,這是唯一能“消遣”的方式了。
看到傳智播客課件上有給學員留一些爬蟲作業,嘿嘿,自己決定做做看。
今天做 “爬取拉勾網爬蟲工程師職位”。
更新:元旦快樂!元旦終于能過個雙休,好好陪姐姐和麻麻,順便學學爬蟲吧(▽)
第一次爬動態頁面,一時不知道該怎么下手,好在拉勾是爬蟲工程師常用來練手的地方,攻略挺多,哈哈。整體思路如下:
- 構造并獲取請求
- 解析所需要的數據
- 以Excel形式保存在本地。
1.構造并獲取請求:
由于拉勾采用異步加載技術,之前用的很簡單的獲取靜態頁面的方式就不行了。需要通過抓包獲得數據包,再從數據包里解析所需要的數據。
打開拉勾網,查找關鍵字“爬蟲工程師”,打開谷歌瀏覽器賢者模式-network,如下:
監聽器中看到的數據有很多,css, png, js......我們需要的數據包均不在以上列出來的類型里,我們的關注點主要是在xhr類型的文件中,關于什么是xhr本渣也不是很懂,只知道它是Ajax對象,而Ajax是目前前端廣泛應用的一種技術,關于Ajax的更多信息暫不做詳細了解。
過濾xhr類型的數據流,我們可以直接選擇 >>>谷歌瀏覽器-Network-XHR獲取:
這就獲得了所有的XHR文件,這時候我們看看獲得的是不是需要的數據,逐個點開-Preview:
這里我點開第一個數據包,其他的類似操作。可以看到,這個數據包里確實包含我們需要的信息,那問題來了,我要如何才能拿到這個數據包呢?
一開始我哧吭哧吭地采用之前很簡單的傳入UA, Cookies, 然后
requests.get(url, header = headers, cookies = cookies)
甚至連瀏覽器的監聽都沒看,這樣拿到的只是拉勾網首頁的靜態頁面上的數據,根本拿不到想要的數據。于是仔細看瀏覽器的監聽,之前抓到的XHR數據包的Headers如下:
關注點有兩個:
Request URL和Request Method,這里對應可以知道獲取這個數據包的鏈接以及方法。
繼續往下看:
form data是我們發起post時必要的參數
然后我又哧吭哧吭地開始碼代碼了:
# -*- coding: utf-8 -*-
import requests
def get_js(page, job_name):
url = 'https://www.lagou.com/jobs/positionAjax.json?city=%E5%B9%BF%E5%B7%9E&needAddtionalResult=false&isSchoolJob=0'
headers = {
'Cookie': "user_trace_token=20171218074035-ade4d2dc-e383-11e7-9def-525400f775ce; LGUID=20171218074035-ade4d6be-e383-11e7-9def-525400f775ce; showExpriedIndex=1; showExpriedCompanyHome=1; showExpriedMyPublish=1; hasDeliver=0; JSESSIONID=ABAAABAACBHABBIC9F4C6647BF37CF4EDC0DB33759D67C9; PRE_UTM=; PRE_HOST=; PRE_SITE=; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2F; _putrc=21717327F1B053B4; _gid=GA1.2.1846682322.1514773610; _ga=GA1.2.2062218679.1513554042; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1513554041,1514544070,1514608259,1514773610; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1514773651; LGSID=20180101102652-3a420853-ee9b-11e7-b956-525400f775ce; LGRID=20180101102732-52342eb9-ee9b-11e7-9fc4-5254005c3644; SEARCH_ID=7275bd67bfd7481fb9033dab8abc11f3; index_location_city=%E5%B9%BF%E5%B7%9E",
'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
}
data = {'first': 'true',
'pn': page,
'kd': job_name
}
response = requests.post(url, data, headers=headers)
print(response.text)
結果:
其實在瀏覽器中直接輸入網址:
url = 'https://www.lagou.com/jobs/positionAjax.json?city=%E5%B9%BF%E5%B7%9E&needAddtionalResult=false&isSchoolJob=0'
結果:
也是一樣的。小白如我黑人問號臉了很久,開始找答案,偶然間看到XX培訓機構的視頻中提到過的一個點,瀏覽器header中referer防止重定向,其實自己之前也聽到過referer,它是規定了當前的鏈接只能由某一個鏈接轉到,不能直接跳轉;不過到這里,才切實體會到其在反爬中的作用。
至此,整體的獲取數據的代碼如下:
# -*- coding: utf-8 -*-
# https://www.lagou.com/jobs/list_python?px=default&city=%E5%8C%97%E4%BA%AC#filterBox
import requests,json,xlwt
def get_js(page, job_name):
url = 'https://www.lagou.com/jobs/positionAjax.json?city=%E5%B9%BF%E5%B7%9E&needAddtionalResult=false&isSchoolJob=0'
headers = {
'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
'Accept': "application/json, text/javascript, */*; q=0.01",
'Accept-Encoding': "gzip, deflate, br",
'Accept-Language': "zh-CN,zh;q=0.9",
'Connection': "keep-alive",
'Content-Length': "82",
'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8",
'Cookie': "user_trace_token=20171218074035-ade4d2dc-e383-11e7-9def-525400f775ce; LGUID=20171218074035-ade4d6be-e383-11e7-9def-525400f775ce; showExpriedIndex=1; showExpriedCompanyHome=1; showExpriedMyPublish=1; hasDeliver=0; JSESSIONID=ABAAABAACBHABBIC9F4C6647BF37CF4EDC0DB33759D67C9; PRE_UTM=; PRE_HOST=; PRE_SITE=; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2F; _putrc=21717327F1B053B4; _gid=GA1.2.1846682322.1514773610; _ga=GA1.2.2062218679.1513554042; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1513554041,1514544070,1514608259,1514773610; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1514773651; LGSID=20180101102652-3a420853-ee9b-11e7-b956-525400f775ce; LGRID=20180101102732-52342eb9-ee9b-11e7-9fc4-5254005c3644; SEARCH_ID=7275bd67bfd7481fb9033dab8abc11f3; index_location_city=%E5%B9%BF%E5%B7%9E",
'Host': "www.lagou.com",
'Origin': "https://www.lagou.com",
'Referer': "https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E7%88%AC%E8%99%AB%E5%B7%A5%E7%A8%8B%E5%B8%88?labelWords=&fromSearch=true&suginput=",
'User-Agent': "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
'X-Anit-Forge-Code': "0",
'X-Anit-Forge-Token': "None",
'X-Requested-With': "XMLHttpRequest",
'Cache-Control': "no-cache",
'Postman-Token': "2311c5f1-5e34-dc58-d976-e26148708846"
}
data = {'first': 'true',
'pn': page,
'kd': job_name
}
response = requests.post(url, data, headers=headers)
2.解析數據
剛剛我們從拉勾上獲取了響應的數據包,這里我們還是要回去看瀏覽器中捕捉到的信息,谷歌瀏覽器-NETWORK-XHR-第一個XHR包-Preview:
我們要獲得的數據,對應的路徑為:content-positionResult-result-0(一直到14)
這里0-14可以點開看,就是每個職位的具體信息:
這些json類型的數據,解析起來很方便,類似于鍵值對的形式,只要我們取其中的鍵就能獲取值。不過首先我們需要對上面get_js(page, job_name)函數做點補充,讓它直接拿到json數據。直接上代碼吧
def parse_js(json_info):
#定義一個空列表,用以存放我們想要提取的數據
info_list = []
for info in json_info:
#將要的數據通通放到空列表中
info_list.append(info['companyFullName'])
info_list.append(info['companyShortName'])
info_list.append(info['companyId'])
info_list.append(info['positionName'])
info_list.append(info['salary'])
info_list.append(info['workYear'])
info_list.append(info['education'])
info_list.append(info['industryField'])
info_list.append(info['financeStage'])
info_list.append(info['companySize'])
info_list.append(info['city'])
return info_list
然后將數據保存下來就行了。代碼如下:
def main():
# 先定義一個空列表,這個列表才是我們真正會寫進Excel的列表
real_list = []
# 這里寫入 Excel 我用 xlwt 這個庫
book = xlwt.Workbook()
sheet1 = book.add_sheet('crwalerposition.xls', cell_overwrite_ok=True)
# 先做個表頭
proformlist = ['公司全稱', '公司簡稱', '公司代號', '職位名稱', '薪水區間', '工作年限', '教育程度', '行業性質', '目前狀況', '公司規模', '上班地點']
j = 0
for pro in proformlist:
sheet1.write(0, j, pro)
j += 1
i_list = []
page = 1
while page < 26:
i_list = i_list + parse_js(get_js(str(page), "爬蟲工程師"))
print("得到第%r頁數據" % page)
page += 1
# time.sleep(5)
# print(i_list)
for k in range(0, len(i_list), 11):
# 將大列表以11為切割的單位,切割成小列表,方便后面操作。這里感覺有點吃力不討好了。。。
new_list = i_list[k: k + 11]
real_list.append(new_list)
m = 1
for list in real_list:
n = 0
for info in list:
sheet1.write(m, n, info)
n += 1
print("第%r家公司數據錄入完畢" %m )
m += 1
print("搞定收工!" )
book.save('python_job_info_in_all.xls')
main()
關于保存,我摸了很久。一開始的思路是,將"保存"這件事封裝成一個函數,這樣,獲取,解析和保存都能單獨作為一個函數,再編寫一個main函數,用for循環遍歷所有的20多個頁面將,并對以上函數調用就OK。然而當我執行代碼的時候,數據總是只能拿到兩頁數據而已。
為什么只能拿到兩頁數據?明明有二十幾頁的呀?這時候新手的不自信就出現了:肯定是我的代碼出現了某種問題,而且這個問題應該在外人看來很簡單。我仔細把重頭代碼看幾遍,試著將解析的列表打印出來看,顯示確實只有那么多數據,排除是寫入文件的問題。
那就是獲取數據出現問題咯?被ban了?爬取太快?可是我每一次重新跑代碼都可以得到數據呀,數據也不多不少就只有那么多,兩頁。我用了隨機ua, time.sleep,差點就上代理ip了,結果還是沒,卵,用!!還是偶然的機會,再回去看拉勾網的時候才注意到,我爬的數據和我看的頁面根本不一樣!!尼瑪坑爹,不知道什么時候手抖把查詢城市選為不限了,而一開始我只打算爬取廣州地區的數據的!!廣州本地的爬蟲工程師職位確實只有兩頁。。。。。。(可憐== 本來自己就菜,工作機會還這么少。。。)
下面是全部完整代碼:
# -*- coding: utf-8 -*-
# https://www.lagou.com/jobs/list_python?px=default&city=%E5%8C%97%E4%BA%AC#filterBox
import requests,json,xlwt
import time,random
def get_js(page, job_name):
url = 'https://www.lagou.com/jobs/positionAjax.json?px=default&needAddtionalResult=false&isSchoolJob=0'
#隨機ua列表
UA_list = ["Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
"Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 (KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
"Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 (KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6"
]
UA = random.choice(UA_list)
#構造請求參數
headers = {
'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
'Accept': "application/json, text/javascript, */*; q=0.01",
'Accept-Encoding': "gzip, deflate, br",
'Accept-Language': "zh-CN,zh;q=0.9",
'Connection': "keep-alive",
'Content-Length': "82",
'Content-Type': "application/x-www-form-urlencoded; charset=UTF-8",
'Cookie': "user_trace_token=20171218074035-ade4d2dc-e383-11e7-9def-525400f775ce; LGUID=20171218074035-ade4d6be-e383-11e7-9def-525400f775ce; showExpriedIndex=1; showExpriedCompanyHome=1; showExpriedMyPublish=1; hasDeliver=0; JSESSIONID=ABAAABAACBHABBIC9F4C6647BF37CF4EDC0DB33759D67C9; PRE_UTM=; PRE_HOST=; PRE_SITE=; PRE_LAND=https%3A%2F%2Fwww.lagou.com%2F; _putrc=21717327F1B053B4; _gid=GA1.2.1846682322.1514773610; _ga=GA1.2.2062218679.1513554042; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1513554041,1514544070,1514608259,1514773610; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1514773651; LGSID=20180101102652-3a420853-ee9b-11e7-b956-525400f775ce; LGRID=20180101102732-52342eb9-ee9b-11e7-9fc4-5254005c3644; SEARCH_ID=7275bd67bfd7481fb9033dab8abc11f3; index_location_city=%E5%B9%BF%E5%B7%9E",
'Host': "www.lagou.com",
'Origin': "https://www.lagou.com",
'Referer': "https://www.lagou.com/jobs/list_%E6%95%B0%E6%8D%AE%E7%88%AC%E8%99%AB%E5%B7%A5%E7%A8%8B%E5%B8%88?labelWords=&fromSearch=true&suginput=",
'User-Agent': UA,
'X-Anit-Forge-Code': "0",
'X-Anit-Forge-Token': "None",
'X-Requested-With': "XMLHttpRequest",
'Cache-Control': "no-cache",
'Postman-Token': "2311c5f1-5e34-dc58-d976-e26148708846"
}
data = {'first': 'true',
'pn': page,
'kd': job_name
}
response = requests.post(url, data, headers=headers)
json_info = response.json()['content']['positionResult']['result']
return json_info #此處return的是一個列表類型
def parse_js(json_info):
#定義一個空列表,用以存放我們想要提取的數據
info_list = []
for info in json_info:
#將要的數據通通放到空列表中
info_list.append(info['companyFullName'])
info_list.append(info['companyShortName'])
info_list.append(info['companyId'])
info_list.append(info['positionName'])
info_list.append(info['salary'])
info_list.append(info['workYear'])
info_list.append(info['education'])
info_list.append(info['industryField'])
info_list.append(info['financeStage'])
info_list.append(info['companySize'])
info_list.append(info['city'])
return info_list
def main():
# 先定義一個空列表,這個列表才是我們真正會寫進Excel的列表
real_list = []
# 這里寫入 Excel 我用 xlwt 這個庫
book = xlwt.Workbook()
sheet1 = book.add_sheet('crwalerposition.xls', cell_overwrite_ok=True)
# 先做個表頭
proformlist = ['公司全稱', '公司簡稱', '公司代號', '職位名稱', '薪水區間', '工作年限', '教育程度', '行業性質', '目前狀況', '公司規模', '上班地點']
j = 0
for pro in proformlist:
sheet1.write(0, j, pro)
j += 1
i_list = []
page = 1
while page < 26:
i_list = i_list + parse_js(get_js(str(page), "爬蟲工程師"))
print("得到第%r頁數據" % page)
page += 1
# time.sleep(5)
# print(i_list)
for k in range(0, len(i_list), 11):
# 將大列表以11為切割的單位,切割成小列表,方便后面操作。這里感覺有點吃力不討好了。。。
new_list = i_list[k: k + 11]
real_list.append(new_list)
m = 1
for list in real_list:
n = 0
for info in list:
sheet1.write(m, n, info)
n += 1
print("第%r家公司數據錄入完畢" %m )
m += 1
print("搞定收工!" )
book.save('python_job_info_in_all.xls')
main()
總結:
1.異步請求,抓包要學會刪選。今天試著抓一些淘寶的評論,哇,那數據簡直嘩嘩的,都不知道自己要的數據在哪個數據包里。告訴自己,學會抓包、學會用抓包工具!
2.簡單的反爬策略:UA, 代理,延時。其他的策略有待繼續學習。
3.把淘寶京東爬一下,就該學學如何提高效率了。
4.scrapy ,scrapy,scrapy,scrapy