参考:Selenium tutorial, Selenium basic
selenium本来是用来做网站测试的,但逐渐成为一个强大的爬虫工具,主要用于抓取使用了Ajax和动态HTML技术的网页内容。
$ pip install selenium
针对不同的浏览器,还需要下载对应的插件,如Chrome v59,需要下载chromedriver v2.32到/usr/bin
目录中。
也可以使用PhantomJS(不显示界面的浏览器):
$ sudo apt-get install phantomjs
安装完成后在/usr/bin/phantomjs
中添加以下代码:
export QT_QPA_PLATFORM=offscreen
export QT_QPA_FONTDIR=/usr/share/fonts
特别提示:如果在调试中发现如下的异常信息,就表明你下载的PhantomJS很可能是不完整的(源里的phantomjs文件有问题)。
selenium.common.exceptions.WebDriverException: Message: Error - Unable to load Atom 'execute_script' from file ':/ghostdriver/./third_party/webdriver-atoms/execute_script.js'
这种情况下,建议去官网下载编译好的二进制文件,复制到/usr/bin
中,替换同名文件即可。
[TOP]
from selenium import webdriver
browser = webdriver.PhantomJS() # 使用PhantomJS,不弹出浏览器界面
browser.get('http://www.taobao.com/')
page_html = browser.page_source # 获取网页源代码
print(page_html)
browser.close()
如在淘宝上搜索“全球通史”:
from selenium import webdriver
browser = webdriver.Chrome()
browser.get('http://www.taobao.com/')
element=browser.find_element_by_id("q")
element.send_keys(ur"全球通史")
element.submit()
browser.back() # 相当于浏览器的"后退"按钮,"前进"为browser.forward()
element=browser.find_element_by_id("q")
element.send_keys(ur"全球通史 斯塔夫里阿诺斯")
element.submit()
browser.close()
[TOP]
上面的例子用到了find_element_by_id
,selenium还提供了很多类似的选择器:
find_element_by_id
find_element_by_name
find_element_by_xpath
find_element_by_link_text
find_element_by_partial_link_text
find_element_by_tag_name
find_element_by_class_name
find_element_by_css_selector
将element
换成elements
就可以一次提取具有同样特征的多个元素,返回的是一个python列表。
[TOP]
指定被拖动的元素和目标元素后,可以使用ActionChains
类来实现拖动,如
element = driver.find_element_by_name("source")
target = driver.find_element_by_name("target")
from selenium.webdriver import ActionChains
action_chains = ActionChains(driver)
action_chains.drag_and_drop(element, target).perform()
[TOP]
上面的例子已经用到了表单的填充
element=browser.find_element_by_id("q")
element.send_keys(ur"全球通史")
清除表单中的文本
element.clear()
实际上send_keys
还可以模拟按键,如
element.send_keys("text", Keys.ARROW_DOWN)
对于下拉选项,可以使用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.deselect_all() # 取消所有选项
all_selected_options = select.all_selected_options # 获取已选的选项
select.options # 获取所有可选选项
browser.find_element_by_id("submit").click() # 点击submit按钮
[TOP]
alert = browser.switch_to_alert()
获取弹窗对象。
[TOP]
browser.switch_to_frame("frameName.0.child")
将焦点切换到name
为child
的frame上。
[TOP]
很多网页用Ajax异步加载数据,比如当页面被打开几秒钟以后,会被替换为Ajax生成的内容,采用传统的爬虫只能获取Ajax加载之前的页面。
如果知道异步加载的延时,可以采用显示等待的方式抓取Ajax生成的内容,如:
from selenium import webdriver
import time
browser = webdriver.Chrome()
browser.get('http://www.toutiao.com/')
for i in range(10):
browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
webdriver.ActionChains(browser).key_down(Keys.DOWN).perform() # 将页面拖到最底端
time.sleep(5) # 显式等待5秒
print browser.find_elements_by_class_name("link")[-1].text
browser.close()
很多时候异步加载的时间是不确定的,因此这种方法有时候会出错。更加有效的方法是通过检查页面中的某个元素是否存在,以此判断是否可以开始采集数据,这种方法就是selenium的隐式等待(implicit wait)。
触发隐式等待条件(expected_conditions
)有很多,如弹出一个提示框,一个元素被选中,页面标题改变,某些文字显示在页面上,一个元素在DOM中变为可见或不可见等等。
下面的代码用id
是loadedButton
的按钮检查页面是否加载完成:
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
browser = webdriver.PhantomJS()
browser.get("***some_url***")
try:
element = WebDriverWait(browser, 10).until(
EC.presence_of_element_located((By.ID, "loadedButton"))
)
finally:
print browser.find_element_by_id("content").text
driver.close()
By
用以指定expected_conditions
所在的元素,称为定位器,定位器与选择器是不一样的,定位器可以用于创建选择器,如
browser.find_element(By.ID, "q")
By
对象策略有ID
, CLASS_NAME
, CSS_SELECTOR
, LINK_TEXT
, PARTIAL_LINK_TEXT
, NAME
, TAG_NAME
, XPATH
。
selenium内置的隐式等待的期望条件有
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
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
[TOP]
# cookie在某个域名下才能生效,因此需要首先建立连接
browser.get('http://www.taobao.com/')
# 获取该URL的所有cookies
coo = browser.get_cookies()
print(coo)
请求网页时发送cookie信息,可用于身份验证,实现免登录访问:
# cookie在某个域名下才能生效,因此需要首先建立连接
browser.get('http://www.taobao.com/')
# 删除第一次建立连接时的cookies
browser.delete_all_cookies()
# 读取手动登录时预存到本地的cookies
with open('cookies.json', 'r', encoding='utf-8') as f:
listCookies = json.loads(f.read())
for cookie in listCookies:
browser.add_cookie({
'domain': '.taobao.com', # 注意xxx.com前面的.
'name': cookie['name'],
'value': cookie['value'],
'path': '/',
'expires': None
})
# 再次访问页面,便可实现免登录
browser.get('http://www.taobao.com/')
[TOP]