操作环境: Windows10、Python3.6、Pycharm、谷歌浏览器
目标网址: https://www.lagou.com/jobs/list_Python/p-city_0?px=default (拉钩Python职位)

很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:101677771

爬虫目录

1、项目疑惑

  拉钩爬虫区别于许多网站的反爬机制,即使请求头参数以及请求体参数加齐也无法请求返回正确数据,若返回 “您操作太频繁,请稍后再访问” 字眼,则表示被拉钩反爬机制识别你的不是正常浏览网页,而是爬虫程序请求。

  1. {"status":false,"msg":"您操作太频繁,请稍后再访问","clientIp":"223.104.65.43","state":2402}

2、分析网页

  本次项目与上次腾讯爬虫一样属于ajax加载的动态数据,但是他与腾讯招聘不同的是,列表页是ajax加载数据,而详情页却是静态数据,腾讯招聘则是经典的双ajax加载数据页面。

  所以本次项目只为了解决反爬机制与爬取列表页数据即可,下次小编再带大家写一篇动静结合的爬虫项目,敬请期待。话不多说,开始进入正题!

2.1、POST请求

  requests模块发送post请求时,提交的是data参数,但data表单参数不会在接口链接上显示,这与之get请求的params参数相反。

2.2、参数解析

 px参数: 工作地点,爬取指定地点的岗位信息。
 pn参数: 翻页页数。
 kd参数: 职位名,爬取指定岗位名称的相关信息。

2.3、详情页分析

  虽说此次不请求详情页里的数据,但还是帮其他有需要的小伙伴解析一波。

  因为详情页为静态数据,所以我们直接分析它的链接即可。从岗位详情页链接可看出两个重要参数:职位特有id与show参数。

  通过分析列表页的json数据发现岗位特有id与show参数均在里面。

  从下图可看出岗位特有id是固定不变的,然而show参数却是每次请求将变换,会更新,不固定。但无关系,直接从请求的列表页中获取即可,即请求即获取。

3、解决请求

目标网址:

3.1、请求数据

  分析好网页,开始写程序代码,首先导入需要的库以及设置请求头伪造身份,而post请求需要用到的data参数需要重复使用到,则定义一个from_data函数构建data参数,以便调用它。

  1. # 导入需要的库
  2. import requests
  3. import json
  4. import parsel
  5. import openpyxl
  6. import re
  7. headers = { # 请求头,伪造身份
  8. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36',
  9. }
  10. '''构建data表单'''
  11. def from_data(kd,pn):
  12. json_data = {
  13. 'first': 'false',
  14. 'pn': str(pn), # 页数
  15. 'kd': kd # 职位名
  16. }
  17. return json_data
  18. '''请求数据'''
  19. def get_data(json_url):
  20. data = from_data('python','1')# 获取表单数据
  21. # 请求接口链接
  22. response = requests.post(url=json_url,headers=headers,data=data)
  23. print(response.text)
  24. if __name__ == '__main__':
  25. # json接口链接
  26. json_url = 'https://www.lagou.com/jobs/positionAjax.json?city=%E5%B9%BF%E5%B7%9E&needAddtionalResult=false'
  27. get_data(json_url) # 获取数据

输出结果为"您操作太频繁,请稍后再访问",出现这情况表示拉钩服务器已识别这次请求为爬虫程序。一开始我以为是请求头参数没有加齐,随后将Headers里的origin与referer参数加上还是没有解决问题。
  后面一想,会不会是爬虫请求频率过快,导致被拉钩服务器限制识别到了?而后我利用time模块设置延迟time.sleep(5)睡眠五秒,依然还是“操作频繁”的结果,脑瓜疼。

3.2、解决反爬

  研究了三四个小时,依旧没有成。随后咨询了大佬,大佬一下给出了两个方案:
   一、利用session保持会话登录提取数据;
   二、请求搜索关键词链接的cookies信息,将其加入到json接口链接post请求中。

  这次小编采取了第二种方案:定义一个get_cookies函数,用于请求关键字页面的cookies身份信息,以便post请求的调用。此外,重新定义两个请求头信息,分别用于获取cookie的get请求和获取json职位数据的post请求。

  1. cookie_headers = { # cookie请求头,伪造身份
  2. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36',
  3. 'referer':'https://www.lagou.com/jobs/list_Python/p-city_213?&cl=false&fromSearch=true&labelWords=&suginput='
  4. }
  5. json_headers = { # json数据请求头
  6. 'Host': 'www.lagou.com',
  7. "origin": "https://www.lagou.com",
  8. "referer": "referer: https://www.lagou.com/jobs/list_Python/p-city_0?&cl=false&fromSearch=true&labelWords=&suginput=",
  9. "user-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36",
  10. }
  11. '''请求cookies值'''
  12. def get_cookies(cookies_url):
  13. # allow_redirects重定向
  14. response = requests.get(url=cookies_url, headers=headers, allow_redirects=False)
  15. cookies = response.cookies # get请求获取cookies值
  16. return cookies
  17. '''请求数据'''
  18. def get_data(json_url):
  19. # for pn in range(1,3,1):
  20. # 搜索关键字链接
  21. cookies_url = 'https://www.lagou.com/jobs/list_Python/p-city_0?&cl=false&fromSearch=true&labelWords=&suginput='
  22. cookies = get_cookies(cookies_url) # 获取cookie
  23. json_data = from_data('1','Python') # 获取表单数据
  24. # 请求接口链接
  25. response = requests.post(url=json_url,headers=json_headers,cookies=cookies,data=json_data)
  26. print(response.text)

  这里测试一页,输出结果中有Python的职位名,获取的数据无误,反爬解决成功!

4、翻页

  搜索关键字职位页面,每个职位固定显示30页。
  由于数据是ajax加载,应该在职位链接接口返回数据里查看总的数据量。
  分析得知,有些职位超过几百页甚至上千页数据,但过了200都是空的数据,即某些职位至多可爬到200页。

4.1、for循环翻页

  for循环翻页即手动设置翻页页数,这样只适合单个职位爬取方式,简单有效。

  1. for pn in range(1,10,1): # for循环翻页
  2. # 搜索关键字链接
  3. cookies_url = 'https://www.lagou.com/jobs/list_Python/p-city_0?&cl=false&fromSearch=true&labelWords=&suginput='
  4. cookies = get_cookies(cookies_url) # 获取cookie
  5. json_data = from_data(str(pn),'Python') # 获取表单数据
  6. # 请求接口链接
  7. response = requests.post(url=json_url,headers=json_headers,cookies=cookies,data=json_data)
  8. print(len(response.text))

  这里代码测试十页,len()返回长度成功!:

4.2、while循环翻页

  自定义每页总的职位数量,while True无限循环,每循环一次加每页总的职位数量,直到自定义的职位数量大于获取到的总职位量,便结束循环、结束翻页。

  提取相关的职位字段数据。
  replace:替换
  ‘’.join():合并

  1. '''请求数据'''
  2. def get_data(json_url):
  3. data_list = [] # 定义一个空列表,用于填充获取到的字段数据
  4. pn = 15
  5. while True:
  6. # 搜索关键字链接
  7. cookies_url = 'https://www.lagou.com/jobs/list_Python/p-city_0?&cl=false&fromSearch=true&labelWords=&suginput='
  8. cookies = get_cookies(cookies_url) # 获取cookie
  9. json_data = from_data(int(pn / 15),'Python') # 获取表单数据
  10. # 请求接口链接
  11. response = requests.post(url=json_url,headers=json_headers,cookies=cookies,data=json_data)
  12. results = response.json()['content']['positionResult']['result']
  13. for result in results:
  14. id = result['positionId'] # id
  15. positionName = result['positionName'] # 职位名称
  16. city = result['city'] # 城市
  17. companyFullName = result['companyFullName'] # 公司名称
  18. pub_time = result['createTime'] # 发布时间
  19. education = result['education'] # 学历
  20. firstType = result['firstType'] # 职位类型
  21. firstType = firstType.replace('|', '-')
  22. salary = result['salary'] # 薪资
  23. workYear = result['workYear'] # 工作经验
  24. companySize = result['companySize'] # 公司规模
  25. skillLables = result['skillLables'] # 学识要求
  26. skillLables = '-'.join(skillLables)
  27. companyLabelList = '-'.join(result['companyLabelList']) # 公司福利
  28. # 输出获取到的字段数据
  29. print(id, positionName, city, companyFullName, pub_time, education,
  30. firstType, salary, workYear, companySize, skillLables, companyLabelList)
  31. data_list.append([id, positionName, city, companyFullName, pub_time, education,
  32. firstType, salary, workYear, companySize, skillLables, companyLabelList])
  33. pn += 15 # 每循环一次增加一页
  34. if pn > response.json()['content']['positionResult']['totalCount'] + 15:
  35. break # 超过总职位数便结束循环
  36. return data_list

代码输出部分结果:

5、存入Excel

  存excel表格需要用到openpyxl,import openpyxl导入,下载即pip install openpyxl

5.1、Excel表头

openpyxl.Workbook(): 创建一个excel薄
create_sheet(): 选择簿名
cell: 操作某行某列的某个值
row: 行
column: 列
value: 值

  1. # 创建一个excel薄
  2. wb = openpyxl.Workbook()
  3. sheet1 = wb.create_sheet('position')
  4. # 写入excel表头
  5. sheet1.cell(row=1, column=1, value='id')
  6. sheet1.cell(row=1, column=2, value='职位名称')
  7. sheet1.cell(row=1, column=3).value = '城市'
  8. sheet1.cell(row=1, column=4).value = '公司名称'
  9. sheet1.cell(row=1, column=5).value = '发布时间'
  10. sheet1.cell(row=1, column=6).value = '学历'
  11. sheet1.cell(row=1, column=7).value = '职位类型'
  12. sheet1.cell(row=1, column=8).value = '薪资'
  13. sheet1.cell(row=1, column=9).value = '工作经验'
  14. sheet1.cell(row=1, column=10).value = '公司规模'
  15. sheet1.cell(row=1, column=11).value = '职位要求'
  16. sheet1.cell(row=1, column=12).value = '公司福利'
  17. wb.save('拉勾招聘岗位信息.xlsx')

5.2、保存函数

  定义一个save_excel函数用于将数据存入Excel表格。
  data_list:数据列表

  1. '''保存为excel文件'''
  2. def save_excel(data_list):
  3. wb = openpyxl.load_workbook('拉勾招聘岗位信息.xlsx')
  4. sheet = wb['position']
  5. for d in data_list:
  6. sheet.append(d) # 写入数据
  7. wb.save('拉勾招聘岗位信息.xlsx') # 保存

  共获取一千二百多条数据,程序成功运行完毕!

六、项目总结

  本次项目只爬取了一个Python职位信息,若想继续爬取更多的职位信息,可以定义一个职位列表,将需要爬取的职位名写入其中即可。

  但需要注意的地方有两点:

6.1、填充问题

  爬取相应的职位需要注意请求头referer参数填充职位名以及请求cookies的链接填充与data表单kd参数的职位名。
  由上图可看出若爬取多个职位名信息的情况下,使用while循环获取每个职位的总页数是非常明智的选择。

6.2、汉字职位填充问题

  职位名填充有些特殊,若只是Python、java等英文字母组成的职位名则无需转码,而若是大数据、数据分析等汉字组成的职位名时,需要转码成前端适合的编码格式才能获取数据。例如:数据分析 —> %E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90

  转化为前端适合的编码格式,需要用到urllib内置库里的parse函数,直接导入即可import urllib.parse 。

  1. import urllib.parse
  2. kd = '数据分析'
  3. position_html = urllib.parse.quote(kd)
  4. print('转化为前端适合的编码格式:',position_html)
  5. # 执行position_html结果为:转化为前端适合的编码格式: %E6%95%B0%E6%8D%AE%E5%88%86%E6%9E%90
  6. position = urllib.parse.unquote(position_html)
  7. print('转化为Python程序适合的编码:',position)
  8. # 执行position结果为:转化为Python程序适合的编码: 数据分析

  如代码所示,链接填充用position_html即可,若data表单里的kd职位名参数用position即可。

Python3网络爬虫之requests动态爬虫:拉钩网的更多相关文章

  1. Python3 Scrapy + Selenium + 阿布云爬取拉钩网学习笔记

    1 需求分析 想要一个能爬取拉钩网职位详情页的爬虫,来获取详情页内的公司名称.职位名称.薪资待遇.学历要求.岗位需求等信息.该爬虫能够通过配置搜索职位关键字和搜索城市来爬取不同城市的不同职位详情信息, ...

  2. 转:【Python3网络爬虫开发实战】 requests基本用法

    1. 准备工作 在开始之前,请确保已经正确安装好了requests库.如果没有安装,可以参考1.2.1节安装. 2. 实例引入 urllib库中的urlopen()方法实际上是以GET方式请求网页,而 ...

  3. Python3 网络爬虫(请求库的安装)

    Python3 网络爬虫(请求库的安装) 爬虫可以简单分为几步:抓取页面,分析页面和存储数据 在页面爬取的过程中我们需要模拟浏览器向服务器发送请求,所以需要用到一些python库来实现HTTP的请求操 ...

  4. Python3网络爬虫开发实战PDF高清完整版免费下载|百度云盘

    百度云盘:Python3网络爬虫开发实战高清完整版免费下载 提取码:d03u 内容简介 本书介绍了如何利用Python 3开发网络爬虫,书中首先介绍了环境配置和基础知识,然后讨论了urllib.req ...

  5. 崔庆才Python3网络爬虫开发实战电子版书籍分享

    资料下载地址: 链接:https://pan.baidu.com/s/1WV-_XHZvYIedsC1GJ1hOtw 提取码:4o94 <崔庆才Python3网络爬虫开发实战>高清中文版P ...

  6. 《Python3 网络爬虫开发实战》开发环境配置过程中踩过的坑

    <Python3 网络爬虫开发实战>学习资料:https://www.cnblogs.com/waiwai14/p/11698175.html 如何从墙内下载Android Studio: ...

  7. 《Python3 网络爬虫开发实战》学习资料

    <Python3 网络爬虫开发实战> 学习资料 百度网盘:https://pan.baidu.com/s/1PisddjC9e60TXlCFMgVjrQ

  8. [Python3网络爬虫开发实战] 2.5-代理的基本原理

    我们在做爬虫的过程中经常会遇到这样的情况,最初爬虫正常运行,正常抓取数据,一切看起来都是那么美好,然而一杯茶的功夫可能就会出现错误,比如403 Forbidden,这时候打开网页一看,可能会看到“您的 ...

  9. python动态网站爬虫实战(requests+xpath+demjson+redis)

    目录 前言 一.主要思路 1.观察网站 2.编写爬虫代码 二.爬虫实战 1.登陆获取cookie 2.请求资源列表页面,定位获得左侧目录每一章的跳转url(难点) 3.请求每个跳转url,定位右侧下载 ...

随机推荐

  1. 回首Java——写在前面

    我记得在大学的课程要求中,第一个接触的高级编程语言,应该是C语言或者C++等.但是Java应该是我的编程母语,我在高中毕业就接触了Java语言.当时看的是纸质书,具体书名也忘记了.只记得当时第一次接触 ...

  2. Spring异常总结

    1.  Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean o ...

  3. tracebace用法

    介绍一下traceback 平时看到的程序的错误信息也就是traceback信息 举个简单例子: import traceback try: s = [1, 2, 3] print s[5] exce ...

  4. AutoMapper 9.0的改造

    AutoMapper于2019.8.12升级9.0 从此不再支持静态的对象转换 自己琢磨了一下,写了一套扩展 官方链接如下 https://github.com/AutoMapper/AutoMapp ...

  5. Python环境搭建、python项目以docker镜像方式部署到Linux

    Python环境搭建.python项目以docker镜像方式部署到Linux 本文的项目是用Python写的,记录了生成docker镜像,然后整个项目在Linux跑起来的过程: 原文链接:https: ...

  6. 深入学习JDK源码系列之、ArrayList

    前言 JDK源码解析系列文章,都是基于JDK8分析的,虽然JDK15马上要出来了,但是JDK8我还不会,我... 类图 实现了RandomAccess接口,可以随机访问 实现了Cloneable接口, ...

  7. 网络安全传输系统-sprint3账号管理子系统设计

    part1:sqlite嵌入式数据库移植 1.数据库系统构成:访问数据库应用-->管理数据库系统-->数据库存储(自上而下) 2.数据库中数据以表的形式而存在.表与表之间可能存在关联关系( ...

  8. 这几个冷门却实用的 Python 库,我爱了!

  9. JS 节点笔记

    h5新增自定义属性     为了保存并使用数据,有一些数据不必要保存到数据库中:     data开头作为自定义属性并赋值     兼容性获取element.getAttribute("da ...

  10. QT QMdiArea 添加背景或添加背景图片失效问题

    说起QMdirArea 这个控件与其他控件真所不同.... 这里记一下 我踩过的坑之一,,,,, QMdiArea 默认的背景 不符合我要求,,当时我就理所当然就想往常一样给它设置颜色 万万没想到.. ...