python爬虫方向_爬虫实战(三) 用Python爬取拉勾网
0、前言
最近,博主面临着选方向的困难(唉,选择困难症患者 >﹏<),所以希望了解一下目前不同岗位的就业前景
这时,就不妨写个小爬虫,爬取一下 拉勾网 的职位数据,并用图形化的方法展示出来,一目了然
整体的 思路 是采用 selenium 模拟浏览器的行为,具体的步骤如下:
初始化
爬取数据,这里分为两个部分:一是爬取网页数据,二是进行翻页操作
保存数据,将数据保存到文件中
数据可视化
整体的 代码结构 如下:
class Lagou:
# 初始化
def init(self):
pass
# 爬取网页数据
def parse_page(self):
pass
# 进行翻页操作
def turn_page(self):
pass
# 爬取数据,调用 parse_page 和 turn_page
def crawl(self):
pass
# 保存数据,将数据保存到文件中
def save(self):
pass
# 数据可视化
def draw(self):
pass
if __name__ == '__main__':
obj = Lagou()
obj.init()
obj.crawl()
obj.save()
obj.draw()
好,下面我们一起来看一下整个爬虫过程的详细分析吧!!
1、初始化
在初始化的部分,我们完成的工作需要包括以下四个方面:
准备全局变量
启动浏览器
打开起始 URL
设置 cookie
(1)准备全局变量
所谓的全局变量,是指在整个爬虫过程中都需要用到的变量,这里我们定义两个全局变量:
data:储存爬取下来的数据
isEnd:判断爬取是否结束
(2)启动浏览器
启动浏览器的方式大致可以分为两种,一是普通启动,二是无头启动
在普通启动时,整个爬取过程可以可视化,方便调试的时候发现错误
from selenium import webdriver
self.browser = webdriver.Chrome()
而无头启动可以减少渲染时间,加快爬取过程,一般在正式爬取时使用
from selenium import webdriver
opt = webdriver.chrome.options.Options()
opt.set_headless()
self.browser = webdriver.Chrome(chrome_options = opt)
(3)打开起始 URL
在输入框中输入【python】进行搜索,可以发现网页跳转到如下的 URL:
然后,我们再次尝试在输入框中输入【爬虫】进行搜索,网页跳转到如下 URL:
从中,我们不难发现规律,对 URL 进行泛化后可以得到下面的结果(这个也就是我们的起始 URL):
其中,参数 position 就是我们在输入框中输入的内容(需要进行 URL 编码)
(4)设置 cookie
由于拉勾网对未登录用户的访问数量做了限制,所以在浏览一定数量的网页后,网页会自动跳转到登陆界面:
这时,爬虫就不能正常工作了(当时博主就是在这个地方卡了好久,一直没找出原因)
为了解决上面的问题,我们可以使用 cookie 进行模拟登陆
方便起见,可以直接在浏览器中手动获取 cookie,然后将 cookie 信息添加到 browser 中
(5)初始化部分完整代码
# 初始化
def init(self):
# 准备全局变量
self.data = list()
self.isEnd = False
# 启动浏览器、初始化浏览器
opt = webdriver.chrome.options.Options()
opt.set_headless()
self.browser = webdriver.Chrome(chrome_options = opt)
self.wait = WebDriverWait(self.browser,10)
# 打开起始 URL
self.position = input('请输入职位:')
self.browser.get('https://www.lagou.com/jobs/list_' + urllib.parse.quote(self.position) + '?labelWords=&fromSearch=true&suginput=')
# 设置 cookie
cookie = input('请输入cookie:')
for item in cookie.split(';'):
k,v = item.strip().split('=')
self.browser.add_cookie({'name':k,'value':v})
2、爬取数据
在这一部分,我们需要完成以下的两个工作:
爬取网页数据
进行翻页操作
(1)爬取网页数据
在起始页面中,包含有我们需要的职位信息(可以使用 xpath 进行匹配):
链接://a[@class="position_link"]
职位://a[@class="position_link"]/h3
城市://a[@class="position_link"]/span/em
月薪、经验与学历://div[@class="p_bot"]/div[@class="li_b_l"]
公司名称://div[@class="company_name"]/a
这里,我们需要使用 try - except - else 异常处理机制去处理异常,以保证程序的健壮性
(2)进行翻页操作
我们通过模拟点击【下一页】按钮,进行翻页操作
这里,我们同样需要使用 try - except - else 去处理异常
(3)爬取数据部分完整代码
# 爬取网页数据
def parse_page(self):
try:
# 链接
link = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//a[@class="position_link"]')))
link = [item.get_attribute('href') for item in link]
# 职位
position = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//a[@class="position_link"]/h3')))
position = [item.text for item in position]
# 城市
city = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//a[@class="position_link"]/span/em')))
city = [item.text for item in city]
# 月薪、经验与学历
ms_we_eb = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="p_bot"]/div[@class="li_b_l"]')))
monthly_salary = [item.text.split('/')[0].strip().split(' ')[0] for item in ms_we_eb]
working_experience = [item.text.split('/')[0].strip().split(' ')[1] for item in ms_we_eb]
educational_background = [item.text.split('/')[1].strip() for item in ms_we_eb]
# 公司名称
company_name = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="company_name"]/a')))
company_name = [item.text for item in company_name]
except TimeoutException:
self.isEnd = True
except StaleElementReferenceException:
time.sleep(3)
self.parse_page()
else:
temp = list(map(lambda a,b,c,d,e,f,g: {'link':a,'position':b,'city':c,'monthly_salary':d,'working_experience':e,'educational_background':f,'company_name':g}, link, position, city, monthly_salary, working_experience, educational_background, company_name))
self.data.extend(temp)
# 进行翻页操作
def turn_page(self):
try:
pager_next = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'pager_next')))
except TimeoutException:
self.isEnd = True
else:
pager_next.click()
time.sleep(3)
# 爬取数据,调用 parse_page 和 turn_page 方法
def crawl(self):
count = 0
while not self.isEnd :
count += 1
print('正在爬取第 ' + str(count) + ' 页 ...')
self.parse_page()
self.turn_page()
print('爬取结束')
3、保存数据
接下来,我们将数据储存到 JSON 文件中
# 将数据保存到文件中
def save(self):
with open('lagou.json','w',encoding='utf-8') as f:
for item in self.data:
json.dump(item,f,ensure_ascii=False)
这里,有两个需要注意的地方:
在使用 open() 函数时,需要加上参数 encoding='utf-8'
在使用 dump() 函数时,需要加上参数 ensure_ascii=False
4、数据可视化
数据可视化有利于更直观地展示数据之间的关系,根据爬取的数据,我们可以画出如下 4 个直方图:
工作经验-职位数量
工作经验-平均月薪
学历-职位数量
学历-平均月薪
这里,我们需要用到 matplotlib 库,需要注意一个中文编码的问题,可以使用以下的语句解决:
plt.rcParams['font.sans-serif'] = ['SimHei']
# 数据可视化
def draw(self):
count_we = {'经验不限':0,'经验应届毕业生':0,'经验1年以下':0,'经验1-3年':0,'经验3-5年':0,'经验5-10年':0}
total_we = {'经验不限':0,'经验应届毕业生':0,'经验1年以下':0,'经验1-3年':0,'经验3-5年':0,'经验5-10年':0}
count_eb = {'不限':0,'大专':0,'本科':0,'硕士':0,'博士':0}
total_eb = {'不限':0,'大专':0,'本科':0,'硕士':0,'博士':0}
for item in self.data:
count_we[item['working_experience']] += 1
count_eb[item['educational_background']] += 1
try:
li = [float(temp.replace('k','000')) for temp in item['monthly_salary'].split('-')]
total_we[item['working_experience']] += sum(li) / len(li)
total_eb[item['educational_background']] += sum(li) / len(li)
except:
count_we[item['working_experience']] -= 1
count_eb[item['educational_background']] -= 1
# 解决中文编码问题
plt.rcParams['font.sans-serif'] = ['SimHei']
# 工作经验-职位数量
plt.title(self.position)
plt.xlabel('工作经验')
plt.ylabel('职位数量')
x = ['经验不限','经验应届毕业生','经验1-3年','经验3-5年','经验5-10年']
y = [count_we[item] for item in x]
plt.bar(x,y)
plt.show()
# 工作经验-平均月薪
plt.title(self.position)
plt.xlabel('工作经验')
plt.ylabel('平均月薪')
x = list()
y = list()
for item in ['经验不限','经验应届毕业生','经验1-3年','经验3-5年','经验5-10年']:
if count_we[item] != 0:
x.append(item)
y.append(total_we[item]/count_we[item])
plt.bar(x,y)
plt.show()
# 学历-职位数量
plt.title(self.position)
plt.xlabel('学历')
plt.ylabel('职位数量')
x = ['不限','大专','本科','硕士','博士']
y = [count_eb[item] for item in x]
plt.bar(x,y)
plt.show()
# 学历-平均月薪
plt.title(self.position)
plt.xlabel('学历')
plt.ylabel('平均月薪')
x = list()
y = list()
for item in ['不限','大专','本科','硕士','博士']:
if count_eb[item] != 0:
x.append(item)
y.append(total_eb[item]/count_eb[item])
plt.bar(x,y)
plt.show()
5、大功告成
(1)完整代码
至此,整个爬虫过程已经分析完毕,完整的代码如下:
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.common.exceptions import StaleElementReferenceException
import urllib.parse
import time
import json
import matplotlib.pyplot as plt
class Lagou:
# 初始化
def init(self):
self.data = list()
self.isEnd = False
opt = webdriver.chrome.options.Options()
opt.set_headless()
self.browser = webdriver.Chrome(chrome_options = opt)
self.wait = WebDriverWait(self.browser,10)
self.position = input('请输入职位:')
self.browser.get('https://www.lagou.com/jobs/list_' + urllib.parse.quote(self.position) + '?labelWords=&fromSearch=true&suginput=')
cookie = input('请输入cookie:')
for item in cookie.split(';'):
k,v = item.strip().split('=')
self.browser.add_cookie({'name':k,'value':v})
# 爬取网页数据
def parse_page(self):
try:
link = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//a[@class="position_link"]')))
link = [item.get_attribute('href') for item in link]
position = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//a[@class="position_link"]/h3')))
position = [item.text for item in position]
city = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//a[@class="position_link"]/span/em')))
city = [item.text for item in city]
ms_we_eb = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="p_bot"]/div[@class="li_b_l"]')))
monthly_salary = [item.text.split('/')[0].strip().split(' ')[0] for item in ms_we_eb]
working_experience = [item.text.split('/')[0].strip().split(' ')[1] for item in ms_we_eb]
educational_background = [item.text.split('/')[1].strip() for item in ms_we_eb]
company_name = self.wait.until(EC.presence_of_all_elements_located((By.XPATH,'//div[@class="company_name"]/a')))
company_name = [item.text for item in company_name]
except TimeoutException:
self.isEnd = True
except StaleElementReferenceException:
time.sleep(3)
self.parse_page()
else:
temp = list(map(lambda a,b,c,d,e,f,g: {'link':a,'position':b,'city':c,'monthly_salary':d,'working_experience':e,'educational_background':f,'company_name':g}, link, position, city, monthly_salary, working_experience, educational_background, company_name))
self.data.extend(temp)
# 进行翻页操作
def turn_page(self):
try:
pager_next = self.wait.until(EC.element_to_be_clickable((By.CLASS_NAME,'pager_next')))
except TimeoutException:
self.isEnd = True
else:
pager_next.click()
time.sleep(3)
# 爬取数据
def crawl(self):
count = 0
while not self.isEnd :
count += 1
print('正在爬取第 ' + str(count) + ' 页 ...')
self.parse_page()
self.turn_page()
print('爬取结束')
# 保存数据
def save(self):
with open('lagou.json','w',encoding='utf-8') as f:
for item in self.data:
json.dump(item,f,ensure_ascii=False)
# 数据可视化
def draw(self):
count_we = {'经验不限':0,'经验应届毕业生':0,'经验1年以下':0,'经验1-3年':0,'经验3-5年':0,'经验5-10年':0}
total_we = {'经验不限':0,'经验应届毕业生':0,'经验1年以下':0,'经验1-3年':0,'经验3-5年':0,'经验5-10年':0}
count_eb = {'不限':0,'大专':0,'本科':0,'硕士':0,'博士':0}
total_eb = {'不限':0,'大专':0,'本科':0,'硕士':0,'博士':0}
for item in self.data:
count_we[item['working_experience']] += 1
count_eb[item['educational_background']] += 1
try:
li = [float(temp.replace('k','000')) for temp in item['monthly_salary'].split('-')]
total_we[item['working_experience']] += sum(li) / len(li)
total_eb[item['educational_background']] += sum(li) / len(li)
except:
count_we[item['working_experience']] -= 1
count_eb[item['educational_background']] -= 1
# 解决中文编码问题
plt.rcParams['font.sans-serif'] = ['SimHei']
# 工作经验-职位数量
plt.title(self.position)
plt.xlabel('工作经验')
plt.ylabel('职位数量')
x = ['经验不限','经验应届毕业生','经验1-3年','经验3-5年','经验5-10年']
y = [count_we[item] for item in x]
plt.bar(x,y)
plt.show()
# 工作经验-平均月薪
plt.title(self.position)
plt.xlabel('工作经验')
plt.ylabel('平均月薪')
x = list()
y = list()
for item in ['经验不限','经验应届毕业生','经验1-3年','经验3-5年','经验5-10年']:
if count_we[item] != 0:
x.append(item)
y.append(total_we[item]/count_we[item])
plt.bar(x,y)
plt.show()
# 学历-职位数量
plt.title(self.position)
plt.xlabel('学历')
plt.ylabel('职位数量')
x = ['不限','大专','本科','硕士','博士']
y = [count_eb[item] for item in x]
plt.bar(x,y)
plt.show()
# 学历-平均月薪
plt.title(self.position)
plt.xlabel('学历')
plt.ylabel('平均月薪')
x = list()
y = list()
for item in ['不限','大专','本科','硕士','博士']:
if count_eb[item] != 0:
x.append(item)
y.append(total_eb[item]/count_eb[item])
plt.bar(x,y)
plt.show()
if __name__ == '__main__':
obj = Lagou()
obj.init()
obj.crawl()
obj.save()
obj.draw()
(2)运行过程
下面,我们一起来运行代码看看!
在运行代码时,程序会要求输入【职位】和【cookie】,其中,cookie 的获取方法如下:
进入 拉勾网首页,并登陆
使用快捷键 Ctrl+Shift+I 或 F12 打开开发者工具
在输入框中输入【职位(这里的示例为 python)】进行搜索,抓包分析,可以看到 cookie 信息就包含在其中
完整的运行过程如下:
(3)运行结果
注意:本项目代码仅作学习交流使用!!!
python爬虫方向_爬虫实战(三) 用Python爬取拉勾网相关推荐
- 云计算Python自动化运维开发实战 三、python文件类型
为什么80%的码农都做不了架构师?>>> 云计算Python自动化运维开发实战 三.python文件类型 导语: python常用的有3种文件类型 1. 源代码 py ...
- Python爬虫实战之一 - 基于Requests爬取拉勾网招聘信息,并保存至本地csv文件
Python爬虫实战之二 - 基于Requests抓取拉勾网招聘信息 ---------------readme--------------- 简介:本人产品汪一枚,Python自学数月,对于小白,本 ...
- python爬取京东评论分析_【实战好文】|爬取京东书籍评论并分析
原标题:[实战好文]|爬取京东书籍评论并分析 这是菜鸟学Python的粉丝第10篇原创投稿 阅读本文大概需要5分钟 本篇作者:小郑同学 上周的赠书活动中,收到了楼主送的<利用Python进行数据 ...
- Python爬虫实战(三) 免登录爬取东野圭吾超话——看看你喜欢的书上榜没?
微博爬虫可以不借助selenium,直接用Chrome下的手机端模式打开,找到其封装的json数据,即可爬取,具体步骤如下. 分析过程 以东野圭吾超话为例,网址为微博超话.进入页面后,使用Chrome ...
- python爬电影排名用os bs4_Pyhton网络爬虫实例_豆瓣电影排行榜_BeautifulSoup4方法爬取...
-----------------------------------------------------------学无止境------------------------------------- ...
- 人工智能python就业方向_目前最全的Python的就业方向
Python是一门面向对象的编程语言,编译速度超快,从诞生到现在已经25个年头了.它具有丰富和强大的库,常被称为"胶水语言",能够把用其他语言编写的各种模块(尤其是C/C++)很轻 ...
- python用selenium爬取网页数据_Python项目实战:使用selenium爬取拉勾网数据
" 一切不经过项目验证的代码都是耍流氓,今天我们就通过一个简单的招聘网站的数据归档进行当前热门岗位的大数据分析,最后以wordcloud进行显示.本文为数据爬取篇." 项目准备: ...
- python list除以_扫描器篇(三)之python编写基于字典的网站目录探测脚本
工具原理: 通过读取字典获取内容,拼接url执行get http请求获取 响应状态码,根据状态码判断目录文件资源是否存在 1 2 思路: 工具命令行参数获取 1 字典读取 1 多线程访问 1 状态码获 ...
- Python爬虫新手入门教学(十七):爬取yy全站小视频
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. Python爬虫.数据分析.网站开发等案例教程视频免费在线观看 https://space. ...
- Python爬虫新手入门教学(十):爬取彼岸4K超清壁纸
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. Python爬虫.数据分析.网站开发等案例教程视频免费在线观看 https://space. ...
最新文章
- MikroTik Routeros Wlan应用之-pppoe Server
- Algs4-2.2.29自然的归并排序(未解决)
- corosync+pacemaker+drbd构建mysql高可用平台的简单案例
- python统计个数的函数_Python
- python画简单花-Python竟能画这么漂亮的花,帅呆了(代码分享)
- 购物车清除的php,php-如何清除废弃的woocommerce购物车
- 问答专场 | 我是高级商业产品总监吴波,你有什么想问的?
- raid5加热备盘_联想服务器X3650 M2 配置RAID5与热备盘图文方法
- python apply函数不打印_Python Pandas dataframe shift在apply函数中不起作用
- 文件共享服务器 域组访问设置权限,怎么对局域网所共享的文件进行访问权限管理...
- np.ones(),np.zeros(), np.empty(),np.full(),np.ones_like() 基本用法
- 超级牛散股神叶健颜专找重组题材股,精准买入,不服不行。
- 潇洒学校丹丹老师分享免喷涂材料注塑工艺的五大要点
- Eclipse设立编辑器为绿豆沙颜色
- 西安交通大学计算机张飞导师,航海学院邀请西安交通大学段战胜教授来院作学术报告...
- Twitter推特爬虫工具开发
- Java中为什么不能用“==”判断字符串是否相等
- 基于DDD的现代ASP.NET开发框架--ABP系列文章总目录
- 【算法竞赛学习笔记】快速傅里叶变换FFT-数学提高计划
- linux 命令学习大全,初学者必备
热门文章
- 计算机二级C语言选择题——01
- linux yum用法,Linux系统yum的使用与说明
- 程序员是一群什么样的人,1024程序员节调查报告」这群IT人有点东西哟
- pandas报错:columns overlap but no suffix specified
- lol服务器维护局,lol维护局 英雄联盟钻石维护局掉多少分
- u盘安装linux系统有什么弊端,使用U盘安装Linux系统的经验总结
- 智能人物画像综合分析系统——Day16
- 每日学点python之六(列表与元组)
- 【机器学习】十二、一文看懂支持向量机原理
- 机器学习sklearn基础(1):多元逻辑回归分类器 (pcolormesh说明及绘图)