soarli

selenium使用方法
安装seleniumpip install seleniumchromedriver(Chrome)chrome:...
扫描右侧二维码阅读全文
28
2021/07

selenium使用方法

安装

selenium

pip install selenium

chromedriver(Chrome)

chrome://version/

【注】chromedriver的版本一定要与Chrome的版本一致,不然就不起作用。

https://code.google.com/p/chromedriver/downloads/list

http://chromedriver.storage.googleapis.com/index.html

https://npm.taobao.org/mirrors/chromedriver/

phantomjs(无头)

https://phantomjs.org/

geckodriver(Firefox)

https://github.com/mozilla/geckodriver/releases/

IEdriver(IE)

https://www.nuget.org/packages/Selenium.WebDriver.IEDriver/

说明

浏览器驱动需放到python.exe同目录或有环境变量的目录下。

使用

引入

from selenium import webdriver

启动浏览器和打开网页

# 谷歌浏览器
browser = webdriver.Chrome()
browser.get('http://www.baidu.com/')

# PhantomJS浏览器
browser = webdriver.PhantomJS()
browser.get('http://www.baidu.com/')

# 火狐浏览器
browser = webdriver.Firefox()
browser.get('http://www.baidu.com/')
# IE浏览器
browser = webdriver.Ie()
browser.get('http://www.baidu.com/')

选择器

1. 通过ID查找元素

当你知道一个元素的 id 时,你可以使用本方法。在该策略下,页面中第一个该 id 元素 会被匹配并返回。如果找不到任何元素,会抛出 NoSuchElementException 异常。

作为示例,页面元素如下所示:

<html>
 <body>
  <form id="loginForm">
   <input name="username" type="text" />
   <input name="password" type="password" />
   <input name="continue" type="submit" value="Login" />
  </form>
 </body>
<html>

可以这样查找表单(form)元素:

login_form = driver.find_element_by_id('loginForm')

2. 通过Name查找元素

当你知道一个元素的 name 时,你可以使用本方法。在该策略下,页面中第一个该 name 元素 会被匹配并返回。如果找不到任何元素,会抛出 NoSuchElementException 异常。

作为示例,页面元素如下所示:

<html>
 <body>
  <form id="loginForm">
   <input name="username" type="text" />
   <input name="password" type="password" />
   <input name="continue" type="submit" value="Login" />
   <input name="continue" type="button" value="Clear" />
  </form>
</body>
<html>

name属性为 username & password 的元素可以像下面这样查找:

username = driver.find_element_by_name('username')
password = driver.find_element_by_name('password')

这会得到 “Login” 按钮,因为他在 “Clear” 按钮之前:

continue = driver.find_element_by_name('continue')

3. 通过XPath查找元素

XPath是XML文档中查找结点的语法。因为HTML文档也可以被转换成XML(XHTML)文档, Selenium的用户可以利用这种强大的语言在web应用中查找元素。 XPath扩展了(当然也支持)这种通过id或name属性获取元素的简单方式,同时也开辟了各种新的可能性, 例如获取页面上的第三个复选框。

使用XPath的主要原因之一就是当你想获取一个既没有id属性也没有name属性的元素时, 你可以通过XPath使用元素的绝对位置来获取他(这是不推荐的),或相对于有一个id或name属性的元素 (理论上的父元素)的来获取你想要的元素。XPath定位器也可以通过非id和name属性查找元素。

绝对的XPath是所有元素都从根元素的位置(HTML)开始定位,只要应用中有轻微的调整,会就导致你的定位失败。 但是通过就近的包含id或者name属性的元素出发定位你的元素,这样相对关系就很靠谱, 因为这种位置关系很少改变,所以可以使你的测试更加强大。

作为示例,页面元素如下所示:

<html>
 <body>
  <form id="loginForm">
   <input name="username" type="text" />
   <input name="password" type="password" />
   <input name="continue" type="submit" value="Login" />
   <input name="continue" type="button" value="Clear" />
  </form>
</body>
<html>

可以这样查找表单(form)元素:

login_form = driver.find_element_by_xpath("/html/body/form[1]")
login_form = driver.find_element_by_xpath("//form[1]")
login_form = driver.find_element_by_xpath("//form[@id='loginForm']")
  1. 绝对定位 (页面结构轻微调整就会被破坏)
  2. HTML页面中的第一个form元素
  3. 包含 id 属性并且其值为 loginForm 的form元素

username元素可以如下获取:

username = driver.find_element_by_xpath("//form[input/@name='username']")
username = driver.find_element_by_xpath("//form[@id='loginForm']/input[1]")
username = driver.find_element_by_xpath("//input[@name='username']")
  1. 第一个form元素中包含name属性并且其值为 username 的input元素
  2. id为 loginForm 的form元素的第一个input子元素
  3. 第一个name属性为 username 的input元素

“Clear” 按钮可以如下获取:

clear_button = driver.find_element_by_xpath("//input[@name='continue'][@type='button']")
clear_button = driver.find_element_by_xpath("//form[@id='loginForm']/input[4]")
  1. Input with attribute named name and the value continue and attribute named type and the value button
  2. Fourth input child element of the form element with attribute named id and value loginForm

4. 通过链接文本获取超链接

当你知道在一个锚标签中使用的链接文本时使用这个。 在该策略下,页面中第一个匹配链接内容锚标签 会被匹配并返回。如果找不到任何元素,会抛出 NoSuchElementException 异常。

作为示例,页面元素如下所示:

<html>
 <body>
  <p>Are you sure you want to do this?</p>
  <a href="continue.html">Continue</a>
  <a href="cancel.html">Cancel</a>
</body>
<html>

continue.html 超链接可以被这样查找到:

continue_link = driver.find_element_by_link_text('Continue')
continue_link = driver.find_element_by_partial_link_text('Conti')

5. 通过标签名查找元素

当你向通过标签名查找元素时使用这个。 在该策略下,页面中第一个匹配该标签名的元素 会被匹配并返回。如果找不到任何元素,会抛出 NoSuchElementException 异常。

作为示例,页面元素如下所示:

<html>
 <body>
  <h1>Welcome</h1>
  <p>Site content goes here.</p>
</body>
<html>

h1 元素可以如下查找:

heading1 = driver.find_element_by_tag_name('h1')

6. 通过Class name 定位元素

当你向通过class name查找元素时使用这个。 在该策略下,页面中第一个匹配该class属性的元素 会被匹配并返回。如果找不到任何元素,会抛出 NoSuchElementException 异常。

作为示例,页面元素如下所示:

<html>
 <body>
  <p class="content">Site content goes here.</p>
</body>
<html>

p 元素可以如下查找:

content = driver.find_element_by_class_name('content')

7. 通过CSS选择器查找元素

当你向通过CSS选择器查找元素时使用这个。 在该策略下,页面中第一个匹配该CSS 选择器的元素 会被匹配并返回。如果找不到任何元素,会抛出 NoSuchElementException 异常。

作为示例,页面元素如下所示:

<html>
 <body>
  <p class="content">Site content goes here.</p>
</body>
<html>

p 元素可以如下查找:

content = driver.find_element_by_css_selector('p.content')

基本的页面操作

定位到元素后,可对该元素进行一些操作(比如输入内容、点击按钮等)

输入内容

 ele_input_id.send_keys('Hello World')

点击按钮

ele_btn.click()

获取内容

获取标签文字:

print(xxx.text)

获取标签class:

print(a.get_attribute('class'))

填充表单

以下拉选项卡的处理为例:

element = driver.find_element_by_xpath("//select[@name='name']")
all_options = element.find_elements_by_tag_name("option")
for option in all_options:
    print("Value is: %s" % option.get_attribute("value"))
    option.click()

首先获取了第一个 select 元素,也就是下拉选项卡。然后轮流设置了 select 选项卡中的每一个 option 选项。但是这并不是一个非常有效的方法。 其实 WebDriver 中提供了一个叫 Select 的方法,可以帮助我们完成这些事情。

from selenium.webdriver.support.ui import Select
select = Select(driver.find_element_by_name('name'))
select.select_by_index(index)
select.select_by_visible_text("text")
select.select_by_value(value)

它可以根据索引来选择,可以根据值来选择,可以根据文字来选择。是十分方便的。 全部取消选择怎么办呢?很简单

select = Select(driver.find_element_by_id('id'))
select.deselect_all()

这样便可以取消所有的选择。 另外我们还可以通过下面的方法获取所有的已选选项。

select = Select(driver.find_element_by_xpath("xpath"))
all_selected_options = select.all_selected_options

获取所有可选选项是

options = select.options

如果你把表单都填好了,最后肯定要提交表单对吧。怎吗提交呢?很简单

driver.find_element_by_id("submit").click()

这样就相当于模拟点击了 submit 按钮,做到表单提交。 当然你也可以单独提交某个元素

element.submit()

页面切换

针对多窗口场景,切换窗口的方法如下:

driver.switch_to_window("windowName")

另外可以使用 window_handles 方法来获取每个窗口的操作对象。例如

for handle in driver.window_handles:
    driver.switch_to_window(handle)

另外切换 frame 的方法如下

driver.switch_to_frame("frameName.0.child")

这样焦点会切换到一个 name 为 child 的 frame 上。

弹窗处理

假设触发某个事件之后,页面出现了弹窗提示

alert = driver.switch_to_alert()

可通过上述方法可以获取弹窗对象。

历史记录

操作页面的前进和后退:

driver.forward()
driver.back()

获取 cookies

在爬虫领域中,常常使用 selenium 获取 cookies 应付反爬虫。

比如,爬取微博的内容,需要登陆状态,而保存的 cookies 会在一定时间后失效,这时候 selenium 就派上了用场,使用预先设置的账号密码登陆,然后获取 cookies 发送给脚本使用。

1. 使用内置函数

获取 cookies 使用 get_cookies 函数,以百度为例:

cookie_r = driver.get_cookies()

打印出 cookie_r 是这样的:

[{'domain': '.baidu.com', 'httpOnly': False, 'name': 'H_PS_PSSID', 'path': '/', 'secure': False, 'value': '22584_1465_21087_18560_22581'}, {'domain': '.baidu.com', 'expiry': 3639883283.649732, 'httpOnly': False, 'name': 'BAIDUID', 'path': '/', 'secure': False, 'value': '69F8E8C5CF050F0C8CA3C358CB08BAC6:FG=1'}, {'domain': '.baidu.com', 'expiry': 3639883283.649952, 'httpOnly': False, 'name': 'PSTM', 'path': '/', 'secure': False, 'value': '1492399635'}, {'domain': '.baidu.com', 'expiry': 3639883283.649925, 'httpOnly': False, 'name': 'BIDUPSID', 'path': '/', 'secure': False, 'value': '69F8E8C5CF050F0C8CA3C358CB08BAC6'}, {'domain': 'www.baidu.com', 'expiry': 1493263637, 'httpOnly': False, 'name': 'BD_UPN', 'path': '/', 'secure': False, 'value': '12314753'}, {'domain': 'www.baidu.com', 'expiry': 1492399637.649969, 'httpOnly': False, 'name': 'BD_LAST_QID', 'path': '/', 'secure': False, 'value': '18362646771513028098'}, {'domain': 'www.baidu.com', 'httpOnly': False, 'name': 'BD_HOME', 'path': '/', 'secure': False, 'value': '0'}, {'domain': '.www.baidu.com', 'expiry': 1492399642.240359, 'httpOnly': False, 'name': '__bsi', 'path': '/', 'secure': False, 'value': '16804089554912194086_00_0_I_R_3_0303_C02F_N_I_I_0'}, {'domain': 'www.baidu.com', 'expiry': 1492399647, 'httpOnly': False, 'name': 'WWW_ST', 'path': '/', 'secure': False, 'value': '1492399637585'}]

此形式的 cookies 是不能直接传递给脚本使用的,我们需要进一步的处理,提取出每个字典 namevalue 值,将其组合在一起。

cookies_list = []for i in cookie_r:
    cookie = i['name'] + '=' + i['value']
    cookies_list.append(cookie)
cookies_str = ';'.join(cookies_list)

经过处理的 cookies_str 就可以直接发送给 脚本使用了,打印出 cookies_str 如下:

H_PS_PSSID=22583_1433_21106_17001_20929;BAIDUID=456846B8C2CECBC077CA6A700DA24A89:FG=1;PSTM=1492400387;BIDUPSID=456846B8C2CECBC077CA6A700DA24A89;BD_HOME=0;BD_UPN=12314753;__bsi=16211205307050373314_00_0_I_R_2_0303_C02F_N_I_I_0;WWW_ST=1492400389401

2. 执行 js 函数

获取 cookies不仅仅可以通过 get_cookies 函数,还可以直接使用 javascript 代码,示例:

# 字符串形式的 js 代码
js_code = 'return document.cookie'
# 执行 js 代码
cookies = driver.execute_script(js_code)
print(cookies)

此时获取的 cookies 可以直接发给脚本使用,结果如下:

BAIDUID=7ABCBA83953DC58B59943B0967D10098:FG=1; BIDUPSID=7ABCBA83953DC58B59943B0967D10098; PSTM=1492400818; BD_HOME=0; H_PS_PSSID=22584_1457_21106_17001_21673_20927; BD_UPN=12314753; __bsi=17435099398291019533_00_0_I_R_2_0303_C02F_N_I_I_0; WWW_ST=1492400820362

页面等待

针对采用了 Ajax 的网页,程序便不能确定何时某个元素完全加载出来,从而使得元素定位困难而且会提高产生 ElementNotVisibleException 的概率。 对此 Selenium 提供了两种等待方式:隐式等待和显式等待。 隐式等待是等待特定的时间,显式等待是指定某一条件直到这个条件成立时继续执行。

1. 显式等待

显式等待指定某个条件,然后设置最长等待时间。如果在这个时间还没有找到元素,那么便会抛出异常了。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Chrome()
driver.get("http://somedomain/url_that_delays_loading")
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()

程序默认会 500ms 调用一次来查看元素是否已经生成,如果本来元素就是存在的,那么会立即返回。 下面是一些内置的等待条件,你可以直接调用这些条件,而不用自己写某些等待条件了。

  • title_is
  • title_contains
  • presence_of_element_located
  • visibility_of_element_located
  • visibility_of
  • presence_of_all_elements_located
  • text_to_be_present_in_element
  • text_to_be_present_in_element_value
  • frame_to_be_available_and_switch_to_it
  • invisibility_of_element_located
  • element_to_be_clickable - it is Displayed and Enabled.
  • staleness_of
  • element_to_be_selected
  • element_located_to_be_selected
  • element_selection_state_to_be
  • element_located_selection_state_to_be
  • alert_is_present
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID,'someid')))

2. 隐式等待

隐式等待比较简单,就是简单地设置一个等待时间,单位为秒。

from selenium import webdriver

driver = webdriver.Chrome()
driver.implicitly_wait(10) # seconds
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")

当然如果不设置,默认等待时间为 0。

实战一

需求:

实现cookie的自动获取,及cookie过期自动更新。

社交网站中的很多信息需要登录才能获取到,以微博为例,不登录账号,只能看到大V的前十条微博。保持登录状态,必须要用到Cookie。以登录www.weibo.cn 为例:

在chrome中输入:http://login.weibo.cn/login/

分析控制台的Headers的请求返回,会看到weibo.cn有几组返回的cookie。

实现步骤:

1,采用selenium自动登录获取cookie,保存到文件;

2,读取cookie,比较cookie的有效期,若过期则再次执行步骤1;

3,在请求其他网页时,填入cookie,实现登录状态的保持。

过程:

1. 在线获取cookie

采用selenium + PhantomJS 模拟浏览器登录,获取cookie;

cookies一般会有多个,逐个将cookie存入以.weibo后缀的文件。

def get_cookie_from_network():

 from selenium import webdriver

 url_login = 'http://login.weibo.cn/login/'

 driver = webdriver.PhantomJS()

 driver.get(url_login)

 driver.find_element_by_xpath('//input[@type="text"]').send_keys('your_weibo_accout') # 改成你的微博账号

 driver.find_element_by_xpath('//input[@type="password"]').send_keys('your_weibo_password') # 改成你的微博密码

 driver.find_element_by_xpath('//input[@type="submit"]').click() # 点击登录

 # 获得 cookie信息

 cookie_list = driver.get_cookies()

 print cookie_list

 cookie_dict = {}

 for cookie in cookie_list:

  #写入文件

  f = open(cookie['name']+'.weibo','w')

  pickle.dump(cookie, f)

  f.close()

  if cookie.has_key('name') and cookie.has_key('value'):

   cookie_dict[cookie['name']] = cookie['value']

 return cookie_dict

2. 从文件中获取cookie

从当前目录中遍历以.weibo结尾的文件,即cookie文件。采用pickle解包成dict,比较expiry值与当前时间,若过期则返回为空;

def get_cookie_from_cache():

 cookie_dict = {}

 for parent, dirnames, filenames in os.walk('./'):

  for filename in filenames:

   if filename.endswith('.weibo'):

    print filename

    with open(self.dir_temp + filename, 'r') as f:

     d = pickle.load(f)

     if d.has_key('name') and d.has_key('value') and d.has_key('expiry'):

      expiry_date = int(d['expiry'])

      if expiry_date > (int)(time.time()):

       cookie_dict[d['name']] = d['value']

      else:

       return {}

 return cookie_dict

3. 若缓存cookie过期,则再次从网络获取cookie

def get_cookie():

 cookie_dict = get_cookie_from_cache()

 if not cookie_dict:

  cookie_dict = get_cookie_from_network()

 return cookie_dict

4. 带cookie请求微博其他主页

def get_weibo_list(self, user_id):

 import requests

 from bs4 import BeautifulSoup as bs

 cookdic = get_cookie()

 url = 'http://weibo.cn/stocknews88'

 headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36'}

 timeout = 5

 r = requests.get(url, headers=headers, cookies=cookdic,timeout=timeout)

 soup = bs(r.text, 'lxml')

 ...

 # 用BeautifulSoup 解析网页

 ...

实战二

需求:

尝试多种操作

过程:

import requests
import sys
import io
from selenium import webdriver

sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8') #改变标准输出的默认编码

#建立Phantomjs浏览器对象,括号里是phantomjs.exe在你的电脑上的路径
browser = webdriver.PhantomJS('d:/tool/07-net/phantomjs-windows/phantomjs-2.1.1-windows/bin/phantomjs.exe')

#登录页面
url = r'http://ssfw.xmu.edu.cn/cmstar/index.portal'

# 访问登录页面
browser.get(url)

# 等待一定时间,让js脚本加载完毕
browser.implicitly_wait(3)

#输入用户名
username = browser.find_element_by_name('user')
username.send_keys('学号')

#输入密码
password = browser.find_element_by_name('pwd')
password.send_keys('密码')

#选择“学生”单选按钮
student = browser.find_element_by_xpath('//input[@value="student"]')
student.click()

#点击“登录”按钮
login_button = browser.find_element_by_name('btn')
login_button.submit()

#网页截图
browser.save_screenshot('picture1.png')
#打印网页源代码
print(browser.page_source.encode('utf-8').decode())

browser.quit()

实战三

需求:

示例代码来自佬潘,针对部分设置反爬网站加以伪装得以实现爬虫,原理详解见参考资料。

过程:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options

bilibili_url = 'https://www.bilibili.com/video/BV1W64y1t7gq'

#伪装
chrome_options = Options()
chrome_options.add_argument('headless')#不显示浏览器
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36')
chrome_options.add_argument("--disable-blink-features=AutomationControlled")


driver = webdriver.Chrome(options=chrome_options)

driver.get('https://bilibili.iiilab.com/')
URL_entry = driver.find_element_by_class_name('form-control.link-input')
URL_entry.send_keys(bilibili_url)

#有时会出现解析失败的情况,多点击几次即可
while driver.find_elements_by_class_name('alert.alert-danger'):
    start_button = driver.find_element_by_class_name('btn.btn-default')
    try:
        start_button.click()
    except:
        break
    

#通过while循环,一旦解析成功就直接返回MP4的地址
mp4_url = '0'
while not mp4_url or len(mp4_url) == 1:
    try:
        dowload_button = driver.find_element_by_class_name('btn.btn-success')
    except:
        pass
    else:
        mp4_url = dowload_button.get_attribute('href')

driver.close()
print(mp4_url)

参考资料:

www.selenium.dev/documentation/zh-cn/

selenium-python-zh.readthedocs.io/en/latest/

www.cnblogs.com/lfri/p/10542797.html

www.imooc.com/article/38665

blog.csdn.net/azsx02/article/details/68947429

cuiqingcai.com/2599.html

www.php.cn/js-tutorial-399684.html

www.cnblogs.com/mghhzAnne/p/12575400.html

www.cnblogs.com/ittop/p/9639449.html

blog.csdn.net/lly1122334/article/details/107352181

最后修改:2021 年 07 月 29 日 12 : 45 PM

发表评论