目录
一、介绍
用 Selenium 爬取网页时,当前访问的 url 就是爬虫当中的目标 url,获取内容只要是页面上可见的,都可以爬取(可见即可爬)。
步骤
Selenium + 浏览器 + 浏览器驱动
1、导入
2、url(找动态 url,抓取到的数据是加密的)
3、获取内容,做解析
Selenium 是一个用于 Web 应用程序测试的工具,最初是为网站自动化测试而开发的,Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器,可以接收指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏。
chromedriver 是一个驱动 Chrome 浏览器的驱动程序,使用它才可以驱动浏览器。
针对不同的浏览器有不同的 driver,但 Chrome 的兼容性最好。
二、对比
Ajax:可以使用网页实现异步更新,可以在不重新加载整个网页的情况下,对网页的某部分进行更新。
1、获取 Ajax 数据的方式
- 直接分析 Ajax 调用的接口,然后通过代码请求这个接口。
- 使用 Selenium + chromedriver 模拟浏览器行为获取数据。
2、获取 Ajax 数据方式对比
方式优点缺点找数据接口直接可以请求到数据,代码量少,性能高分析接口比较复杂,尤其通过 js 混淆的接口,容易被发现是爬虫Selenium直接模拟浏览器行为,浏览器能请求到的,使用 Selenium 也能请求到代码量多,性能低
三、安装
1、驱动下载地址
下载 Chrome 驱动
下载 Firefox 驱动
2、安装 Selenium 第三方库(建议指定版本安装)
pip install selenium==4.0.0a1
3、安装驱动(Chrome 的兼容性最好,建议安装 chromedriver)
- 先确定浏览器版本号
- 打开谷歌驱动下载地址
- 版本号前面三位对应上就可以,最后一位建议选择版本小的
- 按照电脑的系统来选择下载(如果电脑是 windows-64 位,选 win32 就行)
- 驱动下载完成之后,将文件进行解压,复制到 chromedriver.exe 到 Python 解释器目录下
终端输入命令:where python 可以查看 Python 的安装目录
四、简单使用
# 导入模块,加载驱动from selenium import webdriver
# 内置库import time
# 加载驱动
drive = webdriver.Chrome()# 窗口最大化
drive.maximize_window()# 加载网站
drive.get('https://www.baidu.com')# 代码停3秒再运行
time.sleep(3)# 关闭当前的窗口# drive.close() # 要打开多个窗口,关闭的是当前的窗口# 退出驱动
drive.quit()# 关闭所有窗口,退出浏览器
五、定位元素
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 加载驱动
driver = webdriver.Chrome()# 窗口最大化
driver.maximize_window()# 加载网站
driver.get('https://www.baidu.com')
1、By.ID
根据 id 来查找定位元素。
# find_element 找一个元素,find_elements 找多个
el = driver.find_element(By.ID,'kw')# 返回的是一个元素对象print(el)
2、By.CLASS_NAME
通过 class 属性值定位某个元素。
el = driver.find_element(By.CLASS_NAME,'s_ipt')# 返回的是一个元素对象print(el)
3、By.NAME
通过 name 属性查找定位某个元素。
el = driver.find_element(By.NAME,'wd')# 返回的是一个元素对象print(el)
4、By.TAG_NAM
通过标签定位元素。
input_tag = driver.find_elements(By.TAG_NAME,'input')# find_elements 定位元素,返回的数据类型是 listprint(input_tag)
5、By.XPATH
通过 xpath 语法定位元素。
el = driver.find_element(By.XPATH,'//input[@id="kw"]')# 返回的是一个元素对象print(el)
六、操作元素
1、在输入框输入内容并搜索
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 加载驱动
driver = webdriver.Chrome()# 窗口最大化
driver.maximize_window()# 加载网站
driver.get('https://www.baidu.com')# 定位到元素
el = driver.find_element(By.ID,'kw')# 元素输入框里面输入值
el.send_keys('唐僧')# 等待2秒
time.sleep(2)# 点击元素
driver.find_element(By.ID,'su').click()# 清空内容
el.clear()
2、打开网站搜索音乐并播放
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 操作键盘from selenium.webdriver.common.keys import Keys
# 加载驱动
driver = webdriver.Chrome()# 窗口最大化
driver.maximize_window()# 加载网站
driver.get('https://music.163.com/')# 搜索内容
driver.find_element(By.ID,'srch').send_keys('愿')# 按回车键
driver.find_element(By.ID,'srch').send_keys(Keys.ENTER)# 等待2秒
time.sleep(2)# 网页里面嵌套了一个网页,要进入该网页才会获取对应的数据
driver.switch_to.frame('g_iframe')# 播放按钮
driver.find_element(By.ID,'song_2010214999').click()
七、Cookie 操作
1、获取所有的 Cookie
cookies = driver.get_cookies()
2、根据 Cookie 的 name 获取 Cookie
value = driver.get_cookie(name)
3、删除某个 Cookie
driver.delete_cookie('key')
4、处理 Cookie
# 导入模块,加载驱动from selenium import webdriver
# 加载驱动
driver = webdriver.Chrome()# 窗口最大化
driver.maximize_window()# 加载网站
driver.get('https://www.baidu.com')# 获取百度的 cookie
cookies = driver.get_cookies()# 返回的 list,列表里面嵌套的字典print(cookies)'''
通过程序拿到的 cookie 与页面的是不一致,还需要做处理
只需要里面的两个字段值,name 和 value
BAIDUID_BFESS=F875E52E04E65B3748D8FDDE2E25399E; ZFY=idY6KuND2T0e6ROY1txjofI8Nvn4lb6hXiw:BN2mgeaA:C
'''for cookie in cookies:print(cookie['name']+'='+ cookie['value'])
5、案例
模拟登录 qq 空间
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 加载驱动
driver = webdriver.Chrome()# 最大化窗口
driver.maximize_window()# 加载网站
driver.get('https://i.qq.com/')# 切换 iframe
driver.switch_to.frame('login_frame')# 等待2秒
time.sleep(2)# 点击头像进行登录,获取登录之后的 cookie
driver.find_element(By.ID,'img_out_1234567890').click()# 等待2秒
time.sleep(2)# 获取 cookie
cookies = driver.get_cookies()# 打印出的数据为列表# print(cookies)# 获取的 cookie 需要处理
li =[]for cookie in cookies:# 只需要每一组字典里面的 name value
li.append(cookie['name']+'='+cookie['value'])# print(cookie)# 处理好的 cookie
cookie ='; '.join(li)print(cookie)# 导入库import requests
# 确定 url, 静态加载的
url ='https://user.qzone.qq.com/1234567890'# 设置请求头参数
head ={'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36','cookie': cookie
}# 发请求,获取响应
res = requests.get(url, headers=head)# 获取响应内容# print(res.text)# 写入文件withopen('qq.html','w', encoding='utf-8')as f:
f.write(res.text)
八、Selenium 操作下拉菜单
select 元素不能直接点击,因为点击后还需要选中元素,这时候 selenium 就专门为 select 标签提供了一个类。
from selenium.webdriver.support.ui import Select
将获取到的元素当成参数传到这个类中,创建这个对象后,就可以使用这个对象进行选择了。
案例
目标网站:https://news.sina.com.cn/
需求:选择娱乐版块,日期8号相关新闻
分析:
1、打开对应网站
2、点击下拉菜单,选择对应的版块内容
3、点击日期图标,选择的日期是8号
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 专门针对 Select 标签使用from selenium.webdriver.support.ui import Select
# 定位元素from selenium.webdriver.common.by import By
# 加载驱动
driver = webdriver.Chrome()# 最大化窗口
driver.maximize_window()# 加载网站
driver.get('https://news.sina.com.cn/')# 解析,直接定位到 select 标签
el = driver.find_element(By.NAME,'channel')# print(el)# 定位到娱乐的板块,实例化 select 对象
select_tag = Select(el)# 定位下拉框# 方法一# select_tag.select_by_index(4) # 下标从0开始的# 方法二# select_tag.select_by_value('ent') # 根据 option 里面 value 属性定位的# 方法三
select_tag.select_by_visible_text('娱乐')# text 指的是文本# 等待1秒
time.sleep(1)# 定位日期
driver.find_element(By.NAME,'date').click()# 选择8号
driver.find_element(By.XPATH,'//div[@id="dataView"]/div/table/tbody/tr[2]/td[2]').click()
九、Selenium 鼠标行为链
页面中需要借助鼠标操作元素,那么这时候可以使用鼠标行为链类 ActionChains 来完成,比如现在要将鼠标移动到某个元素上并执行点击事件。
学习文档
1、常用方法
actions = ActionChains(driver)# 实例化⼀个⿏标⾏为链的对象
actions.move_to_element(inputTag)# 将⿏标移动到元素的中间
actions.send_keys_to_element(inputTag,'python')# 将键发送到元素
actions.move_to_element(submitTag)# 将⿏标移动到元素的中间
actions.context_click()# 对元素执⾏上下⽂单击(右键单击)
actions.click(submitTag)# 单击⼀个元素
actions.perform()# 执⾏所有存储的操作
actions.lick_and_hold(element)# 点击但不松开⿏标
actions.double_click(element)# 双击
更多方法可参考
2、案例
目标网站:https://passport.vip.com/login?src=https%3A%2F%2Fwww.vip.com%2F
需求:
1、加载网站
2、切换登录方式
3、输入账号密码,勾选协议,点击登录案例
4、鼠标移动到对应的验证码元素上面
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 导入鼠标行为链from selenium.webdriver import ActionChains
# 加载驱动
driver = webdriver.Chrome()# 最大化窗口
driver.maximize_window()# 加载网站
driver.get('https://passport.vip.com/login?src=https%3A%2F%2Fwww.vip.com%2F')# 等待2秒
time.sleep(2)# 切换登录方式 —— 1、定位元素 2、点击
driver.find_element(By.XPATH,'//div[@class="c-tab-nav "]/div[2]').click()# 等待0.5秒
time.sleep(0.5)# 输入用户名
driver.find_element(By.ID,'J_login_name').send_keys('3424234234')# 输入密码
driver.find_element(By.ID,'J_login_pwd').send_keys('34234242')# 等待0.5秒
time.sleep(0.5)# 勾选协议
inputs = driver.find_element(By.ID,'J_login_agree')# 定位到这个元素# 通过 click 无法点击成功,可以采用 js 点击
driver.execute_script('arguments[0].click();', inputs)# 登录
driver.find_element(By.ID,'J_login_submit').click()# 等待1秒
time.sleep(1)# 定位图片
img = driver.find_element(By.CLASS_NAME,'vipsc_qimg')# 鼠标移动
actions = ActionChains(driver)
actions.move_to_element(img)# 移动到目标位置# 提交行为链
actions.perform()
十、Selenium 切换页面与操作多窗口
1、切换页面
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 加载驱动
driver = webdriver.Chrome()# 最大化窗口
driver.maximize_window()# 先模拟打开多个网站
driver.get('https://www.baidu.com')# 百度
time.sleep(3)
driver.execute_script('window.open("https://www.douban.com/")')# 豆瓣
time.sleep(3)
driver.execute_script('window.open("https://juejin.cn/")')# 掘金
time.sleep(3)
driver.execute_script('window.open("https://cloud.tencent.com/developer/ask/sof/1237007")')# 腾讯
time.sleep(3)# 打印鼠标聚焦的 url# print(driver.current_url)# 切换窗口
driver.switch_to.window(driver.window_handles[-3])'''
0:https://www.baidu.com
1:https://cloud.tencent.com/developer/ask/sof/1237007
2:https://juejin.cn/
3:https://www.douban.com/
-1:https://www.douban.com/
-2:https://juejin.cn/
-3:https://cloud.tencent.com/developer/ask/sof/1237007
'''# 打印鼠标聚焦的 urlprint(driver.current_url)
2、多窗口操作
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 加载驱动
driver = webdriver.Chrome()# 最大化窗口
driver.maximize_window()# 加载网站
driver.get('https://juejin.cn/')# 等待2秒
time.sleep(2)# 定位第二篇文章
driver.find_element(By.XPATH,'//div[@class="entry-list list"]/li[2]').click()# 等待1秒
time.sleep(1)# 切换窗口
driver.switch_to.window(driver.window_handles[1])# 获取 elements 内容
te = driver.page_source
print(te)
十一、Selenium 高级操作
1、page_source:返回结构的源码
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 加载驱动
driver = webdriver.Chrome()# 最大化窗口
driver.maximize_window()# 加载网站
driver.get('https://music.163.com/#/discover/toplist')# 等待2秒
time.sleep(2)# 切换到 iframe
driver.switch_to.frame('g_iframe')# 等待2秒
time.sleep(2)# 拿到的是 elements 里面的内容,xpath 直接做解析就可以了print(driver.page_source)
2、find():在源码当中查找某个字符的存在
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 加载驱动
driver = webdriver.Chrome()# 最大化窗口
driver.maximize_window()# 加载网站
driver.get('https://tieba.baidu.com/f?kw=%E8%8F%9C%E8%B0%B1&ie=utf-8&pn=11400')# 等待2秒
time.sleep(2)# # 获取网页源码# html = driver.page_source# # 打印源码# print(html)# # 看网页源码里是否存在下一页# print(driver.page_source.find('下一页>'))'''
如果没有查找到对应的字符,返回的是-1
如果查找到了,返回的是数字
'''whileTrue:# 判断源码里存在下一页时if driver.page_source.find('下一页>')!=-1:# 点击下一页的按钮
driver.find_element(By.CLASS_NAME,'next').click()# 等待1秒
time.sleep(1)# 源码里不存在下一页时,跳出循环else:print('已经是最后一页了')break
3、By.LINK_TEXT:根据链接文本定位
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 加载驱动
driver = webdriver.Chrome()# 最大化窗口
driver.maximize_window()# 加载网站
driver.get('https://movie.douban.com/top250')# 等待2秒
time.sleep(2)# 获取网页源码
html = driver.page_source
# 等待1秒
time.sleep(1)# 根据链接文本定位,点击‘后页>’
driver.find_element(By.LINK_TEXT,'后页>').click()# 打印点击‘后页>’后的文本print(driver.page_source)
4、get_attribute():获取属性值
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 加载驱动
driver = webdriver.Chrome()# 最大化窗口
driver.maximize_window()# 加载网站
driver.get('https://movie.douban.com/top250')# 等待2秒
time.sleep(2)# 获取图片标签
img_tag = driver.find_element(By.XPATH,'//div[@class="pic"]/a/img')# 获取属性值 —— 通过方法print(img_tag.get_attribute('src'))
5、.text:获取节点内容
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 加载驱动
driver = webdriver.Chrome()# 最大化窗口
driver.maximize_window()# 加载网站
driver.get('https://movie.douban.com/top250')# 等待2秒
time.sleep(2)# 获取文本内容
div_tag = driver.find_element(By.XPATH,'//div[@class="hd"]').text
# 打印文本内容print(div_tag)
十二、设置无界面
# 内置库import time
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 设置参数
options = webdriver.ChromeOptions()# 设置无界面模式
options.add_argument('--headless')# 传递参数
driver = webdriver.Chrome(options=options)# 加载网站
driver.get('https://movie.douban.com/top250')# 等待3秒
time.sleep(3)# 获取图片标签
img_tag = driver.find_element(By.XPATH,'//div[@class="pic"]/a/img')# 打印属性值print(img_tag.get_attribute('src'))
十三、页面等待
1、强制等待
time.sleep(时间)
2、隐式等待
调用 driver.implicitly_wait ,针对所有元素,设置等待时间,如果等待时间内加载出来,代码继续往下走,等待时间以内不断刷新看元素是否加载出来,超出则报出异常。
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 加载驱动
driver = webdriver.Chrome()# 加载网站
driver.get('https://www.baidu.com')# 显示等待,针对的全局元素
driver.implicitly_wait(10)# 10秒内出现代码继续往下走
driver.find_element(By.ID,'kw').send_keys('python')# 等待10秒不出现就会报错
driver.find_element(By.ID,'kw1').send_keys('python')
3、显示等待
表明某个条件成立后才执行获取元素的操作,也可以在等待的时候指定一个最大的时间,如果超过这个时间那么就抛出一个异常。
# 显示等待,需要导入模块# 导入 WebDriverWait 类from selenium.webdriver.support.wait import WebDriverWait
# 导入 expected_conditions 模块并使用别名 ECfrom selenium.webdriver.support import expected_conditions as EC
# 导入模块,加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 显示等待,需要导入模块# 导入 WebDriverWait 类from selenium.webdriver.support.wait import WebDriverWait
# 导入 expected_conditions 模块并使用别名 ECfrom selenium.webdriver.support import expected_conditions as EC
# 加载驱动
driver = webdriver.Chrome()# 加载网站
driver.get('https://www.baidu.com')# 默认是0.5秒刷新一次# 等待时间总共是10秒,每隔1秒刷新一次# until 具体的条件内容
element = WebDriverWait(driver,10,1).until(# 判断元素是否加载出来
EC.presence_of_element_located((By.ID,'kw')))
element.send_keys('hello')
隐式等待针对的是全局元素,全局生效,代码简单,只用于查找元素。
显示等待有很多的判断条件,适用范围更广,只针对某一个元素。
十四、案例
目标网站: https://juejin.cn/
需求:爬取文章内容,保存为 txt 格式,文件名以文章标题命名
分析:
翻页方式:滑动滚动条进行加载内容
1、设置先滚动5次,先把下面的内容加载出来,获取元素
2、先获取所有 li 元素,遍历 li 元素,进行点击操作
# 内置库import time
# 加载驱动from selenium import webdriver
# 定位元素from selenium.webdriver.common.by import By
# 正则import re
classJuJin(object):# 定义初始化方法def__init__(self):# 实例属性# 加载驱动
self.driver = webdriver.Chrome()# 窗口最大化
self.driver.maximize_window()# 加载网站
self.driver.get('https://juejin.cn/')# 解析数据defparse_html(self):# 等待2秒
time.sleep(2)# 获取 li 里的所有数据
lis = self.driver.find_elements(By.XPATH,'//div[@class="entry-list list"]/li')# 循环处理数据for li in lis:# 捕获异常try:# 等待2秒
time.sleep(2)# 获取文章标题标签
a = li.find_element(By.CLASS_NAME,'title')# 点击标题标签进入详情页
self.driver.execute_script('arguments[0].click();', a)# 切换窗口到内容页
self.driver.switch_to.window(self.driver.window_handles[1])# 等待2秒
time.sleep(2)# 获取标题标签
title = self.driver.find_elements(By.CLASS_NAME,'article-title')# 获取文章内容标签
contents = self.driver.find_elements(By.XPATH,'//div[@class="markdown-body cache"]/p')# 判断标题是否是空列表,如果是空列表,说明文章是广告文章ifnot title:# 获取标题标签
title = self.driver.find_elements(By.XPATH,'//a[@class="title"]/span')# 获取文章内容标签
contents = self.driver.find_elements(By.XPATH,'//div[@class="markdown-body"]/p')# 获取标题文本
titles = title[0].text
# 正则表达式替换标题特殊字符
titles = re.sub(r'[,?/<>!: ()|"]','', titles)# 定义组装数据的变量
s =''# 获取数据为列表,需循环取出for i in contents:# 组装数据
s += i.text +'\n'# 打印文章标题,内容# print(titles)# 保存数据
self.save_data(titles, s)# 关闭当前窗口
self.driver.close()# 切换窗口到列表页
self.driver.switch_to.window(self.driver.window_handles[0])# 等待1秒
time.sleep(1)except Exception as e:# 打印异常print(e)print("没有文章内容")# 关闭当前窗口
self.driver.close()# 切换窗口到列表页
self.driver.switch_to.window(self.driver.window_handles[0])# 保存数据defsave_data(self, title, contents):# 创建 txt 文本文档withopen(f'掘金/{title}.txt','w', encoding='utf-8')as f:# 文件写入
f.write(contents)# 滚动方法defslide(self, height):# 滑动滚动条
self.driver.execute_script(f'window.scrollTo(0,{height})')# 处理主逻辑defmain(self):# 获取窗口的高度
heights = self.driver.get_window_size()['height']# 滑动次数
page =1# 滑动while page <=5:
self.slide(heights)# 加高度
heights = heights + heights
# 滑动次数+1
page +=1# 等待1秒
time.sleep(1)# 解析数据
self.parse_html()# 创建对象
data = JuJin()# 调用 main 方法,开始执行主程序
data.main()
记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~
版权归原作者 永远十八的小仙女~ 所有, 如有侵权,请联系我们删除。