可见即可爬:Selenium

Selenium是通过拖放控件的方式设计UI,设计是什么样,运行就是什么样。

一.安装Selenium和WebDriver

1.安装Selenium

pip安装

pip install selenium

离线安装
在该网址中找到https://www.lfd.uci.edu/~gohlke/pythonlibs/#lxmlselenium的包
然后解压到该目录下,cmd命令cd到该目录下,执行如下命令

pip install selenium‑3.141.0‑py3‑none‑any.whl

2.安装WebDriver

2.1Chrome版本的WebDriver称为ChromeDriver

ChromeDriver的官网https://chromedriver.chromium.org/

2.1.1使用ChromeDriver:

下载下来的ChromeDriver.exe是一个可执行文件,要将ChromeDriver.exe文件添加到PATH环境变量中,这样在任何路径下都可以执行ChromeDriver。或者将下载下来的ChromeDriver放到指定目录下,在使用ChromeDriver时指定其路径即可

2.1.2

在python中使用ChromeDriver

from selenium import webdriver
browser = webdriver.Chrome()

执行上述代码会立刻启动一个Chrome浏览器的实例,也可以通过Chrome类的构造方法指定ChromeDriver的路径

from selenium import webdriver
browser = webdriver.Chrome('./webdriver/ChromeDriver')

2.2装Edge WebDriver

下载地址https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/

2.2.1在python中使用Edge WebDriver

from selenium import webdriver
browser = webdriver.Edge()

同样也可以指定Web WebDriver路径;可类比Chrome

三.Selenium的基本使用方法

3.1打开浏览器

from selenium import webdriver
browser = webdriver.Chrome('./webdriver/chromedriver')
browser.get('https://www.jd.com')

3.2控制浏览器页面的控件

模拟按键,首先需要找到接收按键动作的节点
Selenium支持多种方式查找节点,如通过id属性,通过class属性。然后可以通过send_keys方法模拟按键的动作

from selenium import webdriver
browser = webdriver.Chrome('./webdriver/chromedriver.exe')
browser.get('https://www.jd.com')
input = browser.find_element_by_id('key')
input.send_keys('Python从菜鸟到高手')
input.send_keys(Keys.ENTER)

完整代码

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
browser = webdriver.Chrome('./webdriver/chromedriver.exe)
try:
    browser.get('https://www.jd.com')
    # 根据id的属性值来查找搜索框
    input = browser.find_element_by_id('key')
    # 使用send_keys方法向搜索框中输入文本
    input.send_keys('Python从菜鸟到高手')
    # 使用send_keys方法按下ENTER键
    input.send_keys(Keys.ENTER)
    # 设置WebDriverWait对象,设置等待时间(4秒)
    wait = WebDriverWait(browser,4)
    # 等待搜索页面显示(通过查找id值为J_goodsList的节点判断搜索页面是否显示)
    wait.until(ec.presence_of_all_elements_located((By.ID,'J_goodsList')))
    # 显示搜索页面的标题
    print(browser.title)
    # 显示搜索页面的URL
    print(browser.current_url)
    # 显示搜索页面的代码
    print(browser.page_source)
    # 关闭浏览器
    browser.close()

except Exception as e:
    print(e)
    browser.close()

在上面代码使用了WebDriverWait类,该类是为了在执行的过程中等待一段时间,这里设置为4秒。这是由于按下ENTER键后,并不一定马上显示搜索结果,需要一定的延长,但python程序不会等待搜索结果出来再往下继续执行下去,就会造成python程序已经运行到处理搜索结果页面的位置时,搜索结果页面还没显示出来。所以使用WebDriverWait类的until方法判断搜索结果页面是否显示完成。

wait = WebDriverWait(browser,4)
    # 等待搜索页面显示(通过查找id值为J_goodsList的节点判断搜索页面是否显示)
wait.until(ec.presence_of_all_elements_located((By.ID,'J_goodsList')))

四.查找节点

4.1查找单个节点

find_element开头的方法都是用于查找单个节点的API.
如下图所示

上述API列表可以看到,Selenium支持通过多种方式查找节点,如XPath、CSS选择器、class属性、id属性、标签名等。这些方法使用都一样,只是需要传入不同的参数值
本例通过使用Selenium通过id属性、name属性、和class属性获取表单中特定的input节点,并自动输入表单的内容
这里查找的网页是用服务器挂载的静态页面

from selenium import webdriver
from selenium.webdriver.common.by import By
# 不支持本地网页
browser = webdriver.Chrome('./webdriver/chromedriver')
try:
    browser.get('http://localhost/demo.html')
    input = browser.find_element_by_id('name')
    input.send_keys('王军')
    input = browser.find_element_by_id('age')
    input.send_keys('30')

    input = browser.find_element_by_name('country')
    input.send_keys('中国')

    input = browser.find_element_by_class_name('myclass')
    input.send_keys('4000')

    # 或下面的代码
    input = browser.find_element(By.CLASS_NAME,'myclass')
    input.clear()  # 不清空  追加
    input.send_keys('8000')



except Exception as e:
    print(e)
    browser.close()

4.2查找多个节点

查找多个节点返回的是一个列表,而查找单个节点返回的是一个节点
若没有符合条件的节点,就会返回空列表
这些API都是以find_elements开头的方法
uploading-image-874268.png

本例使用Selenium通过节点名查找所有符合条件的节点,并输入节点本身、符合条件的节点总数以及第一个符合条件的节点的文本

from selenium import webdriver
from selenium.webdriver.common.by import By
# 不支持本地网页
browser = webdriver.Chrome('./webdriver/chromedriver')
try:
    browser.get('https://www.jd.com')
    input = browser.find_elements_by_tag_name('li')

    print(input)
    print(len(input))
    print(input[0].text)
    input = browser.find_elements(By.TAG_NAME,'ul')
    print(input)
    print(input[0].text)
    
    browser.close()

except Exception as e:
    print(e)
    browser.close()

4.5节点交互

例如click方法可以模拟单击节点的动作
本例使用Selenium通过模拟浏览器单击动作循环单击页面上的6个按钮,单击每个按钮后,按钮下方的div就会按照按钮的背景色设置div的背景色

from selenium import webdriver
import time

browser = webdriver.Chrome('./webdriver/chromedriver')
try:
    browser.get('http://localhost/demo1.html')
    buttons = browser.find_elements_by_class_name('mybutton')
    i = 0
    while True:
        buttons[i].click()
        time.sleep(1)
        i += 1
        if i == len(buttons):
            i = 0

except Exception as e:
    print(e)
    browser.close()

4.6动作链

在前面的交互动作中,交互动作都是针对某个节点执行的,例如,对于某个input节点输入一个字符串、模拟单击某一个按钮等。但还有另外一类交互动作,他们没有特定的执行对象,比如鼠标拖拽、键盘按键等,其实这些动作相当于全局事件,需要另外一种方式执行,这就是动作链。
动作链需要创建ActionChains对象,并通过ActionChains类的若干方法向浏览器发送一个或多个动作。
本例会使用Selenium动作链的move_to_element方法模拟鼠标移动的动作,自动显示京东商城首页左侧的每个二级导航菜单。

from selenium import webdriver
from selenium.webdriver import ActionChains
import time
browser = webdriver.Chrome()
try:
    browser.get('https://www.jd.com')
    # 创建一个ActionChains对象
    actions = ActionChains(browser)
    # 通过CSS选择器查找所有class属性值为cate_menu_item的li节点,每一个li节点
    # 是一个二级导航栏

    li_list = browser.find_elements_by_css_selector(".cate_menu_item")
    # 通过迭代,显示每一个二级菜单,调用动作链中方法发送动作后,必须调用preform方法才能生效
    for li in li_list:
        actions.move_to_element(li).perform()
        time.sleep(1)
except Exception as e:
    print(e)
    browser.close()

本例演示地址是https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable,目的使用drag_and_drop方法将页面右侧的小方块拖到大方块上。

from selenium import webdriver
from selenium.webdriver import ActionChains

browser = webdriver.Chrome('./webdriver/chromedriver')
try:
    browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
    browser.switch_to.frame('iframeResult')
    source = browser.find_element_by_css_selector('#draggable')
    target = browser.find_element_by_css_selector('#droppable')
    actions = ActionChains(browser)
    # 调用drag_and_drop方法拖动节点
    actions.drag_and_drop(source, target)
    # 调用perform方法让拖动生效
    actions.perform()
except Exception as e:
    print(e)
    browser.close()

注意,如果页面存在iframe节点,而且要操作iframe中的节点,需要首先使用frame方法切换到iframe节点,才能操作里面的子节点。

4.7执行JavaScript代码

对于某些操作,Selenium并没有提供相应的API,例如,下拉页面,不过可以使用Selenium的execute_script方法直接运行JavaScript代码,以便扩展Selenium的功能。
本例会使用Selenium的execute_script方法让京东商城首页滚动到最低端,然后弹出一个对话框。

from selenium import webdriver
browser = webdriver.Chrome('./webdriver/chromedriver')
browser.get('https://www.jd.com')
# 将京东商城滚动到最低端
browser.execute_script('window.scrollTo(0,document.body.scrollHeight)')
# 弹出对话框
browser.execute_async_script('alert("已经到达页面底端")')

4.8获取节点信息

使用Selenium的API还可以获得详细的节点信息,如节点的位置,节点名称,节点尺寸和几点属性等。
本例会使用Selenium的API获取京东商城首页HTML代码中id为navitems-groupl的ul节点的相关信息以及ul节点中li节点的相关信息

from selenium import webdriver
from selenium.webdriver import ActionChains
options = webdriver.ChromeOptions()
# 添加参数,不让Chrome浏览器显示,只在后台运行
options.add_argument('headless')

browser = webdriver.Chrome('./webdriver/chromedriver',chrome_options=options)
#browser = webdriver.PhantomJS('./webdriver/phantomjs')
browser.get('https://www.jd.com')
# 查找页面中id属性值为navitems-group1的第一个节点
ul = browser.find_element_by_id("navitems-group1")
print(ul.text)
print('id','=',ul.id)  # 内部id,不是节点id属性值
print('location','=',ul.location)

print('tag_name','=',ul.tag_name)
print('size','=',ul.size)
li_list = ul.find_elements_by_tag_name("li")
for li in li_list:
    print(type(li))
    # 属性没找到,返回None
    print('<',li.text,'>', 'class=',li.get_attribute('class'))
    a = li.find_element_by_tag_name('a')
    print('href','=',a.get_attribute('href'))
browser.close()

五.管理Cookie

使用Selenium,可以方便的管理Cookie,例如获取Cookie、添加和删除Cookie等
本例使用Selenium API获取Cookie列表,并添加新的Cookie,以及删除所有的Cookie。

from selenium import webdriver
browser = webdriver.Chrome('./webdriver/chromedriver')
browser.get('https://www.jd.com')
# 为获取Cookie列表
print(browser.get_cookies())
# 添加新的Cookie
browser .add_cookie({'name': 'name',
 'value':'jd','domain':'www.jd.com'})
print(browser.get_cookies())
# 删除所有的Cookie
browser.delete_all_cookies()
print(browser.get_cookies())  # 大部分删除了,可能还剩下一些

六.管理节点的属性值

Selenium本身并没有提供修改节点属性的API,不过可以通过执行JavaScript代码的方式设置节点属性,而且通过Selenium获取的节点可以直接作为DOM使用,这就意味着可以直接在JavaScript代码中使用查找到的节点。
execute_script方法的第一个参数用于指定Javascript代码,后面的可变参数,可以为Javascript代码传递参数。通过arguments变量获取每一个参数值,例如arguments[0]表示第1个参数值,arguments[1]表示第2个参数值,以此类推。

6.1本例会通过JavaScript代码改变百度搜索按钮的位置,让这个按钮在多个位置之间移动,时间间隔是2秒。

from selenium import webdriver
import time
driver = webdriver.Chrome('./webdriver/chromedriver')
driver.get("http://www.baidu.com")
search_button = driver.find_element_by_id("su")  # 百度搜索按钮
# arguments[0]对应的是第一个参数,可以理解为python里的%s传参,与之类似
# 定义搜索坐标可以移动到x的坐标位置
x_positions = [50,90,130,170]
y_positions = [100,120,160,90]
for i in range(len(x_positions)):
    # 用于移动的JavaScript代码,arguments[0]就是搜索按钮对应的DOM
    js = '''
     arguments[0].style.position = "absolute";
     arguments[0].style.left="{}px";
     arguments[0].style.top="{}px";
    '''.format(x_positions[i],y_positions[i])
    # 执行JS代码,并开始移动搜索按钮
    driver.execute_script(js, search_button)
    time.sleep(2)

6.2本例使用JS代码修改京东商城首页顶端的前两个导航菜单的文本和链接,分别改成....。导航链接也会改变

from selenium import webdriver
import time
driver = webdriver.Chrome('./webdriver/chromedriver')
driver.get("https://www.jd.com")
ul = driver.find_element_by_id('navitems-group1')
li_list = ul.find_elements_by_tag_name('li')
a1 = li_list[0].find_element_by_tag_name('a')
a2 = li_list[1].find_element_by_tag_name('a')
js = '''
 arguments[0].text = 'Python从菜鸟到高手'
 arguments[0].href = 'https://item.jd.com/12417265.html'
 arguments[1].text = '极客起源'
 arguments[1].href = 'https://geekori.com'
 '''
driver.execute_script(js, a1,a2)

12/13新增Webdriver常用方法

通过partial_link_text(部分链接)文本来定位文本链接
find_element_by_partial_link_text('字符串')
通过完整链接文本link_text定位文本链接
find_element_by_link_text('字符串')

1.浏览器操作

get() 访问URL driver.get('url链接')
back 后退上一步 driver.back()
forward 前进下一步 driver.forward()
quit 退出驱动,关闭所有窗口 driver.quit()
close 关闭当前打开的窗口 driver.close()
maximize_window 浏览器最大化 driver.maximize_window()
refresh 刷新浏览器 driver.refresh()

2.元素操作

send_keys() 向文本框类型输入数据 driver.find_element_by_tag('input').send_keys('selenium')
clear() 清空输入的数据 driver.find_element_by_tag('input').clear()
click() 单击事件 driver.find_element_by_tag('button').click()
enter() 触发键盘enter操作 driver.find_element_by_tag('input').enter()
text() 获取元素的文本内容 driver.find_element_by_partial_link_text('Outlook').text() 获取Outlook.com文本
page_source 获取页面HTML内容 driver.page_source() ## 这句话非常有用,可以对抗任何反爬的措施,缘由是获取到了被浏览器渲染过后的网页源代码

3.Cookie操作

get_cookies() 获取当前页的所有Cookies driver.get_cookies()
get_cookie(name) 获取当前页Cookies中的指定name值的cookie driver.get_cookies('time')
add_cookie 添加Cookie driver.add_cookie({'time':'20211213121231'})
delete_cookie(name) 删除一条Cookie driver.delete_cookie('time')
delete_all_cookies 删除所有Cookie driver.delete_all_cookies()

posted @ 2021-09-07 09:24  索匣  阅读(145)  评论(0编辑  收藏  举报