为了避免浏览器被监测出正在被自动化程序控制,我们可以利用 Chrome 的远程调试结合 selenium 来遥控Chrome 进行绕过监测
首先使用 cmd 为 chrome.exe 的启动添加额外的启动参数
# 如果chrome.exe未在环境变量中配置,需进入目录下运行
cd C:\Program Files (x86)\Google\Chrome\Application
chrome.exe --remote-debugging-port=9222 --user-data-dir="C:\selenum\AutomationProfile" --profile-directory="Profile 1"
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--no-sandbox') # 解决DevToolsActivePort文件不存在的报错
chrome_options.add_argument('--disable-gpu') # 谷歌文档提到需要加上这个属性来规避bug
chrome_options.add_argument('blink-settings=imagesEnabled=false') # 不加载图片, 提升速度
chrome_options.add_argument('--headless') # 浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败
# 添加User-Agent
chrome_options.add_argument('user-agent="MQQBrowser/26 Mozilla/5.0 (Linux; U; Android 2.3.7; zh-cn; MB200 Build/GRJ22; CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"')
chrome_options.add_argument('--proxy-server=http://') # 使用代理IP登录浏览器
chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222") # 使用远程调试端口操作浏览器,避免被监测为正在使用自动化程序控制
# 禁用浏览器弹窗
prefs = { 'profile.default_content_setting_values' : { 'notifications' : 2 }}
chrome_options.add_experimental_option('prefs',prefs)
#禁止插件
chrome_options.add_argument('--disable-plugins')
# 禁用弹出拦截
chrome_options.add_argument('--disable-popup-blocking')
from selenium import webdriver
# 创建WebDriver对象(通常默认为wd),指明Chrome浏览器驱动,并添加上述配置
wd = webdriver.Chrome(
executable_path='C:\Program Files (x86)\Google\Chrome\Application\chromedriver.exe',
options=chrome_options,
)
# 窗口最大化
wd.maximize_window()
# 设置窗口指定大小
wd.set_window_size(1920, 1080)
wd.get('https://www.baidu.com')
from selenium.webdriver.support.ui import WebDriverWait
wait = WebDriverWait(driver, 15)
wd.close() # 关闭当前窗口
wd.quit() # 关闭浏览器
如果要查找 web 元素的特征。可以使用浏览器的开发者工具栏帮我们查看、选择 web 元素。(选择元素,右键检查,即可查看页面对应的HTML元素)
wd = webdriver.Chrome()
我们通过上述指令,为 wd 赋值了 WebDriver 类型的对象,借此可以通过这个对象来操控浏览器,比如打开网址、选择界面元素等。
下面的代码
wd.find_element_by_id('kw')
使用了 WebDriver 对象 的方法 find_element_by_id,
在 WebDriver 对象中,定位元素的方法有很多种。其中常使用的为:
# 根据 元素的id 属性选择元素
find_element_by_id
# 根据 class属性、tag名 选择元素
find_element_by_tag_name
find_element_by_class_name
# 根据 元素的css 属性选择元素
find_element_by_css_selector
# 根据xpath来选择元素
find_element_by_xpath
根据上面 html 中的标签的属性,我们可以找到一个属性值为 kw 的 id 属性。
在 html 中,id 可以作为元素的编号,如果元素有 id 属性,那么这个 id 有且唯一,
所以,如果元素有 id ,根据 id 来寻找元素是最简单高效的方法。
示例:
wd.find_element_by_id('kw')
浏览器,找到 id 为 kw 的元素后,将结果通过浏览器驱动返回给自动化程序, 所以 find_element_by_id 方法会 返回一个 WebElement 类型的对象。通过这个WebElement 对象,就可以操控对应的界面元素。
# 找到元素后点击
wd.find_element_by_id('kw').click()
# 找到元素后传递字符串
wd.find_element_by_id('kw').send_keys('')
除了根据元素的id ,我们还可以根据元素的 class 属性选择元素。
元素存在类型, class 属性就用来标志着元素的类型 。在具体的 html 页面中,由于元素的类型可能是同一种,所以我们在实际定位中,可以使用 find_elements 来定位同种类型的全部元素。
例如:
wd.find_elements_by_class_name('s_ipt')
类似的,我们可以使用方法 find_elements_by_tag_name,选择所有的 tag 名为 input 的元素
wd.find_elements_by_tag_name('input')
通过 WebElement 对象的 text属性
可以获取该元素 在网页中的文本内容。
element = wd.find_elements_by_class_name('s_ipt')
print(element.text)
如果以上方法都定位不到控件,说明很可能在iframe里,下面为切换到iframe的方法
driver.switch_to.frame() #转入网页内iframe(内嵌的网页元素)
driver.switch_to.parent_frame() #切回上一层frame
driver.switch_to_default_content() #返回到主页面
使用 find_elements 选择的是符合条件的所有元素, 如果没有符合条件的元素, 返回空列表
使用 find_element 选择的是符合条件的第一个元素, 如果没有符合条件的元素, 抛出 NoSuchElementException 异常
driver.execute_script('window.open()') # 开启一个选项卡
windows=driver.window_handles # 获得当前浏览器所有窗口
driver.switch_to.window(windows[0]) # 切换到最左侧窗口
driver.switch_to.window(windows[-1]) # 切换到最新打开窗口(注:也就是最右侧窗口)
submit()方法用于提交表单,这里特别用于没提交按钮的情况
例如搜索框输入关键字之后的“回车”操作,那么就可以通过submit()来提交搜索框的内容。
driver.find_element_by_id('query').submit()
driver.current_url # 获取当前网址
driver.page_source # 获取源代码
driver.title # 获取当前页面标题内容
driver.delete_all_cookies() # 删除所有cookie
driver.add_cookie({'name':5}) # 添加cookie
driver.get_cookies()
cookie_list = []
for dict in cookies:
cookie = dict['name'] + '=' + dict['value']
cookie_list.append(cookie)
cookie = ';'.join(cookie_list)
当发现元素没有找到的时候, 并不立即返回找不到元素的错误。而是周期性(每隔半秒钟)重新寻找该元素,直到该元素被找到,或者超出指定最大等待时长,这时才 抛出异常(如果是 find_elements 之类的方法, 则是返回空列表)。
Selenium 的 Webdriver 对象 有个方法叫 implicitly_wait
该方法接受一个参数,用来指定 最大等待时长。
# 设置缺省等待时间
driver.implicitly_wait(10)
顾名思义,显式等待就是运行代码后设置好固定的等待时间,然后再继续运行,常用的为 time 模块的 sleep 方法
该方法接受一个参数,用来指定 最大等待时长。
import time
time.sleep(1)
river 对象 有个方法叫 implicitly_wait
该方法接受一个参数,用来指定 最大等待时长。
# 设置缺省等待时间
driver.implicitly_wait(10)
顾名思义,显式等待就是运行代码后设置好固定的等待时间,然后再继续运行,常用的为 time 模块的 sleep 方法
该方法接受一个参数,用来指定 最大等待时长。
import time
time.sleep(1)