一、概述

Selenium自动化测试工具,可模拟用户输入,选择,提交。

爬虫实现的功能:

  1. 输入python,选择地点:上海,北京 ---->就去爬取上海,北京2个城市python招聘信息
  2. 输入会计,选择地址:广州,深圳,杭州---->就去爬取广州,深圳,杭州3个城市会计招聘信息
  3. 根据输入的不同,动态爬取结果

二、页面分析

输入关键字

selenium怎么模拟用户输入关键字,怎么选择城市,怎么点击搜索按钮?

Selenium模拟用户输入关键字,谷歌浏览器右键输入框,点检查,查看代码

通过selenium的find_element_by_id 找到 id = 'kwdselectid',然后send_keys('关键字')即可模拟用户输入

代码为:

textElement = browser.find_element_by_id('kwdselectid')
textElement.send_keys('python')

选择城市

selenium模拟用户选择城市--- (这个就难了,踩了很多坑)

点击城市选择,会弹出一个框

然后选择:北京,上海,  右键检查,查看源代码

可以发现:value的值变成了"北京+上海"

那么是否可以用selenium找到这个标签,更改它的属性值为"北京+上海",可以实现选择城市呢?

答案:不行,因为经过自己的几次尝试,发现真正生效的是下面的"010000,020000",这个是什么?城市编号,也就是说在输入"北京+上海",实际上输入的是:"010000,020000", 那这个城市编号怎么来的,这个就需要去爬取51job弹出城市选择框那个页面了,页面代码里面有城市对应的编号

获取城市编号

getcity.py代码:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import json# 设置selenium使用chrome的无头模式
chrome_options = Options()
chrome_options.add_argument("--headless")
# 在启动浏览器时加入配置
browser = webdriver.Chrome(options=chrome_options)
cookies = browser.get_cookies()
browser.delete_all_cookies()
browser.get('https://www.51job.com/')
browser.implicitly_wait(20)# 找到城市选择框,并模拟点击
button = browser.find_element_by_xpath("//div[@class='ush top_wrap']//div[@class='el on']/p\
[@class='addbut']//input[@id='work_position_input']").click()# 选中城市弹出框
browser.current_window_handle# 定义一个空字典
dic = {}# 找到城市,和对应的城市编号
find_city_elements = browser.find_elements_by_xpath("//div[@id='work_position_layer']//\
div[@id='work_position_click_center_right_list_000000']//tbody/tr/td")
for element in find_city_elements:number = element.find_element_by_xpath("./em").get_attribute("data-value")  # 城市编号city = element.find_element_by_xpath("./em").text  # 城市# 添加到字典dic.setdefault(city, number)
print(dic)
# 写入文件
with open('city.txt', 'w', encoding='utf8') as f:f.write(json.dumps(dic, ensure_ascii=False))
browser.quit()

执行输出:

{'北京': '010000', '上海': '020000', '广州': '030200', '深圳': '040000', '武汉': '180200', '西安': '200200', '杭州': '080200', '南京': '070200', '成都': '090200', '重庆': '060000', '东莞': '030800', '大连': '230300', '沈阳': '230200', '苏州': '070300', '昆明': '250200', '长沙': '190200', '合肥': '150200', '宁波': '080300', '郑州': '170200', '天津': '050000', '青岛': '120300', '济南': '120200', '哈尔滨': '220200', '长春': '240200', '福州': '110200'}

通过selenium的find_element_by_xpath 找到城市编号这个input,然后读取city.txt文件,把对应的城市替换为城市编号,在用selenium执行js代码,就可以加载城市了---代码有点长,完整代码写在后面

selenium模拟用户点击搜索

通过selenium的find_element_by_xpath 找到 这个button按钮,然后click() 即可模拟用户点击搜索

代码为:

browser.find_element_by_xpath("//div[@class='ush top_wrap']/button").click()

以上都是模拟用户搜索的行为,下面就是对数据提取规则

先定位总页数:158页

找到每个岗位详细的链接地址:

最后定位需要爬取的数据

岗位名,薪水,公司名,招聘信息,福利待遇,岗位职责,任职要求,上班地点,工作地点 这些数据,总之需要什么数据,就爬什么

需要打开岗位详细的链接,比如:https://jobs.51job.com/shanghai-mhq/118338654.html?s=01&t=0

三、完整代码

代码介绍

新建目录51cto-selenium,结构如下:

./
├── get51Job.py
├── getcity.py
└── mylog.py

文件说明:

getcity.py  (首先运行)获取城市编号,会生成一个city.txt文件

mylog.py     日志程序,记录爬取过程中的一些信息

get51Job.py 爬虫主程序,里面包含:

Item类  定义需要获取的数据GetJobInfo类 主程序类getBrowser方法     设置selenium使用chrome的无头模式,打开目标网站,返回browser对象userInput方法        模拟用户输入关键字,选择城市,点击搜索,返回browser对象getUrl方法               找到所有符合规则的url,返回urls列表spider方法               提取每个岗位url的详情,返回itemsgetresponsecontent方法  接收url,打开目标网站,返回html内容piplines方法            处理所有的数据,保存为51job.txtgetPageNext方法   找到总页数,并获取下个页面的url,保存数据,直到所有页面爬取完毕

getcity.py

# !/usr/bin/python3
# -*- coding: utf-8 -*-#!/usr/bin/env python
# coding: utf-8
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import json# 设置selenium使用chrome的无头模式
chrome_options = Options()
chrome_options.add_argument("--headless")
# 在启动浏览器时加入配置
browser = webdriver.Chrome(options=chrome_options)
cookies = browser.get_cookies()
browser.delete_all_cookies()
browser.get('https://www.51job.com/')
browser.implicitly_wait(20)# 找到城市选择框,并模拟点击
button = browser.find_element_by_xpath("//div[@class='ush top_wrap']//div[@class='el on']/p\
[@class='addbut']//input[@id='work_position_input']").click()# 选中城市弹出框
browser.current_window_handle# 定义一个空字典
dic = {}# 找到城市,和对应的城市编号
find_city_elements = browser.find_elements_by_xpath("//div[@id='work_position_layer']//\
div[@id='work_position_click_center_right_list_000000']//tbody/tr/td")
for element in find_city_elements:number = element.find_element_by_xpath("./em").get_attribute("data-value")  # 城市编号city = element.find_element_by_xpath("./em").text  # 城市# 添加到字典dic.setdefault(city, number)
print(dic)
# 写入文件
with open('city.txt', 'w', encoding='utf8') as f:f.write(json.dumps(dic, ensure_ascii=False))
browser.quit()

View Code

get51Job.py

# !/usr/bin/python3
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from mylog import MyLog as mylog
import json
import time
import requests
from lxml import etreeclass Item(object):job_name = None  # 岗位名company_name = None  # 公司名work_place = None  # 工作地点salary = None  # 薪资release_time = None  # 发布时间job_recruitment_details = None  # 招聘岗位详细job_number_details = None  # 招聘人数详细company_treatment_details = None  # 福利待遇详细practice_mode = None  # 联系方式class GetJobInfo(object):"""the all data from 51job.com所有数据来自前程无忧招聘网"""def __init__(self):self.log = mylog()  # 实例化mylog类,用于记录日志self.startUrl = 'https://www.51job.com/'  # 爬取的目标网站self.browser = self.getBrowser()  # 设置chromeself.browser_input = self.userInput(self.browser)  # 模拟用户输入搜索self.getPageNext(self.browser_input)   # 找到下个页面def getBrowser(self):"""设置selenium使用chrome的无头模式打开目标网站 https://www.51job.com/:return: browser"""try:# 创建chrome参数对象chrome_options = Options()# 把chrome设置成无界面模式,不论windows还是linux都可以,自动适配对应参数chrome_options.add_argument("--headless")# 在启动浏览器时加入配置browser = webdriver.Chrome(options=chrome_options)# 利用selenium打开网站browser.get(self.startUrl)# 等待网站js代码加载完毕browser.implicitly_wait(20)except Exception as e:# 记录错误日志self.log.error('打开目标网站失败:{},错误代码:{}'.format(self.startUrl, e))else:# 记录成功日志self.log.info('打开目标网站成功:{}'.format(self.startUrl))# 返回实例化selenium对象return browserdef userInput(self, browser):"""北京 上海 广州 深圳 武汉 西安 杭州南京  成都 重庆 东莞 大连 沈阳 苏州昆明 长沙 合肥 宁波 郑州 天津 青岛济南 哈尔滨 长春 福州只支持以上城市,输入其它则无效最多可选5个城市,每个城市用 , 隔开(英文逗号):return:browser"""time.sleep(1)# 用户输入关键字搜索search_for_jobs = input("请输入职位搜索关键字:")# 用户输入城市print(self.userInput.__doc__)select_city = input("输入城市信息,最多可输入5个,多个城市以逗号隔开:")# 找到51job首页上关键字输入框textElement = browser.find_element_by_id('kwdselectid')# 模拟用户输入关键字textElement.send_keys(search_for_jobs)# 找到城市选择弹出框,模拟选择"北京,上海,广州,深圳,杭州"button = browser.find_element_by_xpath("//div[@class='ush top_wrap']\//div[@class='el on']/p[@class='addbut']//input[@id='jobarea']")# 打开城市对应编号文件with open("city.txt", 'r', encoding='utf8') as f:city_number = f.read()# 使用json解析文件city_number = json.loads(city_number)new_list = []# 判断是否输入多值if len(select_city.split(',')) > 1:for i in select_city.split(','):if i in city_number.keys():# 把城市替换成对应的城市编号i = city_number.get(i)new_list.append(i)# 把用户输入的城市替换成城市编号select_city = ','.join(new_list)else:for i in select_city.split(','):i = city_number.get(i)new_list.append(i)select_city = ','.join(new_list)# 执行js代码browser.execute_script("arguments[0].value = '{}';".format(select_city), button)# 模拟点击搜索browser.find_element_by_xpath("//div[@class='ush top_wrap']/button").click()self.log.info("模拟搜索输入成功,获取目标爬取title信息:{}".format(browser.title))return browserdef getPageNext(self, browser):# 找到总页数str_sumPage = browser.find_element_by_xpath("//div[@class='p_in']/span[@class='td'][1]").textsumpage = ''for i in str_sumPage:if i.isdigit():sumpage += i# sumpage = 1self.log.info("获取总页数:{}".format(sumpage))s = 1while s <= int(sumpage):urls = self.getUrl(self.browser)# 获取每个岗位的详情self.items = self.spider(urls)# 数据下载self.pipelines(self.items)# 清空urls列表,获取后面的url(去重,防止数据重复爬取)urls.clear()s += 1self.log.info('开始爬取第%d页' % s)# 找到下一页的按钮点击# NextTag = browser.find_element_by_partial_link_text("下一页").click()NextTag = browser.find_element_by_class_name('next').click()# 等待加载js代码browser.implicitly_wait(20)time.sleep(3)self.log.info('获取所有岗位成功')# browser.quit()def getUrl(self, browser):# 创建一个空列表,用来存放所有岗位详情的urlurls = []# 创建一个特殊招聘空列表job_urls = []# 获取所有岗位详情urlElements = browser.find_elements_by_xpath("//div[@class='j_joblist']//div[@class='e']")for element in Elements:try:url = element.find_element_by_xpath("./a").get_attribute("href")title = element.find_element_by_xpath('./a/p/span[@class="jname at"]').get_attribute('title')except Exception as e:self.log.error("获取岗位详情失败,错误代码:{}".format(e))else:# 排除特殊的url,可单独处理src_url = url.split('/')[3]if src_url == 'sc':job_urls.append(url)self.log.info("获取不符合爬取规则的详情成功:{},添加到job_urls".format(url))else:urls.append(url)self.log.info("获取详情成功:{},添加到urls".format(url))return urlsdef spider(self, urls):# 数据过滤,爬取需要的数据,返回items列表items = []for url in urls:htmlcontent = self.getreponsecontent(url)html_xpath = etree.HTML(htmlcontent)item = Item()# 岗位名job_name = html_xpath.xpath("normalize-space(//div[@class='cn']/h1/text())")item.job_name = job_name# 公司名company_name = html_xpath.xpath("normalize-space(//div[@class='cn']\/p[@class='cname']/a/text())")item.company_name = company_name# 工作地点work_place = html_xpath.xpath("normalize-space(//div[@class='cn']\//p[@class='msg ltype']/text())").split('|')[0].strip()item.work_place = work_place# 薪资salary = html_xpath.xpath("normalize-space(//div[@class='cn']/strong/text())")item.salary = salary# 发布时间release_time = html_xpath.xpath("normalize-space(//div[@class='cn']\//p[@class='msg ltype']/text())").split('|')[-1].strip()item.release_time = release_time# 招聘岗位详细job_recruitment_details_tmp = html_xpath.xpath("//div[@class='bmsg job_msg inbox']//text()")if not job_recruitment_details_tmp:breakitem.job_recruitment_details = ''ss = job_recruitment_details_tmp.index("职能类别:")ceshi = job_recruitment_details_tmp[:ss - 1]for i in ceshi:item.job_recruitment_details = item.job_recruitment_details + i.strip() + '\n'# 招聘人数详细job_number_details_tmp = html_xpath.xpath("normalize-space(//div[@class='cn']\//p[@class='msg ltype']/text())").split('|')item.job_number_details = ''for i in job_number_details_tmp:item.job_number_details = item.job_number_details + ' ' + i.strip()# 福利待遇详细company_treatment_details_tmp = html_xpath.xpath("//div[@class='t1']//text()")item.company_treatment_details = ''for i in company_treatment_details_tmp:item.company_treatment_details = item.company_treatment_details + ' ' + i.strip()# 联系方式practice_mode_tmp = html_xpath.xpath("//div[@class='bmsg inbox']/p//text()")item.practice_mode = ''for i in practice_mode_tmp:item.practice_mode = item.practice_mode + ' ' + i.strip()items.append(item)return itemsdef getreponsecontent(self, url):# 接收url,打开目标网站,返回htmlfakeHeaders = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 \(KHTML, like Gecko) Chrome/67.0.3396.62 Safari/537.36'}try:response = requests.get(url=url,headers=fakeHeaders)# 利用apparent_encoding,自动设置编码response.encoding = response.apparent_encodinghtml = response.textexcept Exception as e:self.log.error(u'Python 返回 url:{} 数据失败\n错误代码:{}\n'.format(url, e))else:self.log.info(u'Python 返回 url:{} 数据成功\n'.format(url))time.sleep(1)  # 1秒返回一个结果  手动设置延迟防止被封return htmldef pipelines(self, items):  # 接收一个items列表# 数据下载filename = u'51job.txt'with open(filename, 'a', encoding='utf-8') as fp:for item in items:fp.write('job_name:{}\ncompany_name:{}\nwork_place:{}\nsalary:\{}\nrelease_time:{}\njob_recruitment_details:{}\njob_number_details:\{}\ncompany_treatment_details:\{}\n\practice_mode:{}\n\n\n\n' \.format(item.job_name, item.company_name, item.work_place,item.salary, item.release_time,item.job_recruitment_details,item.job_number_details, item.company_treatment_details,item.practice_mode))self.log.info(u'岗位{}保存到{}成功'.format(item.job_name, filename))if __name__ == '__main__':st = GetJobInfo()

View Code

mylog.py

# !/usr/bin/python3
# -*- coding: utf-8 -*-
import logging
import getpass
import sys# 定义MyLog类
class MyLog(object):def __init__(self):self.user = getpass.getuser()  # 获取用户self.logger = logging.getLogger(self.user)self.logger.setLevel(logging.DEBUG)# 日志文件名self.logfile = sys.argv[0][0:-3] + '.log'  # 动态获取调用文件的名字self.formatter = logging.Formatter('%(asctime)-12s %(levelname)-8s %(message)-12s\r\n')# 日志显示到屏幕上并输出到日志文件内self.logHand = logging.FileHandler(self.logfile, encoding='utf-8')self.logHand.setFormatter(self.formatter)self.logHand.setLevel(logging.DEBUG)self.logHandSt = logging.StreamHandler()self.logHandSt.setFormatter(self.formatter)self.logHandSt.setLevel(logging.DEBUG)self.logger.addHandler(self.logHand)self.logger.addHandler(self.logHandSt)# 日志的5个级别对应以下的5个函数def debug(self, msg):self.logger.debug(msg)def info(self, msg):self.logger.info(msg)def warn(self, msg):self.logger.warning(msg)def error(self, msg):self.logger.error(msg)def critical(self, msg):self.logger.critical(msg)if __name__ == '__main__':mylog = MyLog()mylog.debug(u"I'm debug 中文测试")mylog.info(u"I'm info 中文测试")mylog.warn(u"I'm warn 中文测试")mylog.error(u"I'm error 中文测试")mylog.critical(u"I'm critical 中文测试")

View Code

运行程序

需要先运行getcity.py,获取城市编号,运行结果如下

{'北京': '010000', '上海': '020000', '广州': '030200', '深圳': '040000', '武汉': '180200', '西安': '200200', '杭州': '080200', '南京': '070200', '成都': '090200', '重庆': '060000', '东莞': '030800', '大连': '230300', '沈阳': '230200', '苏州': '070300', '昆明': '250200', '长沙': '190200', '合肥': '150200', '宁波': '080300', '郑州': '170200', '天津': '050000', '青岛': '120300', '济南': '120200', '哈尔滨': '220200', '长春': '240200', '福州': '110200'}

在运行主程序get51Job.py

关键字输入: python

城市选择:上海

pycharm运行截图:

生成的文件51job.txt截图

根据输入结果的不同,爬取不同的信息,利用selenium可以做到动态爬取

注意:如果遇到51job页面改版,本程序运行会报错。请根据实际情况,修改对应的爬虫规则。

本文参考链接:http://www.py3study.com/Article/details/id/344.html

SeleniumChrome实战:动态爬取51job招聘信息相关推荐

  1. scrapy爬虫实战(二)-------------爬取IT招聘信息

    主要从智联招聘,51job,周伯通三个网站爬取IT类企业的招聘信息,并按照编程语言和职位数量和平均薪资进行统计,计算. 源代码github地址: https://github.com/happyAng ...

  2. Python爬取51job招聘信息

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取 python免费学习资 ...

  3. Python爬虫实战之一 - 基于Requests爬取拉勾网招聘信息,并保存至本地csv文件

    Python爬虫实战之二 - 基于Requests抓取拉勾网招聘信息 ---------------readme--------------- 简介:本人产品汪一枚,Python自学数月,对于小白,本 ...

  4. 什么你还不知道招聘信息,小唐来教你——最新2021爬取拉勾网招聘信息(一)

    文章目录 前言 一.准备我们的库 二.分析分析 三. 代码 四.数据展示 小唐的心路历程 上一篇:没有啦! 下一篇:什么你还不知道招聘信息,小唐来教你--最新2021爬取拉勾网招聘信息(二) 前言 有 ...

  5. Python Scrapy爬虫框架爬取51job职位信息并保存至数据库

    Python Scrapy爬虫框架爬取51job职位信息并保存至数据库 -------------------------------- 版权声明:本文为CSDN博主「杠精运动员」的原创文章,遵循CC ...

  6. 使用Python爬取51job招聘网的数据

    使用Python爬取51job招聘网的数据 进行网站分析 获取职位信息 存储信息 最终代码 进行网站分析 进入https://www.51job.com/这个网站 我在这就以python为例搜索职位跳 ...

  7. Python搭建代理池爬取拉勾网招聘信息

    先来看一张图了解下爬虫 实现功能 多线程爬取拉勾网招聘信息 维护代理 ip 池 搭建 node 服务器 Taro 使用 echarts 做数据分析 1.多线程爬取拉勾网招聘信息 Tip:涉及知识 1. ...

  8. scrapy爬取——阿里招聘信息

    scrapy爬取--阿里招聘信息 爬取网站地址: https://job.alibaba.com/zhaopin/positionList.htm 1.创建项目 进入项目目录 输入cmd进入都是窗口创 ...

  9. 什么你还不知道招聘信息,小唐来教你——最新2021爬取拉勾网招聘信息(二)

    文章目录 前言 一.准备我们的库 二.数据清洗 三.核密度图及词云制作 四.完整代码 五.扩展 上一篇:什么你还不知道招聘信息,小唐来教你--最新2021爬取拉勾网招聘信息(一) 下一篇:没有拉! 前 ...

最新文章

  1. 【Go语言】LiteIDE使用的个人使用方法
  2. 【数学基础】一份非常适合人工智能学习的高等数学基础材料中文版 (国内教材精华)...
  3. es查询index生成时间_Elasticsearch第二谈(ES核心概念、ES简单操作、构建查询、查询结果过滤排序分页、term和match查询区别、自定义查询结果高亮)...
  4. java中length的用法
  5. 电瓶车续航测试软件,【电驹视频】实测13款电动车真实续航,最靠谱的竟然是它……...
  6. excel如何去重统计户数_excel表格单一数据统计-Excel如何去重,然后统计数据?...
  7. 计算机组成原理:MIPS
  8. “绝美画卷”网站欣赏
  9. 随机数生成器python
  10. 面试技巧:HR常问的70个问题回答技巧
  11. usb右下角有显示,计算机没显示,U盘显示在计算机的右下角,但无法打开
  12. 看51CTO新闻的感想(宝兰)
  13. 手机android系统锁了怎么解决方法,安卓手机被恶意软件锁机了怎么办?试下这五种方法...
  14. 用于单图像超分辨率的增强深度残差网络
  15. 海外社交媒体平台如何选择
  16. 2018年-读书笔记
  17. 平安居家养老服务上市
  18. UN Comtrade(联合国商品贸易统计数据库)数据爬取Python代码——使用动态IP
  19. 建筑八大员培训湖北施工员培训建筑施工企业员工流失的原因
  20. 单片机ADC采样算法----有效值采样法

热门文章

  1. 文本编辑器Vim/Neovim被曝任意代码执行漏洞,Notepad:兄弟等你好久了
  2. 基于Arduino的视觉暂留现象和频闪效应演示系统程序设计
  3. hxy系列5-反向传播
  4. 学习日记-Adobe 卸载美工软件
  5. Java基础教程带你走进java的世界
  6. 计算机三级数据库笔记
  7. 天气API 实时降水预报接口, 实时降雨量数据接口
  8. 怎么去除广告(百度推广,阿里妈妈推广等)
  9. Hive---浅谈Hive
  10. 12月英语计算机统考时间,网络教育2019年12月统考时间与统考科目