思路梳理
打开拉勾网输入职位信息,可以看到我们想要的数据,当我们翻页的时候可以发现地址是没有任何变化的,因此可以确定我们整个输入查询的过程是通过post请求和异步加载完成的 ;
打开控制台再次加载页面看看我们得到了什么,我们想要的职位信息都好好的躺在这里的,信息都是以json格式传输的,我们只需要调用json的包读取这些数据然后保存下来就ok了 ;
我们自己看其实在json的url里面是包含了城市的这个变量的,因此我们想要查看不同城市的职位只需要在url里面改变城市就好;
但当我们直接访问这个地址的时候我们是看不到职位信息的,看来服务器对headers是有检查的,因此我们在发送请求的时候还必须加上headers;
下面是我们的headers和需要post的数据,其中需要注意的是headers中Referer是一个变量,根据职位的信息不同改变的,Referer是服务器需要确定你是从哪个页面访问过来的,后面的调试中也确定了拉勾网是对Referer进行了检查的,如果Referer不对,服务器会拒绝请求然后出现上图的页面;
我们需要post的数据又三个,多切换几次页面也会发现,first是表示’是否为第一页’,pn是表示’页码’,kd是表示’职位关键字’,因此我们只需要结合json的地址中的city变量+post的职位和页码就能获取到我们想要的数据了!
代码部分
首先是将字符串转成URL编码,如果是utf-8编码直接传入到地址里面,是无法访问到,这个在后面的城市和职位都需要用来转换;
#字符串转URL编码
def StringToUrl(string):
urlcode = urllib.quote(string)
return urlcode
我们获取到整个json数据中是会包含职位数的,每页是显示15个职位,职位数除以15向上取整,便是我们需要循环的次数
#获取职位数与页码
def GetPagnum(url,keyword,headers):
values = {'first': 'true','pn': '1', 'kd': keyword}
data = urllib.urlencode(values)
req = urllib2.Request(url,data,headers)
jsondata = urllib2.urlopen(req).read()
totalCount = int(json.loads(str(jsondata))["content"]["positionResult"]["totalCount"])
print('***本次搜索到%d个职位***'%totalCount)
pagenum = int (math.ceil(totalCount/15) )
return pagenum
下面是完整代码,整体思路是先根据职位+城市获取到总页数,然后通过循环post页码获取到职位信息,通过pandas保存数据为DataFrame,最后保存为excel
# -*- coding:utf-8 -*-
import re,json
import urllib2
import urllib
import pandas as pd
import math
#字符串转URL编码
def StringToUrl(string):
urlcode = urllib.quote(string)
return urlcode
#获取职位数与页码
def GetPagnum(url,keyword,headers):
values = {'first': 'true','pn': '1', 'kd': keyword}
data = urllib.urlencode(values)
req = urllib2.Request(url,data,headers)
jsondata = urllib2.urlopen(req).read()
totalCount = int(json.loads(str(jsondata))["content"]["positionResult"]["totalCount"])
print('***本次搜索到%d个职位***'%totalCount)
pagenum = int (math.ceil(totalCount/15) )
return pagenum
def LagouSpider(keyword):
keyword_url = StringToUrl(keyword)
city_list = ['北京','上海','深圳','广州','杭州','成都','南京','武汉','西安','厦门','长沙','苏州','天津']
for n in list(range(len(city_list))):
city = city_list[n]
print('***正在保存'+city+'的职位***')
city_url = StringToUrl(city)
url = 'https://www.lagou.com/jobs/positionAjax.json?city='+city_url+'&needAddtionalResult=false&isSchoolJob=0'
Referer = 'https://www.lagou.com/jobs/list_'+keyword_url+'?city='+city_url+'=false&fromSearch=true&labelWords=&suginput='
headers = {
'Accept':'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding':'gzip, deflate, br',
'Accept-Language':'zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4',
'Connection':'keep-alive',
'Content-Length':'55',
'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie':'user_trace_token=20170912104426-9ba6e9c6-3053-45fd-9025-681bef8b0c8f; LGUID=20170916191219-e783b163-9acf-11e7-952a-525400f775ce; index_location_city=%E6%B7%B1%E5%9C%B3; TG-TRACK-CODE=index_search; _gid=GA1.2.1386711592.1505703954; _ga=GA1.2.351899359.1505560343; Hm_lvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1505560343,1505703955; Hm_lpvt_4233e74dff0ae5bd0a3d81c6ccf756e6=1505703988; LGRID=20170918110627-5c595dd3-9c1e-11e7-9196-5254005c3644; JSESSIONID=ABAAABAAAIAACBIF3290756E031DCE7CCEA3986CB372F49; SEARCH_ID=d30eb13562344eb9b5f6b8f05eb2cefc',
'Host':'www.lagou.com',
'Origin':'https://www.lagou.com',
'Referer':Referer,
'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36',
'X-Anit-Forge-Code':'0',
'X-Anit-Forge-Token':'None',
'X-Requested-With':'XMLHttpRequest'
}
Pagenum = GetPagnum(url,keyword,headers)
for i in range(0,Pagenum):
if i == 0:
values = {'first': 'true','pn': '1', 'kd': keyword}
data = urllib.urlencode(values)
else:
values = {'first': 'false','pn': (i+1), 'kd': keyword}
data = urllib.urlencode(values)
req = urllib2.Request(url,data,headers)
data = urllib2.urlopen(req).read()
jsondata = json.loads(str(data))['content']['positionResult']['result']
for t in list(range(len(jsondata))):
jsondata[t].pop('companyLogo')
jsondata[t].pop('businessZones')
jsondata[t].pop('explain')
jsondata[t].pop('plus')
jsondata[t].pop('gradeDescription')
jsondata[t].pop('promotionScoreExplain')
jsondata[t].pop('positionLables')
jsondata[t].pop('district')
jsondata[t].pop('adWord')
jsondata[t].pop('appShow')
jsondata[t].pop('approve')
jsondata[t].pop('companyId')
jsondata[t].pop('companyLabelList')
jsondata[t].pop('deliver')
jsondata[t].pop('imState')
jsondata[t].pop('industryLables')
jsondata[t].pop('pcShow')
jsondata[t].pop('positionId')
jsondata[t].pop('score')
jsondata[t].pop('publisherId')
if t == 0:
rdata=pd.DataFrame(pd.Series(data=jsondata[t])).T
else:
rdata=pd.concat([rdata,pd.DataFrame(pd.Series(data=jsondata[t])).T])
if i == 0:
citydata=rdata
else:
citydata=pd.concat([citydata,rdata])
print('***正在保存第%d页***'%(i+1))
if n == 0:
totaldata = citydata
else:
totaldata=pd.concat([totaldata,citydata])
totaldata.to_excel('LagouSpider.xls',sheet_name='sheet1')
if __name__ == "__main__":
keyword = raw_input('请输入要爬取的关键词:')
LagouSpider(keyword)
print '***LagouSpider@Awesome_Tang***'
运行结果