python selenium 获取js的变量 python selenium获取html_Chrome

前言

        Selenium 是一个用于Web应用程序测试的工具。

        Selenium 测试直接运行在浏览器中,就像真正的用户在操作一样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera,Edge等。

        这个工具的主要功能包括:

浏览器兼容性测试:测试应用程序看是否能够很好的工作在不同浏览器和操作系统之上;

系统功能测试:创建回归测试检验软件功能和用户需求;

支持自动录制动作和自动生成.Net、Java、Perl等不同语言的测试脚本。

        通过本篇,你将学会使用 selenium 动态加载HTML的技巧,包括:操作输入框,键盘,下拉条,页面跳转,标签内容读取...。


正文

        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 】自动导入插件,以后者为例:

python selenium 获取js的变量 python selenium获取html_Selenium_02


三、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"】

python selenium 获取js的变量 python selenium获取html_动态加载_03

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. 页面交互:搜索框输入,上下滚动下拉条,页面前进和后退

常用方法

描述

send_keys(var str)

标签栏输入 str,需要先获取标签位置

send_keys(Keys.PAGE_UP)

翻页键上(Page Up),需要先获取标签位置

send_keys(Keys.PAGE_DOWN)

翻页键下(Page Down),需要先获取标签位置

execute_script('window.scrollTo(0,document.body.scrollHeight)')

向下滚动到底部

execute_script('window.scrollTo(0,0)')

向上滚动到顶部

execute_script('window.scrollTo(0,int n)')

向下滚动 n px 位置

script = "arguments[0].scrollIntoView();";

driver.execute_script(script, driver.find_element(By.xx, 'xx'))

向下滚动到目标元素位置,如:ID = xx

  • 案例:
import time                                  # 时间控制
from selenium import webdriver               # 浏览器驱动
from selenium.webdriver import Keys          # 键盘驱动
from selenium.webdriver.common.by import By  # 节点定位

driver = webdriver.Chrome()
driver.get('https://www.jd.com/')
# 根据id属性获取【输入框】
_input = driver.find_element(By.ID, 'key')
# 标签内输入搜索内容
_input.send_keys('华为mate50')
# 标签内操作向上,向下翻页
_input.send_keys(Keys.PAGE_DOWN)
_input.send_keys(Keys.PAGE_UP)
# 根据class属性获取【搜索】按钮,触发点击事件
driver.find_element(By.CLASS_NAME, 'button').click()
# 向下滚动到底部
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
# 向上滚动到顶部
driver.execute_script('window.scrollTo(0,0)')
# 向下滚动1000位置
driver.execute_script('window.scrollTo(0,1000)')
time.sleep(2)
# 向下滚动目标元素位置
script = "arguments[0].scrollIntoView();";
driver.execute_script(script, driver.find_element(By.ID, 'J_bottomPage'))
time.sleep(2)
driver.get('https://www.baidu.com/')
driver.back()
time.sleep(2)
driver.forword()
time.sleep(2)
driver.close()
  • 输入+点击的代码可以简化一下:
driver.find_element(By.ID, 'key').send_keys("华为mate50")

4. 页面等待:显式,隐式

        当进入一个新的网页时,有时网页的加载并没有那没快,当网速很慢时尤其明显,特别是针对商品列表,图片类的信息,这时候是爬不到完整数据的,所以,我们需要等待页面加载完成。

        等待的方式有3种:

  • 强制等待:必须等这么久,没有任何前提条件,和页面有没有渲染无关;
  • 隐性等待:设置一个时间,在设置的时间内,如果页面加载完成了就进行下一步;如果没有加载完成,则会报超时异常;
  • 显式等待:设置一个等待时间,一个间隔时间,每隔一段时间执行下util中的方法,直到等待时间结束。

 注意:虽然 time.sleep(n) 简单,但是有时设置的睡眠时间过长,干等很浪费效率的,所以一般只用在想要暂停代码查看页面效果的地方,就像案例中一样。

使用方法

描述

强制

time.sleep(int n)

强制等待 n 秒,不关注页面渲染情况

隐式

driver.implicitly_wait(int n)

等待 n 秒,如果页面加载出来就继续,否则报异常

显式

wait = WebDriverWait(driver, int n, int m)

wait.until(EC.presence_of_element_located((By.By.xx, 'xx')))

等待 n 秒,每隔 m 秒 加载一下 until 方法,如果 until 方法内的属性加载出来则继续,否则循环,直到 n 秒结束继续执行。

注:xx代表标签属性

  • 案例:
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,粘贴

6. selenium转BeautifulSoup

        根据小编的开发经验,selenium 很擅长模拟和测试,它的特性是BeautifulSoup不具备的,但是对于取值操作,简单的还好,复杂点的比如循环<li>标签这种操作,我还是觉得BeautifulSoup更方便。

        在爬虫的世界里,大量有价值的数据都是循环展现的,比如:某排行榜,某商品列表等...所以,selenium+BeautifulSoup的操作必不可少。

  • 核心代码
from selenium import webdriver       # 浏览器驱动
from bs4 import BeautifulSoup        # 解析html

driver = webdriver.Chrome()
driver.get('https://www.jd.com/')
# 获取完整渲染的网页源代码
pageSource = driver.page_source 
soup = BeautifulSoup(pageSource,'html.parser')
# ...

四、注意事项

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 其他 ...