源代碼:https://github.com/nnngu/LagouSpider
效果預(yù)覽
思路
1亚兄、首先我們打開拉勾網(wǎng)混稽,并搜索“java”,顯示出來的職位信息就是我們的目標(biāo)。
2匈勋、接下來我們需要確定礼旅,怎樣將信息提取出來。
查看網(wǎng)頁源代碼洽洁,這時候發(fā)現(xiàn)痘系,網(wǎng)頁源代碼里面找不到職位相關(guān)信息,這證明拉勾網(wǎng)關(guān)于職位的信息是異步加載的饿自,這也是一種很常用的技術(shù)汰翠。
異步加載的信息,我們需要借助 chrome 瀏覽器的開發(fā)者工具進(jìn)行分析璃俗,打開開發(fā)者工具的方法如下:
- 點擊Nerwork進(jìn)入網(wǎng)絡(luò)分析界面奴璃,這時候是一片空白,刷新一下界面就可以看到一系列的網(wǎng)絡(luò)請求了城豁。
前面我們說到苟穆,拉勾網(wǎng)關(guān)于職位的信息是異步加載的,那么在這一系列的網(wǎng)絡(luò)請求中唱星,必定有某個請求發(fā)送給服務(wù)器雳旅,響應(yīng)回來的是職位信息。
正常情況下间聊,我們可以忽略css攒盈,圖片等類型的請求,關(guān)注點放在XHR這種類型請求上哎榴,如圖:
一共4個XHR類型的請求型豁,我們逐個打開對比,分別點擊Preview就能看到它們響應(yīng)的內(nèi)容尚蝌。
發(fā)現(xiàn)第一個請求就是我們要找的迎变。如圖:
點擊Headers,查看一下請求參數(shù)飘言。如下圖:
到此衣形,我們可以確定city參數(shù)就是城市,pn參數(shù)就是頁數(shù)姿鸿,kd參數(shù)就是搜索關(guān)鍵字谆吴。
接下來開始寫代碼了。
代碼
代碼分成四個部分苛预,便于后期維護(hù)句狼。
1、基本 https 請求https.py
這部分對 requests 包進(jìn)行了一些封裝热某,部分代碼如下:
# -*- coding: utf-8 -*-
from src.setting import IP, UA
import requests, random
import logging
class Http:
'''
http請求相關(guān)的操作
'''
def __init__(self):
pass
def get(self, url, headers=None, cookies=None, proxy=None, timeOut=5, timeOutRetry=5):
'''
獲取網(wǎng)頁源碼
url: 網(wǎng)頁鏈接
headers: headers
cookies: cookies
proxy: 代理
timeOut: 請求超時時間
timeOutRetry: 超時重試次數(shù)
return: 源碼
'''
if not url:
logging.error('GetError url not exit')
return 'None'
# 這里只展示了一部分代碼
# 完整代碼已上傳到Github
這里只展示了一部分代碼鲜锚,完整代碼已上傳到Github
2突诬、代碼主邏輯部分main.py
這部分的程序邏輯,如下:
- 獲取職位信息
def getInfo(url, para):
"""
獲取信息
"""
generalHttp = Http()
htmlCode = generalHttp.post(url, para=para, headers=headers, cookies=cookies)
generalParse = Parse(htmlCode)
pageCount = generalParse.parsePage()
info = []
for i in range(1, 3):
print('第%s頁' % i)
para['pn'] = str(i)
htmlCode = generalHttp.post(url, para=para, headers=headers, cookies=cookies)
generalParse = Parse(htmlCode)
info = info + getInfoDetail(generalParse)
time.sleep(2)
return info
- 對信息進(jìn)行儲存
def processInfo(info, para):
"""
信息存儲
"""
logging.error('Process start')
try:
title = '公司名稱\t公司類型\t融資階段\t標(biāo)簽\t公司規(guī)模\t公司所在地\t職位類型\t學(xué)歷要求\t福利\t薪資\t工作經(jīng)驗\n'
file = codecs.open('%s職位.xls' % para['city'], 'w', 'utf-8')
file.write(title)
for p in info:
line = str(p['companyName']) + '\t' + str(p['companyType']) + '\t' + str(p['companyStage']) + '\t' + \
str(p['companyLabel']) + '\t' + str(p['companySize']) + '\t' + str(p['companyDistrict']) + '\t' + \
str(p['positionType']) + '\t' + str(p['positionEducation']) + '\t' + str(
p['positionAdvantage']) + '\t' + \
str(p['positionSalary']) + '\t' + str(p['positionWorkYear']) + '\n'
file.write(line)
file.close()
return True
except Exception as e:
print(e)
return None
3芜繁、信息解析部分parse.py
這部分針對服務(wù)器返回的職位信息的特點旺隙,進(jìn)行解析,如下:
class Parse:
'''
解析網(wǎng)頁信息
'''
def __init__(self, htmlCode):
self.htmlCode = htmlCode
self.json = demjson.decode(htmlCode)
pass
def parseTool(self, content):
'''
清除html標(biāo)簽
'''
if type(content) != str: return content
sublist = ['<p.*?>', '</p.*?>', '<b.*?>', '</b.*?>', '<div.*?>', '</div.*?>',
'</br>', '<br />', '<ul>', '</ul>', '<li>', '</li>', '<strong>',
'</strong>', '<table.*?>', '<tr.*?>', '</tr>', '<td.*?>', '</td>',
'\r', '\n', '&.*?;', '&', '#.*?;', '<em>', '</em>']
try:
for substring in [re.compile(string, re.S) for string in sublist]:
content = re.sub(substring, "", content).strip()
except:
raise Exception('Error ' + str(substring.pattern))
return content
# 這里只展示了一部分代碼
# 完整代碼已上傳到Github
這里只展示了一部分代碼骏令,完整代碼已上傳到Github
4蔬捷、配置部分setting.py
這部分加入 cookies 的原因是為了應(yīng)對拉勾網(wǎng)的反爬,長期使用需要進(jìn)行改進(jìn)榔袋,進(jìn)行動態(tài) cookies 獲取
# -*- coding: utf-8 -*-
# headers
headers = {
'Host': 'www.lagou.com',
'Connection': 'keep-alive',
'Content-Length': '23',
'Origin': 'https://www.lagou.com',
'X-Anit-Forge-Code': '0',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'X-Requested-With': 'XMLHttpRequest',
'X-Anit-Forge-Token': 'None',
'Referer': 'https://www.lagou.com/jobs/list_java?city=%E5%B9%BF%E5%B7%9E&cl=false&fromSearch=true&labelWords=&suginput=',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7'
}
測試
運(yùn)行結(jié)果:
爬取結(jié)束后周拐,在src目錄下就可以看到爬蟲爬取到的數(shù)據(jù)。
到此凰兑,拉勾網(wǎng)的職位信息抓取就完成了妥粟。完整代碼已經(jīng)上傳到我的Github