Selenium 与 PhantomJS

selenium和phantomjs概述

案例操作:模拟登陆csdn

1. selenium和phantomJS是什么东西?

selenium是一套web网站自动化测试工具,主要通过命令行的操作完成常规可视化界面下的用户各种操作行为,因为其简单易学成本低,并且执行测试效率较高而在web自动化测试方面比较突出,该库可以直接运行操作各种主流浏览器,辅助浏览器自动完成表单互动、鼠标点击、鼠标拖拽、窗口切换等等各种用户行为,是一套非常好用且强大的测试库,但是selenium没有内置的浏览器模块,不能独立运行,必须要和第三方浏览器配合使用才可以完成自动化测试操作。在实际操作的过程中,经常使用selenium和各大主流浏览器共同操作,如谷歌、火狐、IE等等,但是在selenium自动化测试发展过程中,有一个特殊的浏览器经常用于和它配合使用,就是比较出名的无界面浏览器phantomJS。

2. 爬虫、selenium、phantomJS这时候问题就来了,爬虫中,为什么要涉及到selenium测试工具和无界面浏览器这样的东东呢?

故事背景:那是很久的以前,人们生活在一个非常平和的年代

老李住在人民小区的一所豪宅中,人人互爱互助,路不拾遗夜不闭户已经成了传统

这天,从遥远的他乡来了一个人~老王(爬虫),禁不住五脏庙的闹腾,终于决定要找点吃的了,他一路独行直接进来了老李家,把老李留给媳妇的无骨炖鸡汤给吃了个精光,然后施施然潇洒的离去了

[爬虫老王,根据自己需要的数据对于网站服务器老李进行了数据采集,服务器没有任何防范,数据直接被获取到了!老李终于回家了,发现有人动了他的鸡汤....于是,晚上老李家传来了老李的惨叫声.>

老李吸取教训,应该是有小区之外的人进了小区,于是跟守门大妈说了一句,以后进门的人一定要问问有木有门卡(备注:门卡是小区住户才有的一种身份卡片),有卡才让进小区,否则不允许进入

[服务器老李由于数据无端泄露导致出现了安全问题,于是进行了简单的升级防范,针对所有进行访问的用户验证其User-agent,如果User-agent不合适则禁止访问]

老王这天又饿的不行了,但是进小区时发现大妈竟然要查牌,好吧,老王找到小区的某个人,请它吃了顿饭,顺便看了看门卡长的什么样子,然后自己偷偷去做了一张一模一样的卡片,然后 老王又进去了老李家,半夜~小区又传来了老李的惨叫

[爬虫老王通过抓包工具进行了服务器请求的抓包,分析了请求中的各项参数,在请求头中添加了浏览器的User-agent的值,再次访问服务器,顺利拿到了需要采集的数据]

老李愤慨于老王的行为,再次跟门口大妈说了说,家里的东西又被人动了,大妈回忆了一下这几天的情况,发现老王频繁的进入小区,于是大妈针对每天频繁进入小区的人单独进行了登记,注意防范,一旦出现就坚决不允许这样的人再进入小区

[服务器老李针对再次数据泄露,认识到了可能有非法用户多次采集数据造成的,于是针对限定时间频繁访问数据的操作进行了屏蔽,如果出现1分钟内访问次数超过30次的直接屏蔽ip地址]

老王这天来到小区门口,发现和他一样的老孙饿的皮包骨头,很诧异的问老孙什么情况,老孙据实说了实际情况,老孙已经进了大妈的黑名单,再也不能进小区觅食了!老王发现了这个问题之后,于是~每天只进入一次小区,还跟大妈很热情的打招呼呢.....老李是彻底的愤怒了,家里的吃的虽然没有像之前丢的那么频繁,但是终归还是丢了特别重要的部分,半夜时分,老李的惨叫是那么的惨绝人寰

[爬虫老王限制了爬虫访问服务器的时间,根据正常用户的发送请求的时间,限制了不同爬取请求之间的休眠时间,尽管采集数据较慢,但是同样得到了数据]

老李这次学乖了,出门的时候给家里上锁了,在也不愁数据数据再次丢失的问题了[服务器老李在请求参数中,添加了一个加密字段,如果参数中包含了正确的加密字段,就允许访问数据,如果参数中没有标注则拒绝访问]

老王已经饿了太多天了
老王找到了传说中的某个大师,跟他学了旷古绝技,于是在某个艳阳高照的晴天,再次进了老李家....这天半夜,老李默默的坐了一个晚上

[爬虫针对加密数据进行了分析追踪,得到了加密 的具体流程,于是进行了加密字段的重现,将加密数据通过请求传递给了服务器,顺利获取到了数据]

老李根据自己的需要,换了指纹密码锁[服务器针对数据安全问题,进行了再次升级,对数据进行了混淆编码的同时,通过混淆编码进行了多重加密操作,同时进行了多个字段的数字指纹签名操作,如果请求中不包含这些数据的情况下,拒绝提供数据]

老王看着紧锁的大门,想了很久,这天老李家来了客人,好酒好菜两人畅谈甚久,夜幕时分,老王施施然从老李家走了出来,身旁就是老李相送[客户端老王看到服务器老李已经做了非常复杂的反爬虫操作,于是权衡之后不再做反扒操作,直接让自己变成了正式用户发送请求,同样获取到了数据]

而这里涉及到的正式用户的请求,就是直接通过浏览器发送请求访问服务器,用到的浏览器就是phantomJS无界面浏览器,通过selenium测试工具发送请求操作访问过程获取数据

准备工作:selenium和PhantomJS
phantomjs:一个独立的无界面浏览器,并不是python模块,所以需要单独下载安装;

phantomjs官方网站:http://phantomjs.org/

selenium:独立的第三方模块,通过pip install selenium进行安装

PhantomJS

PhantomJS是一个基于Webkit的'无界面'浏览器
phantomJS 官网参考文档:http://phantomjs.org/documentation
官网下载安装: http://phantomjs.org/download.html
1、解压放到:C:\phantomjs-2.1.1-windows
2、需要设置环境变量,Path中添加
C:\phantomjs-2.1.1-windows\bin
3、在控制台中输入phantomjs -v,若输出了版本号,则证明安装成功

Chrome dirver的安装

1、打开如下页面:
https://sites.google.com/a/chromium.org/chromedriver/downloads
对照下载说明,找到对应的ChromeDriver版本
2、打开如下页面:
http://chromedriver.storage.googleapis.com/index.html
找到对应的版本,下载对应文件

案例

# 导入 webdriver
from selenium import webdriver
# 要想调用键盘按键操作需要引入 keys 包
from selenium.webdriver.common.keys import Keys
# 调用环境变量指定的 PhantomJS 浏览器创建浏览器对象
driver = webdriver.PhantomJS()
# get 方法会一直等到页面被完全加载,然后才会继续程序,通常测试会在这里选择
time.sleep(2)
driver.get("http://www.baidu.com/")
# 获取页面名为 wrapper 的 id 标签的文本内容
data = driver.find_element_by_id("wrapper").text
# 打印数据内容
print(data)
# 打印页面标题 "百度一下,你就知道"
print(driver.title)
# 生成当前页面快照并保存
driver.save_screenshot("baidu.png")
# id="kw"是百度搜索输入框,输入字符串"长城"
driver.find_element_by_id("kw").send_keys("奇酷信息")
# id="su"是百度搜索按钮,click() 是模拟点击
driver.find_element_by_id("su").click()
# 获取新的页面快照
driver.save_screenshot("奇酷信息.png")
# 打印网页渲染后的源代码
print(driver.page_source)
print('============')
# 获取当前页面 Cookie
print(driver.get_cookies())
# 清除输入框内容
driver.find_element_by_id("kw").clear()
print('============')
# 获取当前 url
print(driver.current_url)
# 关闭当前页面,如果只有一个页面,会关闭浏览器
driver.close()
# 关闭浏览器
driver.quit()

定位元素

单个元素查找
find_element_by_name
find_element_by_id
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_id
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

ActionChains

在页面上模拟一些鼠标操作,比如双击、右击、拖拽甚至按住不动等,可以通过导入ActionChains类实现
案例:

menu = driver.find_element_by_css_selector(".nav")
hidden_submenu = driver.find_element_by_css_selector(".nav #submenu1")
ActionChains(driver).move_to_element(menu).click(hidden_submenu).perform()
ActionChains方法列表
方法列表.jpg

selenium核心API

  • selenium.webdriver
  • selenium核心驱动模块,主要包含了web服务相关的核心操作,可以调用指定的服务器
driver = selenium.webdriver.PhantomJS() 
driver = selenium.webdriver.Chrome()
  • 浏览器填写url地址访问文章:
    driver.get("http://www.baidu.com")
  • 获取标签对象 find_element_by_id()
    根据标签编号查询标签对driver.find_by_element_by_id("box")
  • 同下:
from selenium.webdriver.common.by import By *
driver.find_element(by=By.ID, value='box') 
find_elements_by_name() 
  • 根据标签的name属性只查询标签对象
    driver.find_elements_by_name("real_name")

  • 同下:

from selenium.webdriver.common.by import By *
driver.find_elemnets(by=By.NAME, value='real_name') 
find_elemnets_by_xpath()
  • 根据xpath语法查询指定的标签
    driver.find_elements_by_xpath('//input[id="kw"]')
  • 同下:
from selenium.webdriver.common.by import By *
driver.find_elements(by=By.XPATH, value='//input[@id="kw"]')
find_elements_by_link_text() 
  • 根据超链接标签链接文本查询标签
    driver.find_elements_by_link_text('damu')
  • 同下:
from selenium.webdriver.common.by import By *
driver.find_elements(by=By.LINK_TEXT, value='damu') 
find_elemetns_by_partial_link_text() 
  • 根据超链接标签链接文本 扩展 查询标签
    driver.find_elements_by_partial_link_text('damu')
  • 同下:
from selenium.webdriver.common.by import By *
driver.find_elements(by=By.PARTIAL_LINK_TEXT, value='damu') 
find_elements_by_tag_name() 
  • 根据标签名称查询标签
    driver.find_elements_by_tag_text('damu')
  • 同下:
from selenium.webdriver.common.by import By *
driver.find_elements(by=By.TAG_NAME, value='damu') 
find_elements_by_class_name() 
  • 根据标签的class名称查询标签
    driver.find_elements_by_class_name("")
    同下:
from selenium.webdriver.common.by import By *
driver.find_elements(by=By.CLASS_NAME)
find_elements_by_css_selector() 
  • 根据标签的样式名称查询得到标签
    driver.find_elements_by_css_selector("#box > div")
  • 同下:
from selenium.webdriver.common.by import By *
driver.find_elements(by=By.CSS_SELECT, value='#box')
  • selenium.webdirver.common.keys.Keys
  • selenium用于操作用户键盘的核心模块
  • 表单处理:输入框填写数据
  • 选择输入框:kw = driver.find_element_by_id("kw")
  • 输入数据:kw.send_keys(u"关键字")
  • 表单处理:下拉列表框选择数据
from selenium.webdriver.support.ui import Select *
选择下拉框:sl = Select(driver.find_element_by_id("city"))        
输入选择的值: sl.select_by_index(1) 
根据值的索引赋值:sl.select_by_value("zhengzhou") 
根据具体下拉框的value赋值:sl.select_by_visible_text("郑州")
根据下拉框显示的值赋值:sl.deselect_all() 

全部取消 * 键盘按键:功能键+字母按键

from selenium.webdriver.common.keys import Keys
driver.find_element_by_id("kw").send_keys(Keys.CONTROL, "a")
# ctrl+a全选 * ALT:alt按键 * NUMBER1:数字键1 * LFET:←左方向键 * F1:功能键F1 
* 更多more~
selenium.webdriver.ActionChains 该模块包含了和鼠标操作相关的行为
模拟鼠标单击  driver.find_element_by_id("su").click() 
from selenium.webdriver import ActionChains # 引入鼠标模块 
su = driver.find_element_by_id("su") # 获取标签对象 
ActionChains(driver).move_to_element(su).perform()# 鼠标移动到对象上
ActionChains(driver).move_to_element(su).click(su).perform() # 鼠标单击
ActionChains(driver).move_to_element(su).double_click(su).perform()# 鼠标双击 
ActionChains(driver).move_to_element(su).context_click(su).perform()# 鼠标右键单击
ActionChains(driver).move_to_element(su).click_to_hold(su).perform()# 鼠标单击并按住 
pos1 = driver.find_element_by_element("pos1") 
pos2 = driver.find_element_by_element("pos2")
ActionChains(driver).drag_and_drop(pos1, pos2).perform() # 鼠标将pos1脱拽到pos2的位置
* 页面窗口操作 * 
driver.switch_to.window("window name")# 窗口诶切换 
driver.forward()# 导航前进 
driver.back()# 导航后退
* cookie操作 *
 driver.get_cookies() 获取当前正在访问url地址的所有cookies数据 
* driver.delete_cookie(key) 根据key值删除对应的cookie数据 
* driver.delete_all_cookies() 清空cookie* 网页延时:针对网页中通过Ajax异步加载Json数据的情况,不同的网速下返回Json数据并渲染页面会有延迟,网页中并不一定能正常获取数据,需要延时操作 * 显式等待 
# coding:utf-8 
from selenium import webdriver 
from selenium.webdriver.common.by import By 
from selenium.webdriver.support.ui import WebDriverWait 
from selenium.webdirver.support import except_conditions as EC 
driver = webdriver.PhantomJS()
driver.get("http://www.baidu.com") 
try: 
  # 获取标签:间隔10S获取标签~一直等待到标签获取成功 
  element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "box")) )
finally: 
  driver.quit() 

这里的等待条件,就是except_conditions调用时执行的函数,内置如下条件可以直接调用

 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 
  • 隐时等待:设置一个等待时间即可
# coding:utf-8 
from selenium import webdriver 
driver = webdriver.PhantomJS() driver.implicitly_wait(10)
driver.get("http://www.baidu.com")
driver.find_element_by_id("su") 

以上,是selenium核心的几个API操作方式

案例:CSDN登录真实用户登录CSDN场景:

  • 用户打开浏览器,访问并打开csdn登录网页
  • 填写账号、密码,点击登录
  • 进入CSDN主页selenium配合phantomjs完成登录操作,并保存数据到文件中
# coding:utf-8
from selenium import webdriver
driver = webdriver.PhantomJS("./phantomjs-2.1.1/bin/phantomjs")
# 访问登录页面
driver.get("https://passport.csdn.net/account/login?ref=toolbar")
# 保存登录页面截图
driver.save_screenshot("csdn1.png")
# 获取登录 用户输入框、密码输入框
u_name = driver.find_element_by_id("username").send_keys("damumoye")
p_word = driver.find_element_by_id("password").send_keys("********")
# 模拟点击登录
login_btn = driver.find_element_by_css_selector("#fm1 .logging")login_btn.click()
# 保存登录后的截图
driver.save_screenshot("csdn2.png")
# 保存数据
with open("csdn.html", "w") as f: 
  f.write(driver.page_source.encode("utf-8"))
# 退出浏览器
driver.quit()
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容