Python爬虫:selenium动态加载HTML的常用方法【汇总笔记】
前言
Selenium 是一个用于Web应用程序测试的工具。
Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera,Edge等。
这个工具的主要功能包括:
- 浏览器兼容性测试:测试应用程序看是否能够很好的工作在不同浏览器和操作系统之上;
- 系统功能测试:创建回归测试检验软件功能和用户需求;
-
支持自动录制动作和自动生成.Net、Java、Perl等不同语言的测试脚本。
正文
Selenium 是浏览器自动测试框架,模拟浏览器,驱动浏览器执行特定的动作,并可获取浏览器当前呈现的页面的源代码,可见即可爬。正是利用了这一特点,Python 可以实现对动态页面的渲染,做到可见即可爬。
一、chromedriver 驱动安装
Selenium 相当于机器人,可以模拟人在浏览器中的行为,并自动处理浏览器中的行为,如:单击、翻页、输入数据、回车和删除cookie操作。 而 Chromedriver 是 Chrome 浏览器的驱动程序,可以移动浏览器。
1. 驱动程序介绍
驱动器因浏览器而异,案例以 Chrome 浏览器为例,以下是各种浏览器及其相应的驱动程序:
浏览器 | 驱动地址 |
---|---|
Chrome | http://chromedriver.storage.googleapis.com/index.html |
Edge | https://developer.Microsoft.com/en-us/Microsoft-edge/tools/web驱动程序/ |
Firefox | https://github.com/Mozilla/gecko driver/releases |
Safari | https://WebKit.org/blog/6900/web驱动程序- support-in-safari-10 |
2. 驱动程序安装
注意:Chromedriver 要下载与本地 Chrome 浏览器相对应的版本。
建议:直接使用 Chromedriver 驱动的绝对路径,这样做能规避很多坑,听我的没错。
from selenium import webdriver
# 指定chromedriver的绝对路径
driver_path = r'C:\Users\Administrator\Desktop\chromedriver.exe'
# 初始化driver
drive = webdriver.Chrome(executable_path=driver_path)
# 请求页面,打开网页
drive.get("https://www.baidu.com/")
# 通过page_source获取网页源代码
print(drive.page_source)
# 关闭网页
drive.close()
Chromedriver 主要负责爬取动态页面的前面部分 -- 打开HTML页面,后面页面的渲染和操作,就是 Selenium 的工作内容了。
二、Selenium 插件安装
在【Terminal】控制台"pip install selenium "命令导入,或者在导航栏下【Pycharm - Settings - Python Interpreter 】自动导入插件,以后者为例:
三、Selenium 常用方法
1. 获取节点信息
据说旧版本是使用【find_element_by_xx】方法获取节点,新版本已经不可用了,我目前使用的 Selenium 为【4.4.3】版本:
- 获取单个节点信息(多个则匹配第一个):find_element(By.xx, 'xx')
- 获取多个节点信息(加S):find_elements(By.xx, 'xx')
常用方法 | 描述 |
---|---|
By.ID | 根据id值获取对应的节点 |
By.NAME | 根据name值获取对应的单个或多个节点 |
By.TAG_NAME | 根据节点名获取节点 |
By.CLASS_NAME | 根据class值获取节点 |
By.LINK_TEXT | 根据链接文本获取对应的节点 |
By.PARTIAL_LINK_TEXT | 根据部分链接文本获取对应的节点 |
By.CSS_SELECTOR | 根据CSS选择器获取节点,对应的value字符串字符串CSS位置 |
By.XPATH | 根据By.XPATH获取节点,对应的value字符串节点位置 |
- 案例:
from selenium import webdriver # 浏览器驱动
from selenium.webdriver.common.by import By # 节点定位
driver = webdriver.Chrome()
driver.get('https://www.jd.com/')
# 通过id属性获取节点
driver.find_element(By.ID, 'key').send_keys("华为mate50")
# 通过class属性获取节点,并触发点击事件
driver.find_element(By.CLASS_NAME, 'button').click()
time.sleep(5)
driver.close()
- HTML说明:输入框和按钮的属性分别是【id="key"】和【class="button"】
2. 获取元素属性
常用方法 | 描述 |
---|---|
get_attribute(xx) | 获取当前节点xx属性 |
id | 获取当前节点id |
location | 获取当前节点位置 |
tag_name | 获取当前节点名称 |
size | 获取当前节点大小 |
text | 获取当前节点文本 |
- 案例:
from selenium import webdriver
driver = webdriver.Chrome()
driver.get('https://www.jd.com/')
el_div = driver.find_element(By.ID, 'key')
print(el_div)
print(el_div.get_attribute("class")) # class属性
print(el_div.id) # id
print(el_div.location) # 位置
print(el_div.tag_name) # 标签名
print(el_div.size) # 大小
print(el_div.text) # 文本
3. 页面交互:搜索框输入,上下滚动下拉条,页面前进和后退
- 案例:
import time # 时间控制
from selenium import webdriver # 浏览器驱动
from selenium.webdriver.common.by import By # 节点定位
driver = webdriver.Chrome()
driver.get('https://www.jd.com/')
# 根据id属性获取【输入框】,输入搜索内容
_input = browser.find_element(By.ID, 'kw')
_input.send_keys('华为mate50')
# 根据class属性获取【搜索】按钮,触发点击事件
driver.find_element(By.CLASS_NAME, 'button').click()
# 向下滚动到底部
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
time.sleep(3)
# 向上滚动到顶部
driver.execute_script('window.scrollTo(0,0)')
time.sleep(3)
driver.get('https://www.baidu.com/')
driver.back()
time.sleep(3)
driver.forword()
time.sleep(3)
driver.close()
- 输入+点击的代码可以简化一下:
driver.find_element(By.ID, 'key').send_keys("华为mate50")
4. 页面等待:显式,隐式
当进入一个新的网页时,有时网页的加载并没有那没快,当网速很慢时尤其明显,特别是针对商品列表,图片类的信息,这时候是爬不到完整数据的,所以,我们需要等待页面加载完成。
等待的方式有3种:
- 强制等待:必须等这么久,没有任何前提条件,和页面有没有渲染无关;
- 隐性等待:设置一个时间,在设置的时间内,如果页面加载完成了就进行下一步;如果没有加载完成,则会报超时异常;
- 显示等待:设置一个等待时间,一个间隔时间,每隔一段时间执行下util中的方法,直到等待时间结束。
注意:虽然 time.sleep(n) 简单,但是有时设置的睡眠时间过长,干等很浪费效率的,所以一般只用在想要暂停代码查看页面效果的地方,就像案例中一样。
- 案例:
import time # 时间控制
from selenium import webdriver # 浏览器驱动
from selenium.webdriver.common.by import By # 节点定位
driver = webdriver.Chrome()
driver.get('https://www.jd.com/')
# 根据id属性获取【搜索框】位置,输入搜索内容
driver.find_element(By.ID, 'key').send_keys("华为mate50")
# 根据class属性获取【搜索】按钮位置,触发点击事件
driver.implicitly_wait(5)
driver.find_element(By.CLASS_NAME, 'button').click()
wait = WebDriverWait(driver, 10, 0.2)
wait.until(EC.presence_of_element_located((By.CLASS_NAME, "p-img")))
# 向下滚动到底部
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
time.sleep(3)
# 向上滚动到顶部
driver.execute_script('window.scrollTo(0,0)')
time.sleep(3)
driver.close()
5. 键盘事件
代码 | 含义 |
---|---|
Keys.BACK_SPACE | 回退键(BackSpace) |
Keys.TAB | 制表键(Tab) |
Keys.ENTER | 回车键(Enter) |
Keys.SHIFT | 大小写转换键(Shift) |
Keys.CONTROL | Control键(Ctrl) |
Keys.ALT | ALT键(Alt) |
Keys.ESCAPE | 返回键(Esc) |
Keys.SPACE | 空格键(Space) |
Keys.PAGE_UP | 翻页键上(Page Up) |
Keys.PAGE_DOWN | 翻页键下(Page Down) |
Keys.END | 行尾键(End) |
Keys.HOME | 行首键(Home) |
Keys.LEFT | 方向键左(Left) |
Keys.UP | 方向键上(Up) |
Keys.RIGHT | 方向键右(Right) |
Keys.DOWN | 方向键下(Down) |
Keys.INSERT | 插入键(Insert) |
DELETE | 删除键(Delete) |
NUMPAD0 ~ NUMPAD9 | 数字键1-9 |
F1 ~ F12 | F1 - F12键 |
(Keys.CONTROL, ‘a’) | 组合键Control+a,全选 |
(Keys.CONTROL, ‘c’) | 组合键Control+c,复制 |
(Keys.CONTROL, ‘x’) | 组合键Control+x,剪切 |
(Keys.CONTROL, ‘v’) | 组合键Control+v,粘贴 |
四、注意事项
4.1 no such element: Unable to locate element
在某些场景下使用 selenium 的 driver.find_element(By.CLASS_NAME,'xxxx') 定位web元素的时候,会提示找不到定位元素的异常,比如:我们案例中要定位的包含 class="button cw-icon" 属性的按钮。
- 异常原文
selenium.common.exceptions.NoSuchElementException: Message: no such element: Unable to locate element: {"method":"css selector","selector":".button cw-icon"}
- 原因分析
经过认真检查,发现从web上获取的元素的class_name并没有错,问题的原因只能是多个属性间的空格“ ”不能被 find_element() 识别造成的。
- 解决办法
针对前端代码一个标签内使用多个属性值的情况,我们只需要把class_name里面的空格间隔符替换成英文的“.”就可以了。
# 注释掉的为原方法,未注释的是修改以后的方法
# driver.find_element(By.CLASS_NAME,'button cw-icon').click()
driver.find_element(By.CLASS_NAME,'button.cw-icon').click()
4.2 其他 ...