https://blog.csdn.net/weixin_44110998/article/details/103185785 # selenium 学习
window.navigator.webdriver # 规避检测
窗口切换
driver.get("https://seleniumhq.github.io")
driver.window_handle # 获取所有的窗口id
driver.find_element(By.LINK_TEXT, "new window").click() # 点击新连接,新打开一个窗口页面
driver.switch_to.window(driver.window_handle[-1]) # 切换到了新打开的窗口页面
#隐式等待:在查找所有元素时,如果尚未被加载,则等10秒 driver.implicitly_wait(10)
通过它我们可以让代码控制浏览器,从而进行数据爬取,尤其在以下两个地方该模块的作用更加强大:
- 获取整张页面的数据,对有的页面来说前后端分离的API接口太难找了,使用requests模块根本找不到发送加载数据的接口
- 进行自动登录
pip3 install selenium
下载浏览器驱动程序:
- http://chromedriver.storage.googleapis.com/index.html
- 查看驱动和浏览器版本的映射关系:
- http://blog.csdn.net/huilan_same/article/details/51896672
如果是MAC
平台,解压到如下路径,win
平台解压到任意位置皆可:
由于我们使用的是chorme
浏览器,所以只需要实例化出其操纵对象即可:
from selenium import webdriver driver = webdriver.Chrome()
以后的操纵都是操纵该实例对象,如果你使用其他版本浏览器,请自行下载驱动,支持的浏览器如下:
driver = webdriver.Firefox() driver = webdriver.Edge() driver = webdriver.PhantomJS() driver = webdriver.Safari()
1.基本使用
from selenium
import webdriver
import time
# 载入驱动
driver = webdriver.Chrome(r"./chromedriver.exe")
# 打开百度页面
driver.get("https://www.baidu.com")
# 找到搜索框,输入博客园
driver.find_element_by_id("kw").send_keys("博客园") time.sleep(2) driver.find_element_by_id('su').click() time.sleep(2)
# 关闭浏览器
driver.quit()
2.元素定位
driver.find_element_by_id()
driver.find_element_by_name()
driver.find_element_by_class_name()
driver.find_element_by_tag_name()
driver.find_element_by_link_text()
driver.find_element_by_partial_link_text()
driver.find_element_by_xpath()
driver.find_element_by_css_selector()
3 ifarme定位
对于webdriver
来说,它拥有一层作用域。
默认是在顶级作用域中,如果出现了ifarme
标签,则必须切换到ifarme
标签的作用域才能查找其里面的元素。
如下,想查找其中的button
:
<div id="modal">
<iframe id="buttonframe"name="myframe"src="https://seleniumhq.github.io">
<button>Click here</button>
</iframe>
</div>
如果直接获取button
则不会生效,因为目前作用域是外部的html
标签中,不能获取内部iframe
的作用域:
正确的方法是找到ifarme
标签,对其进行切换作用域的操作:
# 存储网页元素
iframe = driver.find_element(By.CSS_SELECTOR, "#modal > iframe")
# 切换到选择的
iframe driver.switch_to.frame(iframe)
# 单击按钮
driver.find_element(By.TAG_NAME, 'button').click()
如果您的frame
或iframe
具有id
或name
属性,则可以使用该属性。如果名称或 id 在页面上不是唯一的, 那么将切换到找到的第一个。
还可以通过索引值进行切换:
iframe
的作用域,使用以下代码: 我们可以与浏览器BOM
或者element
进行交互。
如找到搜索框,使用send_keys()
即可输入内容,clear()
即可清空内容。
再比如找到button
使用click()
即可触发单击事件。
release().perform() 松开鼠标按键 与动作链配合
更多方法请参照官方文档,截图也在其中:
https://www.selenium.dev/documentation/zh-cn/webdriver/browser_manipulation/
5. 动作链
如果碰到滑动验证的操作,则需要使用动作链进行。
上述的交互中,如send_keys()
与click()
都是一次性完成的,如果是非一次性的操作如拖拽,滑动的就可以通过动作链完成。
动作链的官方文档,包括获取当前元素的大小,配合截图使用有奇效,举个例子,截图到当前的验证码页面,然后使用第三方打码工具进行解析验证码:
https://www.selenium.dev/documentation/zh-cn/support_packages/mouse_and_keyboard_actions_in_detail/
from selenium import webdriver
from time import sleep
#导入动作链对应的类
from selenium.webdriver
import ActionChains
bro = webdriver.Chrome(executable_path='./chromedriver')
bro.get('https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
#如果定位的标签是存在于iframe标签之中的则必须通过如下操作在进行标签定位
bro.switch_to.frame('iframeResult')
#切换浏览器标签定位的作用域
div = bro.find_element_by_id('draggable')
#动作链
action = ActionChains(bro)
#点击长按指定的标签
action.click_and_hold(div)
for i in range(5):
#perform()立即执行动作链操作
#move_by_offset(x,y):x水平方向 y竖直方向
action.move_by_offset(17,0).perform() sleep(0.5)
#释放动作链
action.release()
bro.quit()
6. 执行脚本
如果webdriver
实例中没有实现某些方法,则可以通过执行Js
代码来完成,比如下拉滑动条:
from selenium import webdriver
driver = webdriver.Chrome(r"./chromedriver.exe")
driver.get('https://www.jd.com/')
# 执行脚本:滑动整个页面
driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')
7. 动态数据
上面提到过,如果使用requets
模块访问某一url
却没有拿到想要的数据,那么很可能是前后端分离通过RESTful APIs
进行数据交互。
这个时候我们可以使用selenium
模块来对同一url
发起请求,由于是浏览器打开,所有的RESTFUL API
都会进行请求,然后直接通过属性page_source
解析返回的源码数据:
from selenium import webdriver
from lxml import etree
driver=webdriver.Chrome(r"./chromedriver.exe",)
driver.get('https://www.baidu.com/')
source_code = driver.page_source # 获取网页源代码
# 直接获取百度的图片地址
root = etree.HTML(source_code,parser=etree.HTMLParser())
driver.close()
img_src = "http:" + root.xpath(r"//*[@id='s_lg_img_new']")[0].attrib.get("src")
print(img_src)
11. 异常处理
屏蔽掉所有可能出现的异常:
from selenium import webdriver
from selenium.common.exceptions import TimeoutException,NoSuchElementException,NoSuchFrameException
try:
browser=webdriver.Chrome()
browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
browser.switch_to.frame('iframssseResult')
except TimeoutException as e:
print(e)
except NoSuchFrameException as e:
print(e)
finally:
browser.close()
12 无头操作
每次使用selenium
时都会打开一个浏览器,能不能有什么办法让他隐藏界面呢?
指定参数即可,这种没有界面的浏览也可以称其为无头浏览器:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
# 设置配置项chrome_options = Options()
chrome_options.add_argument('--headless')
# 指定配置driver = webdriver.Chrome(
executable_path='./chromedriver.exe',chrome_options=chrome_options)
driver.get("http://www.baidu.com")
driver.close()
13 规避检测
window.navigator.webdriver 检测
可能有的门户网站已经对selenium
做出了检测,如果检测到是该脚本执行可能不允许你访问API
,此时就可以通过伪造信息达到潜行的效果。
将selenium
伪装成人为操作:
#实现规避检测from selenium.webdriver import ChromeOptions#实现规避检测option = ChromeOptions() option.add_experimental_option('excludeSwitches', ['enable-automation']) # 指定配置driver = webdriver.Chrome(executable_path='./chromedriver.exe',options=option)driver.get("http://www.baidu.com") driver.close()
屏蔽掉所有可能出现的异常: