需求分析
知己知彼,方可百战不殆。在学习技术的时候我们往往面临太多选择而不知所措,可能是各个方面都有涉猎,对某个领域没有深入研究,看似什么都会,真要让你做个什么东西的时候就显得捉肘见襟。如果我们能从招聘职位所需的技能开始学习,便可练就一身硬功夫,为实战应用中打下良好的基础。
通过python抓取拉钩网的招聘详情,并筛选其中的技能关键词,存储到excel 中。
项目简介
职位检索页面分析
通过对职位检索页面分析发现需要的职位信息在content –> positionResult –> result
下,其中包含了工作地点、公司名、职位等信息。 我们只需要保存这个数据 (JSON格式) 就可以了。
真实的URL获取
需要注意:在职位检索过程中真正请求的url地址是https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false
职位详情页面分析
点击进入具体的职业招聘信息的详情页
- 通过观察可以发现,拉勾网的职位页面详情是由 http://www.lagou.com/jobs/
positionId.html 组成。
注意: - 拉勾网反爬虫做的比较严,请求头可多添加几个参数才能不被网站识别。反爬报错一般如下所示:
- 找到真正的请求网址,发现返回的是一个
JSON
串,解析这个JSON
串即可,而且注意是POST
传值,通过改变Form Data
中pn
的值来控制翻页。
XHR
:XMLHttpRequest
对象用于和服务器交换数据。
点击页面中的页数,比如第 2 页,我们可以在右边看到一个 POST 请求,这个请求里面包含了真实的 URL (浏览器上的URL 并没有职位数据,查看源代码就可以发现这一点)、POST
请求的请求头Headers
、POST 请求提交的表单Form Data
(这里面包含了页面信息pn
、搜索的职位信息kd
)
代码示例:
import time
import requests
from fake_useragent import UserAgent
from lxml import etree
ua = UserAgent()
def download_positions(kd="python", city="北京", page=1):
"""
获取拉勾网所有的岗位API接口的响应信息
:param kd: 岗位名称/关键字
:param city: 城市
:param page: 页码
:return: position_id
"""
# 拉勾网访问的网址,并不是Ajax的网址
# old_url = 'https://www.lagou.com/jobs/list_python'
# 真实的API接口的网址(通过F12开发者模式中的XHR分析出来的)
url = 'https://www.lagou.com/jobs/positionAjax.json?=false'
# url提交的参数信息, http://xxxxx/?param1=value1¶m2=value2
params = {
'city': city,
# 'needAddtionalResult': 'false',
}
# url以POST方式提交的信息(参数分析出来的)
data = {
# 'first': 'true',
'pn': page,
'kd': kd
}
# 头部信息, 为了防止拉钩反爬策略的
headers = {
'UserAgent': ua.random,
'Host': 'www.lagou.com',
'Origin': 'https://www.lagou.com',
'Referer': 'https://www.lagou.com/jobs/list_python',
'TE': 'Trailers',
'X-Requested-With': 'XMLHttpRequest',
'Connection': 'keep-alive',
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept - Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
}
# 以POST方式请求网址并返回响应
response = requests.post(url=url, params=params, data=data)
data = response.json()
print(data)
if data.get('status') == False:
raise Exception("获取职位失败: %s" % (response.text))
else:
return response
def parse_position_ids(response):
"""
根据页面信息解析所有岗位的ID号
:param response:
:return: 字典
"""
# 响应的信息是json格式, 通过json方法自动化解析json字符串为python对象
ajax_data = response.json()
content = ajax_data.get('content')
positionResults = content.get('positionResult').get('result')
for position in positionResults:
yield {
'name': position.get('positionName'),
'positionId': position.get('positionId')
}
def download_detail(id):
"""下载详情页页面"""
url = 'https://www.lagou.com/jobs/%s.html' % (id)
try:
response = requests.get(url)
except Exception as e:
print("采集职位详情页失败: " % (str(e)))
else:
return response
def parse_position_detail(id):
"""解析详情页页面并提取岗位详情内容"""
response = download_detail(id)
# 使用解析器解析页面的岗位详情(正则、Xpath、BS4)
html = etree.HTML(response.text)
# 通过类名寻找class="job-detail"的节点, xpath('string(.)')获取节点所有的文本信息(标签自动删除)
job_detail = html.xpath('//div[@class="job-detail"]')
if job_detail:
return job_detail[0].xpath('string(.)')
return job_detail[0]
def test_ids():
response = download_positions()
position_ids = parse_position_ids(response)
for id in position_ids:
print(id)
def test_detail_id():
id = '6372641'
job_detail = parse_position_detail(id)
print(job_detail)
if __name__ == '__main__':
test_ids()
test_detail_id()