背景:拉钩网是一家专门提供互联网招聘的平台,反爬机制是做得很厉害的。在今年2到3月之间,做了一个比较具有迷惑性的反爬机制,导致网上99%以上的以往爬取拉钩信息的帖子都失效了。
本片帖子将详细一步步进行突破,并进行详细的分析。
环境:python3.6、time模块、json模块
工具:pycharm、Google Chrome
1、登录拉钩网,进行抓包分析。
本次爬取的是java相关的职位。在搜索栏输入java,然后搜索,在开发者工具中可以看到。第一个文件是HTML文件,它的名字更浏览器的输入框中出现的url的的一部分是完全相同的。HTML文档中没有我们需要的信息,我们需要的信息是以ajax异步的方式显示在网页中的。我们直接去看json文件。
2、可以看到里面有不少的json文件,但是真正有用的,只有下面这个文件,展开可以看到我们想啊哟ode信息正式包含在这个文件中。同时要注意一下开头是approve的那个文件,我们在点击下一页或者页码的时候,是想服务器发送了两个请求的,第一个是包含我们想要的数据的positionAjax开通的文件,另一个就是approve开通的这个东西。点开可以发现,approve文件里面凡是标true的数字,其实都是positionAjax中的companyId。而且approve其实是发送的get请求获取的。
但是当我们同时对这两个文件发送get请求和post请求的时候,发现还是不成功,说明我们的思路有问题。而且,请求approve的url是跟companyId有关,我们想要仿造进本是不可能的。
3、我们再仔细查看一下,发现一个有意思的地方,这些json文件的cookie都不一样。再结合headers里面所有的Referer都是https://www.lagou.com/jobs/list_java?city=%E6%AD%A6%E6%B1%89&cl=false&fromSearch=true&labelWords=&suginput=
跟我们最开始请求到的HTML文件url是一样的。我们大胆尝试一下先请求一下这个Referer,然后再发一个positionAjax的post请求,记得更新一下headers(这个很重要,是最近看到的一个大佬的帖子上提到的细节)。
这样尝试之后,我们会发现,果然,我们能拿到数据,我们突破了拉钩的坑了!真的不容易啊。
突破反爬之后,我们就可以批量获取数据了,我拿自己的code展示下。
import requests
import time
import json
url1 = "https://www.lagou.com/jobs/positionAjax.json?city=%E6%AD%A6%E6%B1%89&needAddtionalResult=false"
url2 ="https://www.lagou.com/jobs/list_java?city=%E6%AD%A6%E6%B1%89&cl=false&fromSearch=true&labelWords=&suginput="
headers = {
"Referer": "https://www.lagou.com/jobs/list_java?city=%E6%AD%A6%E6%B1%89&cl=false&fromSearch=true&labelWords=&suginput=",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3642.0 Safari/537.36",
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
}
def get_page(url1, url2, headers,data,i):
session = requests.Session()
session.headers.update(headers)
session.get(url2)
info = session.post(url=url1, data=data)
f = open("result%s.json" % i , "w", encoding="utf-8")
json.dump(info.json(), f, ensure_ascii=False)
def run(url1, url2, headers):
i = 1
while True:
try:
data = {
"first": "true",
"pn": i,
"kd": "java"
}
get_page(url1, url2, headers, data,i)
time.sleep(3)
i += 1
except:
print("出现问题")
i += 1
if __name__ == '__main__':
run(url1=url1, url2=url2, headers=headers)
需要注意的是,同一个ip如果爬取得信息次数过多,好像也会被封