应对AJAX动态加载,并应用表单的交互技术,爬取爬取拉勾网招聘信息,解析网页返回的json数据,并将爬取的数据存储于MongoDB数据库中。
本文为整理代码,梳理思路,验证代码有效性——2020.2.2
环境:
Python3(Anaconda3)
PyCharm
Chrome浏览器
主要模块: 后跟括号内的为在cmd窗口安装的指令
requests(pip install requests)
pymongo(pip install pymongo )
json
time
爬取目标url:https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=
看看python的相关职位。
在源代码中查看相关的信息,我们可以发现在网页源代码中没有找到任何岗位的信息,由此可以推断,该网页是异步加载(AJAX)的。
打开开发者工具F12,选择Network选项,并点击XHR文件,刷新一下网页,依次查看各个文件返回的内容。
我们发现在第一个文件在中就返回了我们需要的信息,而且是json格式。
解析json格式。由于该json格式比较复杂,所以我们先点击到Preview查看,如图。
那么在content —》positionResult- --》result 路径中,我们用python中的json库对其解析。
注意:这里得到的 results 是多组信息,后用循环对它进行分组拆分,详见完整代码。
html = requests.post(url, data=params, headers=headers, cookies=get_cookie(), timeout=5)
# 将网页的Html文件加载为json文件
json_data = json.loads(html.text)
# 解析json文件,后跟中括号为解析的路径
results = json_data['content']['positionResult']['result']
到上一步,我们就已经获取到了信息了,但是不满足于此,我们还要爬取更多页的信息,手动翻页,发现url没有变化,可判断翻页也是异步加载,同上,我们还是进行逆向工程,去XHR文件中找线索。
发现它是一个POST请求,页数是由pn参数控制。
发现返回的json数据中含有信息的总数,如图。
拉勾网每页有15条岗位信息,并默认只有30页,那么我们将返回的信息总数除以15看是否小于30,若小于,总页数取对应结果,不然总页数就等于30,代码如下。
# 定义获取页数的函数
def get_page(url, params):
html = requests.post(url, data=params, headers=headers, cookies=get_cookie(), timeout=5)
# 将网页的Html文件加载为json文件
json_data = json.loads(html.text)
# 解析json文件,后跟中括号为解析的路径
total_Count = json_data['content']['positionResult']['totalCount']
page_number = int(total_Count/15) if int(total_Count/15) < 30 else 30
爬取过程中出现如下错误,我起初同一位兄弟的想法一致,以为是headers的参数不足,各种尝试,后面把网页里的整个请求头都加进去还是没用。
这时有点难受了,开始百度,发现请求要添加相应的Cooke值才行,但是拉钩网的的Cookie内含时间戳,即具有一次性,于是用下面的代码获取cookie完美解决问题。
# 获取cookies值
def get_cookie():
# 原始网页的URL
url = "https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput="
s = requests.Session()
s.get(url, headers=headers, timeout=3) # 请求首页获取cookies
cookie = s.cookies # 为此次获取的cookies
return cookie
参考资料,请移步至页尾查看123
# 导入相应的文件
import requests
import json
import time
import pymongo
# 连接数据库
client = pymongo.MongoClient('localhost', 27017)
# 创建数据库和数据集合
mydb = client['mydb']
lagou = mydb['lagou']
# 加入请求头
headers = {
"Accept": "application/json, text/javascript, */*; q=0.01",
"Referer": "https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36",
}
# 获取cookies值
def get_cookie():
# 原始网页的URL
url = "https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput="
s = requests.Session()
s.get(url, headers=headers, timeout=3) # 请求首页获取cookies
cookie = s.cookies # 为此次获取的cookies
return cookie
# 定义获取页数的函数
def get_page(url, params):
html = requests.post(url, data=params, headers=headers, cookies=get_cookie(), timeout=5)
# 将网页的Html文件加载为json文件
json_data = json.loads(html.text)
# 解析json文件,后跟中括号为解析的路径
total_Count = json_data['content']['positionResult']['totalCount']
page_number = int(total_Count/15) if int(total_Count/15) < 30 else 30
# 调用get_info函数,传入url和页数
get_info(url, page_number)
# 定义获取招聘信息函数
def get_info(url, page):
for pn in range(1, page+1):
# post请求参数
params = {
"first": "true",
"pn": str(pn),
"kd": "python"
}
# 获取信息 并捕获异常
try:
html = requests.post(url, data=params, headers=headers, cookies=get_cookie(), timeout=5)
print(url, html.status_code)
# 将网页的Html文件加载为json文件
json_data = json.loads(html.text)
# 解析json文件,后跟中括号为解析的路径
results = json_data['content']['positionResult']['result']
for result in results:
infos = {
# positionName: "python"
#
# companyFullName: "深圳云安宝科技有限公司"
# companySize: "15-50人"
# industryField: "信息安全,数据服务"
# financeStage: "A轮"
#
# firstType: "开发|测试|运维类"
# secondType: "后端开发"
# thirdType: "Python"
#
# positionLables: ["云计算", "大数据"]
#
# createTime: "2020-02-02 12:51:01"
#
# city: "深圳"
# district: "南山区"
# businessZones: ["科技园"]
#
# salary: "15k-30k"
# workYear: "3-5年"
# jobNature: "全职"
# education: "本科"
#
# positionAdvantage: "地铁口近 周末双休"
"positionName": result["positionName"],
"companyFullName": result["companyFullName"],
"companySize": result["companySize"],
"industryField": result["industryField"],
"financeStage": result["financeStage"],
"firstType": result["firstType"],
"secondType": result["secondType"],
"thirdType": result["thirdType"],
"positionLables": result["positionLables"],
"createTime": result["createTime"],
"city": result["city"],
"district": result["district"],
"businessZones": result["businessZones"],
"salary": result["salary"],
"workYear": result["workYear"],
"jobNature": result["jobNature"],
"education": result["education"],
"positionAdvantage": result["positionAdvantage"]
}
print(infos)
# 插入数据库
lagou.insert_one(infos)
# 睡眠2秒
time.sleep(2)
except requests.exceptions.ConnectionError:
print("requests.exceptions.ConnectionError")
pass
# 主程序入口
if __name__ == '__main__':
url = "https://www.lagou.com/jobs/positionAjax.json"
# post请求参数
params = {
"first": "true",
"pn": 1,
"kd": "python"
}
get_page(url, params)
获取cookie的方法 ↩︎
指出拉勾网的Cookie具有时间戳,一次性 ↩︎
后知后觉,获取Cookie的url为原始请求的URL ↩︎