Selenium是一个自动化测试工具,可以驱动浏览器器执行特定的动作,如点击,下拉等。同时还可以获取浏览器当前呈现页面的源代码,可见即可爬。
浏览器驱动
根据自己的浏览器进行选择:
Chrome: https://sites.google.com/a/chromium.org/chromedriver/downloads
Firefox: https://github.com/mozilla/geckodriver/releases
使用selenium写爬虫
优势
* 不需要做复杂的抓包、构造请求、解析数据等,开发难度相对要低一些。
* 其访问参数跟使用浏览器的正常用户一模一样,访问行为也相对更像正常用户,不容易被反爬虫策略命中。
* 生成的浏览器环境可以自动运行 JS 文件,所以不用担心如何逆向混淆过的JS文件生成用作人机校验的参数,如马蜂窝酒店评论的人机校验参数_sn,网易云音乐评论的人机校验参数params、encSecKey。可以自行抓包查看。
* 如果需要抓取同一个前端页面上面来自不同后端接口的信息,如OTA酒店详情页的酒店基础信息、价格、评论等,使用Selenium可以在一次请求中同时完成对三个接口的调用,相对方便
劣势
相比于抓包→构造请求→解析返回值的爬虫,由于Selenium需要生成一个浏览器环境,所有操作(与元素交互、获取元素内容等)均需要等待页面加载完毕后才可以继续进行,所以速度相比构造请求的慢很多。
对于为了反爬做了特殊处理的展示内容,如字体加密(参考猫眼)、图片替换数字(参考自如)等,可能取不到想要的数据。
准备
以Firefox为例来研究selenium的用法, 在开始之前,请确保已经正确安装好Firefox浏览器并配置好了GeckoDriver;另外,还需要正确安装Python的Selenium库
初步体验
-
from selenium
import webdriver
-
browser = webdriver.Firefox()
-
browser.get(
'http://www.baidu.com/')
运行这段代码,会自动打开浏览器,然后访问百度。
如果程序执行错误,浏览器没有打开,那么应该是没有装 Firefox浏览器或者 Firefox驱动没有配置在环境变量里。下载驱动,然后将驱动文件路径配置在环境变量即可
模拟提交
首先等页面加载完成,然后输入到搜索框文本,点击提交。
-
from selenium
import webdriver
-
from selenium.webdriver.common.keys
import Keys
-
driver = webdriver.Firefox()
-
driver.get(
"http://www.python.org")
-
assert
"Python"
in driver.title
-
elem = driver.find_element_by_name(
"q")
-
elem.send_keys(
"pycon")
-
elem.send_keys(Keys.RETURN)
-
print(driver.page_source)
页面操作
页面交互
要做到页面交互,比如点击,输入等, 前提就是要找到页面中的元素。WebDriver提供了各种方法来寻找元素。
Eg:
<input type="text" name="passwd" id="passwd-id" />
-
element = driver.find_element_by_id(
"passwd-id")
-
element = driver.find_element_by_name(
"passwd")
-
element = driver.find_elements_by_tag_name(
"input")
-
element = driver.find_element_by_xpath(
"//input[@id='passwd-id']")
在用 xpath 的时候还需要注意的是,如果有多个元素匹配了 xpath,它只会返回第一个匹配的元素。如果没有找到,那么会抛出 NoSuchElementException 的异常。
获取了元素之后,下一步当然就是向文本输入内容了,可以利用下面的方法
element.send_keys("some text")
同样你还可以利用 Keys 这个类来模拟点击某个按键。
element.send_keys("and some", Keys.ARROW_DOWN)
你可以对任何获取到到元素使用 send_keys 方法,就像你在 GMail 里面点击发送键一样。不过这样会导致的结果就是输入的文本不会自动清除。所以输入的文本都会在原来的基础上继续输入。你可以用下面的方法来清除输入文本的内容
element.clear()
这样输入的文本会被清除
填充表单
下拉选项卡处理方式
-
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 按钮,做到表单提交
页面切换
一个浏览器肯定会有很多窗口,所以我们肯定要有方法来实现窗口的切换
driver.switch_to_window("windowName")
另外还可以使用 window_handles 方法来获取每个窗口的操作对象
-
for handle
in driver.window_handles:
-
driver.switch_to_window(handle)
操作页面的前进和后退功能
-
driver.forward()
-
driver.back()
元素选取
关于元素的选取,有如下api
-
* 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
-
* find_elements_by_name
-
* find_elements_by_xpath
-
* find_elements_by_link_text
-
* find_elements_by_partial_link_text
-
* find_elements_by_tag_name
-
* find_elements_by_class_name
-
* find_elements_by_css_selector
另外还可以利用 By 类来确定哪种选择方式
-
from selenium.webdriver.common.by
import By
-
driver.find_element(By.XPATH,
'//button[text()="Some text"]')
-
driver.find_elements(By.XPATH,
'//button')
By 类的一些属性如下
-
ID =
"id"
-
XPATH =
"xpath"
-
LINK_TEXT =
"link text"
-
PARTIAL_LINK_TEXT =
"partial link text"
-
NAME =
"name"
-
TAG_NAME =
"tag name"
-
CLASS_NAME =
"class name"
-
CSS_SELECTOR =
"css selector"
页面等待
Selenium 提供了两种等待方式,一种是隐式等待,一种是显式等待。 隐式等待是等待特定的时间,显式等待是指定某一条件直到这个条件成立时继续执行。
-
显示等待
-
from selenium.webdriver.support
import expected_conditions
as EC
-
wait = WebDriverWait(driver,
10)
-
element = wait.until(EC.element_to_be_clickable((By.ID,
'someid')))
-
-
其他的等待条件
-
* 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
-
-
隐式等待
-
隐式等待比较简单,就是简单地设置一个等待时间,单位为秒。
-
driver.implicitly_wait(
10)
简单的爬虫示例
爬取Amazon某一类商品图片URL及产品的基本讯息
-
from selenium
import webdriver
-
-
option = webdriver.FirefoxOptions()
-
# option.add_argument('--headless') #无头模式
-
option.set_preference(
'permissions.default.image',
2)
#不加载图片
-
# option.set_preference('permissions.default.stylesheet', 2)
-
driver = webdriver.Firefox(options=option)
-
driver.get(
'https://www.amazon.com/s?bbn=13861679011&rh=n%3A3760911%2Cn%3A%2111055981%2Cn%3A17242866011%2Cn%3A11063461%2Cn%3A13861679011%2Cp_36%3A10000-200000&qid=1581758015&rnid=386662011&ref=lp_13861679011_nr_p_36_4')
-
-
def get_product_conf(max_num):
-
global id,CSV_headers,random_str_list
-
for i
in range(max_num):
-
id = id +
1
-
# print(i.get_attribute('href'))
-
product_img = driver.find_element_by_xpath(
'//span/div[@class="s-result-list s-search-results sg-row"]/div[%d]//img[@class="s-image"]' %(i+
1))
-
print(product_img.get_attribute(
'src'))
-
try:
-
driver.find_element_by_xpath(
'//span/div[@class="s-result-list s-search-results sg-row"]/div[%d]' %(i+
1)).click()
-
product_title = driver.find_element_by_id(
'productTitle').text
-
except:
-
driver.back()
-
continue
-
# 商品描述
-
product_description = driver.find_element_by_id(
'productDescription').text.replace(
'\n',
'<br/>')
-
# 商品介绍
-
product_feature = driver.find_element_by_id(
'feature-bullets').text
-
# 所属栏位
-
product_categories = driver.find_element_by_id(
'wayfinding-breadcrumbs_feature_div').text.replace(
'\n',
'').replace(
'›',
'>')
-
-
-
print(
'product_title:',product_title)
-
print(
'product_description:',product_description)
-
print(
'product_feature:',product_feature)
-
print(
'product_categories:',product_categories)
-
driver.back()
-
-
if __name__ ==
'__main__':
-
id =
1
-
while
True:
-
print(
'start')
-
max_num = len(
-
driver.find_elements_by_xpath(
'//span/div[@class="s-result-list s-search-results sg-row"]/div')) -
1
-
print(max_num)
-
get_product_conf(max_num)
-
# data = get_product_conf(max_num)
-
# write_csv_rows('demo_test.csv', CSV_headers, data)
-
# print('1111111111111111111111')
-
if driver.find_elements_by_xpath(
'//li[@class="a-last"]/a[@href]'):
-
print(driver.find_elements_by_xpath(
'//li[@class="a-last"]/a[@href]'))
-
driver.find_element_by_class_name(
'a-last').click()
-
# print('222222222222222222222')
-
else:
-
break
-
driver.close()
其他常用函数
关闭浏览器:quit()
最大化窗口: maximize_window()
设置窗口参数:set_window_size(600,800)
刷新页面: refresh()
鼠标事件:
双击:double_click()
右击:context_click()
拖放:drag_and_drop()
悬停:move_to_element()
按下:click_and_hold()
键盘事件:
send_keys(Keys.BACK_SPACE) = BackSpace
send_keys(Keys.SPACE) = Space
send_keys(Keys.TAB) = Tab
send_keys(Keys.ESCAPE) = Esc
send_keys(Keys.ENTER) = Enter
send_keys(Keys.CONTROL,‘a’) = Ctrl+A
send_keys(Keys.F1) = 键盘F1
多表单切换:switch_to.frame()
多窗口切换:switch_to.window()
当前句柄:current_window_handle
所有句柄:window_handles
警告框处理:switch_to_alert()
text:返回所有alert/confirm/prompt中的文字信息
accept():接受现有警告框
dismiss():解散现有警告框
send_keys(keysToSend):发送文本至警告框
cookie处理:
get_cookies():获得所有cookie信息
get_cookie(name):返回字典的key为“name”的cookie信息
add_cookie(cookie_dict):添加cookie。“cookie_dict”指字典对象,必须有name和value值
delete_cookie(name,optionsString):删除cookie信息。“name”是要删除的cookie的名称,“optionsString”是该cookie的选项,目前支持的选项包括“路径”,“域”
delete_all_cookies():删除所有cookie信息
窗口截图:get_screenshot_as_file()
生成随机数:radint()
滚动条设置
-
# 使用scrollTop滑动到底部
-
js =
"var action=document.documentElement.scrollTop=10000"
-
driver.execute_script(js)
-
-
-
# 使用scrollTo设置位置
-
driver.set_window_size(
600,
600)
-
js =
"window.scrollTo(100,450);"
-
driver.execute_script(js)
转载:https://blog.csdn.net/qq_31033037/article/details/104795641