selenium自动化测试工具的爬虫之旅

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)

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值