澳门新萄京官方网站-www.8455.com-澳门新萄京赌场网址

数据报表自动化深入分析,selenium的第三方广告检

2019-11-04 作者:www.8455.com   |   浏览(156)

急需应际而生/使用景况:

  因为集团索要将word办的接口文档在线化,看起来是个很好的事务,不过正是苦逼了我们那个干活儿的,当中工程量最大的正是参数的录入,假诺参数少也罢,有的接口动辄三叁18个参数,更甚八93个,小编手动复制了三个三四十多个的就让小编出乎意料人生,小编觉的自家的人生不能够在赋值接口参数中浪费掉。从前也学过一些python知识,也举办过通过selenium来模拟点击,所以就萌发了多个读取文件然后通过selenium来进行表单的填写和交由,达成工具以往会省去大概七成的专门的学问量。 大大进步了频率,也收缩了对手腕的损害。

  上面是参数录入分界面,能够明白点击以往叁个个粘贴须要费多大的劲头。

澳门新萄京官方网站 1


本文的工程指标是运用ruby编写二个本子文件,完成对网页中第三方广告的检验和总结。
体系源代码:https://github.com/vito0705/selenium_vito

Selenium自动化测量检验库模拟登入

原文:

落实进程:

  上边介绍一下兑现进度及思路,因为要复制word中的内容,但是在word中的格式不是联合的, 所以要拓宽人工的将接口复制到文本文书档案中,並且要做相应的格式管理,所以这么些工具归于于半自动化。

效率展示动图

本文主要内容


  • 生机勃勃.项目剖判
    • 项目目标
    • 花色供给
    • 品类铲除思路
  • 二.情状配置
    • Linux下遇到安顿
    • Windows下景况陈设
  • 三.程序编写制定
    • 品种统筹思路
    • 代码完成
      • (风度翩翩卡塔 尔(英语:State of Qatar)加载库文件
      • (二卡塔尔开头化部分
      • (三卡塔 尔(阿拉伯语:قطر‎网页检验部分
      • (四卡塔尔代码推行部分
  • 四.脚本使用
  • 五.总结

1:用场主要用于驱动浏览器实行自动化的操作。

谢谢灰蓝大神!

  1.读取文件

    首先要经过python实行理文件件的读取,一定要说python的语法是真的简简洁,读取文件意气风发行代码的事,然后剩下的正是基于有个别标记符,对每意气风发行数据进行拍卖存储。  下列是读取文件代码示例:

    f = open("C:\Users\Administrator\Desktop\api.txt", 'r', encoding='UTF-8')
    list = f.readlines()

需求:
博主以前有意气风发段时间忽地不想玩果壳网了,然后恰恰四弟想玩,就给她用了,手提式有线电电话机绑定也换来了他的号子。近期意想不到又想要玩,就重新开了个号。新号博客园空空的,也从不什么样关切。于是就时有产生了多少个须求,正巧能够借这几个时机学习一下自动化测验工具webdriver的着力使用:
1、将原网易的博文搬到新账号
2、用新账号关心原搜狐的有着关怀

黄金年代.项目分析


2:支持的浏览器有 Google,火狐浏览器等。

本框架传送门:

  2.上马使用selenium

    selenium能够支撑火狐、IE、Google,使用的时候都急需先下载对应的浏览器驱动,这里作者选择谷歌(Google卡塔尔。首先去下载浏览器驱动,    在此个网站下载 ,相同的时候,贴出Chrome浏览器版本和与之相应的驱动,参谋网站 

澳门新萄京官方网站 2

    下载完未来还须要进行配备, 一是内需去情况变量配置,在上头网站中有介绍,二是一向内定路径,笔者使用的是第三种方法,比较方便,不要遗忘导入对应的模块

    browser = webdriver.Chrome(executable_path=".chromedriver.exe")

 

    selenium的基本操作,这里只介绍部分那几个代码中动用到的,更加的多API百度一下不行多:

    browser.get("https://baidu.com")    // 访问网址
    obj = browser.find_element_by_id("ks_ka_api_id")   // 通过id查找元素
    obj1 = browser.find_element_by_xpath('//*[@id="test_form"]/input[5]') // 通过xpath查找元素
    obj2 = find_elements_by_tag_name("p") // 通过Dom来查找元素

    obj2.send_keys();    // 填充数据
    obj.click()    // 点击按钮

    在自动话的经过中选取到了下拉框的选料,通过寻找能够通过须臾间代码来促成钦命选中,别的的主意能够透过网络教程来询问:

    f_selet = Select(browser.find_element_by_id("ks_ka_id"))   // 下拉框对象
    f_selet.select_by_visible_text(select_text)   // 选中哪个文本

说明:
本篇首要描述第一个须求的落到实处,第一个要求的落实参见python爬虫入门 实战(六卡塔尔国---用webdriver完成天涯论坛批量自动关心。

花色指标

对页面中的第三方广告举办检验,寻觅里面隐蔽的广告网页并将数据记录下来。

意况寻思:

在早先早前,请让自家先评释几点:

总结:     

  到目前甘休基本宗旨部分的笔触就完了了,然后对代码举行修饰,增添日志和充裕处理,代码就成功了,贴出完毕代码。  那个程序亦不是特意复杂, 可是能够对有蒙受近似情况的提供贰个减去本身专业量的思绪。今后间照旧得以看出这种絮乱而且重复的分神仍可以通过代码来编排一些自动化学工业具的常常多思忖,这种时候就能够让和睦的工作量减少过多,做出了这几个软件一方面是压缩专业量,另一面也是开展了python的就学,一矢双穿。

  同期大家不只怕每一遍运营这些顺序都以通过ide来运行,最棒的措施是打成exe,需求的时候只要求双击一下。  假若有需求打开包装功用的校友能够看下后生可畏篇作品: 

澳门新萄京官方网站 3View Code

 

涉及:
1、request的大旨使用
2、json解析
3、用request下载图片并保留到本地
4、用webdriver登陆并发送和讯
5、用autoIT消除非input型的文本上传

品种必要

  • 检验全体广告及广告的域并记录下来
  • 总结全部广告的数目及其间隐蔽广告的数目
  • 以表格格局保留数据

Selenium 安装

  1. 请保管您早就调整了宗旨的Python语法
  2. 假若您要搭建UI框架,请保管您早已调控了Selenium的基本用法
  3. 以此框架首要面向刚刚会写脚本可是不清楚该怎么着走向下一步的同班,应接戏弄,但最佳带上校正提出

本篇目录:
1.思路
2.爬取原天涯论坛
3.用webdriver运营浏览器登陆乐乎
4.用webdriver发表带图片的和讯
5.完好代码
6.功效体现动图
7.参考

类型解决思路

  • 其三方广告都在网页中的iframe标签中,需要从iframe标签中获得所需的数量
  • 依赖需求,大家筛选selenium用作web自动化测验工具
  • 数码必要保留在表格中,大家采纳spreadsheet这一个gem来实现相关职能

pip3 install selenium

观念:我们须要二个哪些的框架

既是要搭四个框架,我们先是得弄领会大家须求二个什么的框架,那几个框架要协理什么成效?

框架首要的信守正是扶助大家编辑特别简便易行并且好保安的用例,让大家把首要精力放在测试用例的宏图上,那么大家就必要把装有额外的事物抽象出来作为框架的一些。

那就是说,额外的事物是什么样?

  1. 日志以致报告
  2. 日志品级、U奥迪Q7L、浏览器类型等主导配备
  3. 参数化
  4. 国有艺术

二.情状配置


Linux和windows下均能够行使那一个本子,但对此情形安顿略有分歧。

测验是还是不是安装落成:
import selenium 是不是报错

搭建框架目录结构

近年来大家十分轻巧就把框架的布局搭建好了:

Test_framework
    |--config(配置文件)
    |--data(数据文件)
    |--drivers(驱动)
    |--log(日志)
    |--report(报告)
    |--test(测试用例)
    |--utils(公共方法)
    |--ReadMe.md(加个说明性的文件,告诉团队成员框架需要的环境以及用法)

接下去有局地选用题要做了:

图1.封面而已

Linux下碰到安顿

基本操作:

Python 2 or 3? Selenium 2 or 3?

Python 3的利用更为多,何况3的unittest中蕴藏subTest,能够通过子用例达成参数化。而用2的话须求unittest2或别的的库来实现,所以我们那边选取python 3。

Selenium 3刚发布正式版不久,一些成效driver还没赶趟跟上,特别是geckodriver,所以接收Selenium 2(PY3应当要用selenium2.53.1卡塔尔国。

条件选拔实在影响极小,你也能够筛选你自个儿习于旧贯的条件。

思路

1、爬取原网易的博文内容,爬一条发一条
2、文字音讯保存在list里,图片保存到本地
3、用webdriver完毕批量出殡和下葬和讯
4、上传图片依附第三方工具autoIT

注:
何以用webdriver来发新浪而不用天涯论坛开放平台的api?
因为公布带图片的新浪的api是高端api供给创设应用并通过查处本领申请,而过审并非足以糊弄的,需求成熟且系统的行使。

1.安装ruby

能够参照那篇文章中央银行使rvm管理ruby的点子安装,须求ruby版本大于等于2.0,具体安装不作越来越多表明。

1:声爱他美个浏览器驱动对象

安顿文件

布局文件大家有多样增选:ini、yaml、xml、properties、txt、py等

鉴于笔者在此以前写过风度翩翩篇yaml的博文,大家这里就用yaml吧。

之所以大家在config文件夹里创造config.yml文件,在utils里创立四个config.py文件读取配置,内容权且无论。

爬取原博客园

有关爬取新浪的详细思路和兑现能够参考笔者从前写的另朝气蓬勃篇:
python爬虫入门 实战(四卡塔尔---爬“榜姐”话题博客园及销路好争辩

这里会间接引进实战四的代码模块crawl_weibo,当中的getWeibo方法能够取拿到钦赐腾讯网顾客的富有新浪的json,并领取此中的cards(一个list数组,全体的今日头条音讯都在里边卡塔尔国再次回到,该模块详细源码参见以上链接末尾。

getWeibo方法:

# 获取指定博主的所有微博card的list
def getWeibo(self,id,page):#id(字符串类型):博主的用户id,page(整型):微博翻页参数

    url='https://m.weibo.cn/api/container/getIndex?type=uid&value=' id '&containerid=107603' id '&page=' str(page)
    response=requests.get(url)
    ob_json=json.loads(response.text)

    list_cards=ob_json['cards']
    return list_cards# 返回本页所有的cards

第后生可畏鲜明我们要爬取原新浪的具备除了转载以外的新浪的初稿、图片以至来自、点赞数、商量数等任何新闻。接下来先深入分析一下json 的构造,json的格式化推荐json.cn。

图2.json结构

事先教程里也说了,json正是list和dict的并行嵌套,所以只要会用list和dict,搞清楚json结构,提取数额就比较轻巧了。

我们把文字音信提抽出来,把图纸都下载到本地的一个文书夹里,以便之后发今日头条上传。对于图片存款和储蓄,用request来get一下图形的url,获取的归来内容用open创设多少个.jpg格式的file来写入。为了上传的时候便于填写图片地址,图片按梯次编号存入项目下的img文件夹中。上传时只须求依靠图片总量按序遍历就能够

收获天涯论坛内容数据代码:

def getContent(self,card):# 获取该card下微博的内容
    mblog=card['mblog']
    count_img=0# 每条微博重新计数图片数,用于发送图片的地址

    text= html.fromstring(mblog['text'])
    text=text.xpath('string(.)')#过滤正文中的多余标签

    url_img=''
    if 'pics' in mblog:#如果mblog中有键'pics',说明该条微博有图片,存储图片到本地
        pics=mblog['pics']
        for pic in pics:
            url_img=pic['large']['url']
            ir = requests.get(url_img)
            if ir.status_code == 200:# 如果请求已成功
                count_img =1# 给图片计数
                open('../img/' str(count_img) '.jpg', 'wb').write(ir.content)# 保存在img文件夹下,发送也从这个文件夹下找


    scheme=card['scheme']# 原微博链接
    created_at=mblog['created_at']# 原微博创建时间
    source=mblog['source']# 原微博来源,即终端
    reposts_count=mblog['reposts_count']# 原微博转发数
    comments_count=mblog['comments_count']# 原微博评论数
    attitudes_count=mblog['attitudes_count']# 原微博点赞数

    return text,count_img,scheme,created_at,source,reposts_count,comments_count,attitudes_count# 其实返回的是一个list

将getWeibo再次来到的list(也便是json中的cards卡塔尔国中的三个card传入以上函数,就能够回到大家要求的数码,细节见注释。通过那么些主意大家需求揭橥的天涯论坛数据现已得以爬取到了,接下去大家要登入微博把它们披表露来。

2.安装ruby版本的selenium

terminal中执行:

gem install selenium-webdriver  

selenium-webdriver的Github源码地址

from selenium import webdriver
browser = webdriver.Chrome()
运维报错:

大致的对未来的内容勾画一下

  1. 首先大家要把安顿收取来,用yaml文件放配置。所以我们要在config层加多安插文件config.yml,在utils层增添file_reader.py与config.py来管理。——何以从0早先搭建三个测量检验框架_1
  2. 然后大家将python自带的logging模块封装了弹指间,从安排文件读取并安装固定的logger。在utils中创制了log.py。——何以从0开端搭建一个测验框架_2
  3. 接下来封装xlrd模块,读取excel,达成用例的参数化。——什么从0开头搭建一个测验框架_3
  4. 接下来是生成HTML测量检验报告,这几个博主修正了英特网原有的HTMLTestRunner,改为华语并标榜,然后改进其帮衬PY3。你能够平素拿去用。——怎么着从0起头搭建一个测量检验框架_4
  5. 接下来大家给框架增加了发送邮件报告的能力。在utils中增多了mail.py。——什么从0初步搭建多少个测量检验框架_5
  6. 然后我们将测验用例用Page-Object思想举行包装,进一层细分test层的子层。——怎么从0起首搭建八个测量检验框架_6
  7. 接下去为了接口测验封装client类。在utils中增多了client.py。——什么样从0开端搭建一个测验框架_7
  8. 下一场加多了三个轻便易行的自定义断言,在utils中增加assertion.py,可用相仿的点子自行扩充。——什么样从0最初搭建七个测验框架_8
  9. 接下去大家为了收取响应结果,用JMES帕特h封装Extractor,在utils中增添extractor.py。——哪些从0开始搭建四个测验框架_9
  10. 然后是生成器。为大家自动生成固定类型的测量检验数据。utils下创办了generator.py。——何以从0开首搭建叁个测验框架_10
  11. 最后为了局地体系中的帮忙措施,如加密、具名等,创立援救库support.py。——如何从0初叶搭建一个测验框架_11

全副流程下来我们八个轻便易行的框架就如模像样了,在那底工上可继续周详,实际用在品种中也还未有什么样难题,再轻便构成 Jenkins 布置起来,定时或每一回代码提交后可自动运营测量检验,直接把测量检验报告发送到项目成员手中,妥妥的!接下去就跟自己一块学习呢。

这一步大家用到了selenium的着力的学识,以至一些unittest和PyYaml库的从头到尾的经过。

作者们先创设二个大致的本子吧,在test文件夹创设test_baidu.py:

import os
import time
from selenium import webdriver
from selenium.webdriver.common.by import By

URL = "http://www.baidu.com"
base_path = os.path.dirname(os.path.abspath(__file__))   '..'
driver_path = os.path.abspath(base_path 'driverschromedriver.exe')

locator_kw = (By.ID, 'kw')
locator_su = (By.ID, 'su')
locator_result = (By.XPATH, '//div[contains(@class, "result")]/h3/a')

driver = webdriver.Chrome(executable_path=driver_path)
driver.get(URL)
driver.find_element(*locator_kw).send_keys('selenium 灰蓝')
driver.find_element(*locator_su).click()
time.sleep(2)
links = driver.find_elements(*locator_result)
for link in links:
    print(link.text)
driver.quit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

剧本张开chrome,输入“selenium 灰蓝”,然后把装有结果中的标题打字与印刷出来。

生机勃勃经想要搜索“Python selenium”,是否要再成立贰个本子?仍旧把原本的脚本修改一下?

抑或大家得以用unittest来改一下,把五次寻找分别写叁个测试方法:

import os
import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By


class TestBaiDu(unittest.TestCase):
    URL = "http://www.baidu.com"
    base_path = os.path.dirname(os.path.abspath(__file__))   '..'
    driver_path = os.path.abspath(base_path 'driverschromedriver.exe')

    locator_kw = (By.ID, 'kw')
    locator_su = (By.ID, 'su')
    locator_result = (By.XPATH, '//div[contains(@class, "result")]/h3/a')

    def setUp(self):
        self.driver = webdriver.Chrome(executable_path=self.driver_path)
        self.driver.get(self.URL)

    def tearDown(self):
        self.driver.quit()

    def test_search_0(self):
        self.driver.find_element(*self.locator_kw).send_keys('selenium 灰蓝')
        self.driver.find_element(*self.locator_su).click()
        time.sleep(2)
        links = self.driver.find_elements(*self.locator_result)
        for link in links:
            print(link.text)

    def test_search_1(self):
        self.driver.find_element(*self.locator_kw).send_keys('Python selenium')
        self.driver.find_element(*self.locator_su).click()
        time.sleep(2)
        links = self.driver.find_elements(*self.locator_result)
        for link in links:
            print(link.text)


if __name__ == '__main__':
    unittest.main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

当今,大家把布署抽取来放到config.yml中:

URL: http://www.baidu.com
  • 1
  • 1

为了读取yaml文件,大家须求叁个封装Yaml里德r类,在utils中开创file_reader.py文件:

import yaml
import os


class YamlReader:
    def __init__(self, yamlf):
        if os.path.exists(yamlf):
            self.yamlf = yamlf
        else:
            raise FileNotFoundError('文件不存在!')
        self._data = None

    @property
    def data(self):
        # 如果是第一次调用data,读取yaml文档,否则直接返回之前保存的数据
        if not self._data:
            with open(self.yamlf, 'rb') as f:
                self._data = list(yaml.safe_load_all(f))  # load后是个generator,用list组织成列表
        return self._data
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

並且大家须要叁个Config类来读取配置,config.py:

"""
读取配置。这里配置文件用的yaml,也可用其他如XML,INI等,需在file_reader中添加相应的Reader进行处理。
"""
import os
from utils.file_reader import YamlReader

# 通过当前文件的绝对路径,其父级目录一定是框架的base目录,然后确定各层的绝对路径。如果你的结构不同,可自行修改。
BASE_PATH = os.path.abspath(os.path.dirname(os.path.abspath(__file__))   '..')
CONFIG_FILE = BASE_PATH   'configconfig.yml'
DATA_PATH = BASE_PATH   'data\'
DRIVER_PATH = BASE_PATH   'drivers\'
LOG_PATH = BASE_PATH   'log\'
REPORT_PATH = BASE_PATH   '\report\'


class Config:
    def __init__(self, config=CONFIG_FILE):
        self.config = YamlReader(config).data

    def get(self, element, index=0):
        """
        yaml是可以通过'---'分节的。用YamlReader读取返回的是一个list,第一项是默认的节,如果有多个节,可以传入index来获取。
        这样我们其实可以把框架相关的配置放在默认节,其他的关于项目的配置放在其他节中。可以在框架中实现多个项目的测试。
        """
        return self.config[index].get(element)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

修改test_baidu.py:

import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from utils.config import Config, DRIVER_PATH


class TestBaiDu(unittest.TestCase):
    URL = Config().get('URL')

    locator_kw = (By.ID, 'kw')
    locator_su = (By.ID, 'su')
    locator_result = (By.XPATH, '//div[contains(@class, "result")]/h3/a')

    def setUp(self):
        self.driver = webdriver.Chrome(executable_path=DRIVER_PATH   'chromedriver.exe')
        self.driver.get(self.URL)

    def tearDown(self):
        self.driver.quit()

    def test_search_0(self):
        self.driver.find_element(*self.locator_kw).send_keys('selenium 灰蓝')
        self.driver.find_element(*self.locator_su).click()
        time.sleep(2)
        links = self.driver.find_elements(*self.locator_result)
        for link in links:
            print(link.text)

    def test_search_1(self):
        self.driver.find_element(*self.locator_kw).send_keys('Python selenium')
        self.driver.find_element(*self.locator_su).click()
        time.sleep(2)
        links = self.driver.find_elements(*self.locator_result)
        for link in links:
            print(link.text)


if __name__ == '__main__':
    unittest.main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

咱俩早就把安顿分离出来了,尽管今后看起来就像很麻烦,不过观念假设您有49个用例文件以至越多,大器晚成旦项目U奔驰M级L变了,你还要八个个去更改吗?

那有的需求事先驾驭Python的内置库logging

接下去大家为大家的框架加上log,在utils中开创叁个log.py文件,python有很有益于的logging库,大家对其进行轻易的包裹,使框架能够很简短地打字与印刷日志(输出到调整台以至日志文件卡塔尔国。

import logging
from logging.handlers import TimedRotatingFileHandler
from utils.config import LOG_PATH


class Logger(object):
    def __init__(self, logger_name='framework'):
        self.logger = logging.getLogger(logger_name)
        logging.root.setLevel(logging.NOTSET)
        self.log_file_name = 'test.log'
        self.backup_count = 5
        # 日志输出级别
        self.console_output_level = 'WARNING'
        self.file_output_level = 'DEBUG'
        # 日志输出格式
        self.formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    def get_logger(self):
        """在logger中添加日志句柄并返回,如果logger已有句柄,则直接返回"""
        if not self.logger.handlers:  # 避免重复日志
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(self.formatter)
            console_handler.setLevel(self.console_output_level)
            self.logger.addHandler(console_handler)

            # 每天重新创建一个日志文件,最多保留backup_count份
            file_handler = TimedRotatingFileHandler(filename=LOG_PATH   self.log_file_name,
                                                    when='D',
                                                    interval=1,
                                                    backupCount=self.backup_count,
                                                    delay=True,
                                                    encoding='utf-8'
                                                    )
            file_handler.setFormatter(self.formatter)
            file_handler.setLevel(self.file_output_level)
            self.logger.addHandler(file_handler)
        return self.logger

logger = Logger().get_logger()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

接下来更改test_baidu.py,将出口改到log中:

import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from utils.config import Config, DRIVER_PATH
from utils.log import logger


class TestBaiDu(unittest.TestCase):
    URL = Config().get('URL')

    locator_kw = (By.ID, 'kw')
    locator_su = (By.ID, 'su')
    locator_result = (By.XPATH, '//div[contains(@class, "result")]/h3/a')

    def setUp(self):
        self.driver = webdriver.Chrome(executable_path=DRIVER_PATH   'chromedriver.exe')
        self.driver.get(self.URL)

    def tearDown(self):
        self.driver.quit()

    def test_search_0(self):
        self.driver.find_element(*self.locator_kw).send_keys('selenium 灰蓝')
        self.driver.find_element(*self.locator_su).click()
        time.sleep(2)
        links = self.driver.find_elements(*self.locator_result)
        for link in links:
            logger.info(link.text)

    def test_search_1(self):
        self.driver.find_element(*self.locator_kw).send_keys('Python selenium')
        self.driver.find_element(*self.locator_su).click()
        time.sleep(2)
        links = self.driver.find_elements(*self.locator_result)
        for link in links:
            logger.info(link.text)


if __name__ == '__main__':
    unittest.main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

进行后,能够观望在log文件夹下创建了test.log文件,打字与印刷的音信都输出到了文本中:

2017-07-26 16:00:59,457 - framework - INFO - Python selenium —— 一定要会用selenium的等待,三种..._CSDN博客
2017-07-26 16:00:59,487 - framework - INFO - Selenium - 灰蓝 - CSDN博客
2017-07-26 16:00:59,515 - framework - INFO - ...教你在Windows上搭建Python Selenium环境 - 灰蓝 - CSDN博客...
2017-07-26 16:00:59,546 - framework - INFO - Python selenium —— 父子、兄弟、相邻节点定位方式详..._CSDN博客
2017-07-26 16:00:59,572 - framework - INFO - Selenium - 灰蓝 - CSDN博客
2017-07-26 16:00:59,595 - framework - INFO - selenium之 时间日期控件的处理 - 灰蓝 - CSDN博客
...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

笔者们还是能够把log的设贮存到config中,匡正config.yml,将几项珍视的安装都写进去:

URL: http://www.baidu.com
log:
    file_name: test.log
    backup: 5
    console_level: WARNING
    file_level: DEBUG
    pattern: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

并且修改log.py,读取config,如若config中有,则运用文件中的设置,不然,选择暗许设置

"""
日志类。通过读取配置文件,定义日志级别、日志文件名、日志格式等。
一般直接把logger import进去
from utils.log import logger
logger.info('test log')
"""
import logging
from logging.handlers import TimedRotatingFileHandler
from utils.config import LOG_PATH, Config


class Logger(object):
    def __init__(self, logger_name='framework'):
        self.logger = logging.getLogger(logger_name)
        logging.root.setLevel(logging.NOTSET)
        c = Config().get('log')
        self.log_file_name = c.get('file_name') if c and c.get('file_name') else 'test.log'  # 日志文件
        self.backup_count = c.get('backup') if c and c.get('backup') else 5  # 保留的日志数量
        # 日志输出级别
        self.console_output_level = c.get('console_level') if c and c.get('console_level') else 'WARNING'
        self.file_output_level = c.get('file_level') if c and c.get('file_level') else 'DEBUG'
        # 日志输出格式
        pattern = c.get('pattern') if c and c.get('pattern') else '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
        self.formatter = logging.Formatter(pattern)

    def get_logger(self):
        """在logger中添加日志句柄并返回,如果logger已有句柄,则直接返回
        我们这里添加两个句柄,一个输出日志到控制台,另一个输出到日志文件。
        两个句柄的日志级别不同,在配置文件中可设置。
        """
        if not self.logger.handlers:  # 避免重复日志
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(self.formatter)
            console_handler.setLevel(self.console_output_level)
            self.logger.addHandler(console_handler)

            # 每天重新创建一个日志文件,最多保留backup_count份
            file_handler = TimedRotatingFileHandler(filename=LOG_PATH   self.log_file_name,
                                                    when='D',
                                                    interval=1,
                                                    backupCount=self.backup_count,
                                                    delay=True,
                                                    encoding='utf-8'
                                                    )
            file_handler.setFormatter(self.formatter)
            file_handler.setLevel(self.file_output_level)
            self.logger.addHandler(file_handler)
        return self.logger

logger = Logger().get_logger()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 澳门新萄京官方网站,41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

今昔,我们早就能够很有利地出口日志了,何况能够经过配备config.yml来改正log的装置。

负有的代码小编都放到了GITHUB上传送,能够本人下载去学习,有何样好的提议依旧难题,能够留言大概加小编的QQ群:455478219讨论。

这一步大家供给使用Python库xlrd

我们早已把布署抽离,并加多了log,接下去我们理应尝试着开展多少抽离,进行参数化了。

咱俩更正file_reader.py文件,增多ExcelReader类,完结读取excel内容的作用:

"""
文件读取。YamlReader读取yaml文件,ExcelReader读取excel。
"""
import yaml
import os
from xlrd import open_workbook


class YamlReader:
    def __init__(self, yamlf):
        if os.path.exists(yamlf):
            self.yamlf = yamlf
        else:
            raise FileNotFoundError('文件不存在!')
        self._data = None

    @property
    def data(self):
        # 如果是第一次调用data,读取yaml文档,否则直接返回之前保存的数据
        if not self._data:
            with open(self.yamlf, 'rb') as f:
                self._data = list(yaml.safe_load_all(f))  # load后是个generator,用list组织成列表
        return self._data


class SheetTypeError(Exception):
    pass


class ExcelReader:
    """
    读取excel文件中的内容。返回list。

    如:
    excel中内容为:
    | A  | B  | C  |
    | A1 | B1 | C1 |
    | A2 | B2 | C2 |

    如果 print(ExcelReader(excel, title_line=True).data),输出结果:
    [{A: A1, B: B1, C:C1}, {A:A2, B:B2, C:C2}]

    如果 print(ExcelReader(excel, title_line=False).data),输出结果:
    [[A,B,C], [A1,B1,C1], [A2,B2,C2]]

    可以指定sheet,通过index或者name:
    ExcelReader(excel, sheet=2)
    ExcelReader(excel, sheet='BaiDuTest')
    """
    def __init__(self, excel, sheet=0, title_line=True):
        if os.path.exists(excel):
            self.excel = excel
        else:
            raise FileNotFoundError('文件不存在!')
        self.sheet = sheet
        self.title_line = title_line
        self._data = list()

    @property
    def data(self):
        if not self._data:
            workbook = open_workbook(self.excel)
            if type(self.sheet) not in [int, str]:
                raise SheetTypeError('Please pass in <type int> or <type str>, not {0}'.format(type(self.sheet)))
            elif type(self.sheet) == int:
                s = workbook.sheet_by_index(self.sheet)
            else:
                s = workbook.sheet_by_name(self.sheet)

            if self.title_line:
                title = s.row_values(0)  # 首行为title
                for col in range(1, s.nrows):
                    # 依次遍历其余行,与首行组成dict,拼到self._data中
                    self._data.append(dict(zip(title, s.row_values(col))))
            else:
                for col in range(0, s.nrows):
                    # 遍历所有行,拼到self._data中
                    self._data.append(s.row_values(col))
        return self._data


if __name__ == '__main__':
    y = 'E:Test_frameworkconfigconfig.yml'
    reader = YamlReader(y)
    print(reader.data)

    e = 'E:/Test_framework/data/baidu.xlsx'
    reader = ExcelReader(e, title_line=True)
    print(reader.data)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90

大家加多title_line参数,用来声称是还是不是在excel表格里有题目行,若是有标题行,重临dict列表,不然重返list列表,如下:

# excel表格如下:
# | title1 | title2 |
# | value1 | value2 |
# | value3 | value4 |

# 如果title_line=True
[{"title1": "value1", "title2": "value2"}, {"title1": "value3", "title2": "value4"}]

# 如果title_line=False
[["title1", "title2"], ["value1", "value2"], ["value3", "value4"]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在data目录下创办baidu.xlsx,如下:

| search |
| selenium 灰蓝 |
| Python selenium |
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

下一场我们再校正大家相当的小用例:

import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from utils.config import Config, DRIVER_PATH, DATA_PATH
from utils.log import logger
from utils.file_reader import ExcelReader


class TestBaiDu(unittest.TestCase):
    URL = Config().get('URL')
    excel = DATA_PATH   '/baidu.xlsx'

    locator_kw = (By.ID, 'kw')
    locator_su = (By.ID, 'su')
    locator_result = (By.XPATH, '//div[contains(@class, "result")]/h3/a')

    def sub_setUp(self):
        self.driver = webdriver.Chrome(executable_path=DRIVER_PATH   'chromedriver.exe')
        self.driver.get(self.URL)

    def sub_tearDown(self):
        self.driver.quit()

    def test_search(self):
        datas = ExcelReader(self.excel).data
        for d in datas:
            with self.subTest(data=d):
                self.sub_setUp()
                self.driver.find_element(*self.locator_kw).send_keys(d['search'])
                self.driver.find_element(*self.locator_su).click()
                time.sleep(2)
                links = self.driver.find_elements(*self.locator_result)
                for link in links:
                    logger.info(link.text)
                self.sub_tearDown()


if __name__ == '__main__':
    unittest.main(verbosity=2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

subTest是PY3 unittest里带的功用,PY第22中学尚无,PY第22中学要想行使,供给用unittest2库。subTest是绝非setUp和tearDown的,所以需求团结手动增添并进行。

今昔我们就兑现了数码抽离,之后若是要研究“张三”、“李四”,只要在excel里增多行就足以了。subTest参数化也援助我们少写了过多用例方法,不用叁遍遍在Case里copy and paste了。

这一步我们要求选择并校勘HTMLTestRunner.py,它本身是依照PY2的,轻巧而实用,在此以前博主对其展开了美化,而且改成了中文(下载链接)。 
后天博主基于此开展了对PY3的改善,扩展了对subTest的扶助。

  1. StringIO -> io
  2. 去掉decode
  3. 增加addSubTest()

有的改过内容:

# import StringIO  # PY3改成了io库
import io
...
  def startTest(self, test):
          TestResult.startTest(self, test)
          # just one buffer for both stdout and stderr
          # self.outputBuffer = StringIO.StringIO()
          self.outputBuffer = io.StringIO()
...
# 添加addSubTest方法,将有subTest的Case拆分成多个Case,均在报告中输出。这点处理与unittest的TextRunner并不相同,细心的同学可以试验下,看看它是怎么处理的。
    def addSubTest(self, test, subtest, err):
            if err is not None:
                if getattr(self, 'failfast', False):
                    self.stop()
                if issubclass(err[0], test.failureException):
                    self.failure_count  = 1
                    errors = self.failures
                    errors.append((subtest, self._exc_info_to_string(err, subtest)))
                    output = self.complete_output()
                    self.result.append((1, test, output   'nSubTestCase Failed:n'   str(subtest),
                                        self._exc_info_to_string(err, subtest)))
                    if self.verbosity > 1:
                        sys.stderr.write('F  ')
                        sys.stderr.write(str(subtest))
                        sys.stderr.write('n')
                    else:
                        sys.stderr.write('F')
                else:
                    self.error_count  = 1
                    errors = self.errors
                    errors.append((subtest, self._exc_info_to_string(err, subtest)))
                    output = self.complete_output()
                    self.result.append(
                        (2, test, output   'nSubTestCase Error:n'   str(subtest), self._exc_info_to_string(err, subtest)))
                    if self.verbosity > 1:
                        sys.stderr.write('E  ')
                        sys.stderr.write(str(subtest))
                        sys.stderr.write('n')
                    else:
                        sys.stderr.write('E')
                self._mirrorOutput = True
            else:
                self.subtestlist.append(subtest)
                self.subtestlist.append(test)
                self.success_count  = 1
                output = self.complete_output()
                self.result.append((0, test, output   'nSubTestCase Pass:n'   str(subtest), ''))
                if self.verbosity > 1:
                    sys.stderr.write('ok ')
                    sys.stderr.write(str(subtest))
                    sys.stderr.write('n')
                else:
                    sys.stderr.write('.')
...
  def run(self, test):
          "Run the given test case or test suite."
          result = _TestResult(self.verbosity)
          test(result)
          self.stopTime = datetime.datetime.now()
          self.generateReport(test, result)
          # print >>>sys.stderr 'nTime Elapsed: %s' % (self.stopTime-self.startTime)  # PY3的print需处理
          print('nTime Elapsed: %s' % (self.stopTime-self.startTime), file=sys.stderr)
          return result
...
        # PY3这里不用decode了,直接处理
        # if isinstance(o,str):
        #             # TODO: some problem with 'string_escape': it escape n and mess up formating
        #             # uo = unicode(o.encode('string_escape'))
        #             # uo = o.decode('latin-1')
        #             uo = o.decode('utf-8')
        #         else:
        #             uo = o
        #         if isinstance(e,str):
        #             # TODO: some problem with 'string_escape': it escape n and mess up formating
        #             # ue = unicode(e.encode('string_escape'))
        #             # ue = e.decode('latin-1')
        #             ue = e.decode('utf-8')
        #         else:
        #             ue = e

                script = self.REPORT_TEST_OUTPUT_TMPL % dict(
                    id = tid,
                    # output = saxutils.escape(uo ue),
                    output = saxutils.escape(o e),
                )
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

如上代码列出半数以上重大校勘。博主在GitHub上上传了该文件,如今仅是总结做了点改良,未有经过正规的测试,之后大概会进展更加多更动,感兴趣的可以star下来,恐怕本身尤其改正。

style="">传送门

您也融洽编辑本身的Report Runner,并不很复杂。

将其位于utils目录中,然后我们再次改过test_baidu:

import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from utils.config import Config, DRIVER_PATH, DATA_PATH, REPORT_PATH
from utils.log import logger
from utils.file_reader import ExcelReader
from utils.HTMLTestRunner import HTMLTestRunner


class TestBaiDu(unittest.TestCase):
    URL = Config().get('URL')
    excel = DATA_PATH   '/baidu.xlsx'

    locator_kw = (By.ID, 'kw')
    locator_su = (By.ID, 'su')
    locator_result = (By.XPATH, '//div[contains(@class, "result")]/h3/a')

    def sub_setUp(self):
        self.driver = webdriver.Chrome(executable_path=DRIVER_PATH   'chromedriver.exe')
        self.driver.get(self.URL)

    def sub_tearDown(self):
        self.driver.quit()

    def test_search(self):
        datas = ExcelReader(self.excel).data
        for d in datas:
            with self.subTest(data=d):
                self.sub_setUp()
                self.driver.find_element(*self.locator_kw).send_keys(d['search'])
                self.driver.find_element(*self.locator_su).click()
                time.sleep(2)
                links = self.driver.find_elements(*self.locator_result)
                for link in links:
                    logger.info(link.text)
                self.sub_tearDown()


if __name__ == '__main__':
    report = REPORT_PATH   '\report.html'
    with open(report, 'wb') as f:
        runner = HTMLTestRunner(f, verbosity=2, title='从0搭建测试框架 灰蓝', description='修改html报告')
        runner.run(TestBaiDu('test_search'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

推行后,能够在report目录下观看有 report.html 文件,大家早已成形测量检验报告了。

我们早原来就有了日记、有了报告,生成报告之后要求给其余组员看,自然要有发邮件的意义。那块大家要用到smtplib和email库。

在utils中创立mail.py,最先化时传出全体所需数据,message是本文,可不填,path可以传list也许str;receiver帮衬五人,用”;”隔离就能够

"""
邮件类。用来给指定用户发送邮件。可指定多个收件人,可带附件。
"""
import re
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from socket import gaierror, error
from utils.log import logger


class Email:
    def __init__(self, server, sender, password, receiver, title, message=None, path=None):
        """初始化Email

        :param title: 邮件标题,必填。
        :param message: 邮件正文,非必填。
        :param path: 附件路径,可传入list(多附件)或str(单个附件),非必填。
        :param server: smtp服务器,必填。
        :param sender: 发件人,必填。
        :param password: 发件人密码,必填。
        :param receiver: 收件人,多收件人用“;”隔开,必填。
        """
        self.title = title
        self.message = message
        self.files = path

        self.msg = MIMEMultipart('related')

        self.server = server
        self.sender = sender
        self.receiver = receiver
        self.password = password

    def _attach_file(self, att_file):
        """将单个文件添加到附件列表中"""
        att = MIMEText(open('%s' % att_file, 'rb').read(), 'plain', 'utf-8')
        att["Content-Type"] = 'application/octet-stream'
        file_name = re.split(r'[\|/]', att_file)
        att["Content-Disposition"] = 'attachment; filename="%s"' % file_name[-1]
        self.msg.attach(att)
        logger.info('attach file {}'.format(att_file))

    def send(self):
        self.msg['Subject'] = self.title
        self.msg['From'] = self.sender
        self.msg['To'] = self.receiver

        # 邮件正文
        if self.message:
            self.msg.attach(MIMEText(self.message))

        # 添加附件,支持多个附件(传入list),或者单个附件(传入str)
        if self.files:
            if isinstance(self.files, list):
                for f in self.files:
                    self._attach_file(f)
            elif isinstance(self.files, str):
                self._attach_file(self.files)

        # 连接服务器并发送
        try:
            smtp_server = smtplib.SMTP(self.server)  # 连接sever
        except (gaierror and error) as e:
            logger.exception('发送邮件失败,无法连接到SMTP服务器,检查网络以及SMTP服务器. %s', e)
        else:
            try:
                smtp_server.login(self.sender, self.password)  # 登录
            except smtplib.SMTPAuthenticationError as e:
                logger.exception('用户名密码验证失败!%s', e)
            else:
                smtp_server.sendmail(self.sender, self.receiver.split(';'), self.msg.as_string())  # 发送邮件
            finally:
                smtp_server.quit()  # 断开连接
                logger.info('发送邮件"{0}"成功! 收件人:{1}。如果没有收到邮件,请检查垃圾箱,'
                            '同时检查收件人地址是否正确'.format(self.title, self.receiver))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

日后我们改正用例文件,实施到位后发送邮件:

import time
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from utils.config import Config, DRIVER_PATH, DATA_PATH, REPORT_PATH
from utils.log import logger
from utils.file_reader import ExcelReader
from utils.HTMLTestRunner import HTMLTestRunner
from utils.mail import Email


class TestBaiDu(unittest.TestCase):
    URL = Config().get('URL')
    excel = DATA_PATH   '/baidu.xlsx'

    locator_kw = (By.ID, 'kw')
    locator_su = (By.ID, 'su')
    locator_result = (By.XPATH, '//div[contains(@class, "result")]/h3/a')

    def sub_setUp(self):
        self.driver = webdriver.Chrome(executable_path=DRIVER_PATH   'chromedriver.exe')
        self.driver.get(self.URL)

    def sub_tearDown(self):
        self.driver.quit()

    def test_search(self):
        datas = ExcelReader(self.excel).data
        for d in datas:
            with self.subTest(data=d):
                self.sub_setUp()
                self.driver.find_element(*self.locator_kw).send_keys(d['search'])
                self.driver.find_element(*self.locator_su).click()
                time.sleep(2)
                links = self.driver.find_elements(*self.locator_result)
                for link in links:
                    logger.info(link.text)
                self.sub_tearDown()


if __name__ == '__main__':
    report = REPORT_PATH   '\report.html'
    with open(report, 'wb') as f:
        runner = HTMLTestRunner(f, verbosity=2, title='从0搭建测试框架 灰蓝', description='修改html报告')
        runner.run(TestBaiDu('test_search'))
    e = Email(title='百度搜索测试报告',
              message='这是今天的测试报告,请查收!',
              receiver='...',
              server='...',
              sender='...',
              password='...',
              path=report
              )
    e.send()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

实践到位现在能够看来receiver收到了大家的告知。当然,在此块你有希望遇到重重难题,可以根据错误号去英特网查询最近日头条援救。通常常有二种多如牛毛的谬误:

  1. 账户密码出错
  2. 服务器sever出错,这么些能够依据你的出殡和安葬人的邮箱去网址或邮箱设置中查见到
  3. 邮箱未有开通smtp服务,日常在邮箱设置中
  4. 邮件被阻挡,在title、message甚至发送的文件中不用带鲜明乱码、广告趋向的字符
  5. sender跟loginuser不意气风发致的主题素材,发赠与外人必得是登陆客户

本着UI自动化,接下去大家用PO思想进行下封装。

对于不一样的项目,区别的页面,大家都亟需选取浏览器、展开网站等,大家能够把那一个操作抽象出来,让分歧的用例去调用,只须要传入区别参数即可,不用叁遍遍复制粘贴。

为此,我们对test目录再一次开展分层,创制page、common、case、suite八个目录:

test
    |--case(用例文件)
    |--common(跟项目、页面无关的封装)
    |--page(页面)
    |--suite(测试套件,用来组织用例)

大家首先想要封装的筛选浏览器、展开网站的类,所以放到common中,创设browser.py:

import time
import os
from selenium import webdriver
from utils.config import DRIVER_PATH, REPORT_PATH

# 可根据需要自行扩展
CHROMEDRIVER_PATH = DRIVER_PATH   'chromedriver.exe'
IEDRIVER_PATH = DRIVER_PATH   'IEDriverServer.exe'
PHANTOMJSDRIVER_PATH = DRIVER_PATH   'phantomjs.exe'

TYPES = {'firefox': webdriver.Firefox, 'chrome': webdriver.Chrome, 'ie': webdriver.Ie, 'phantomjs': webdriver.PhantomJS}
EXECUTABLE_PATH = {'firefox': 'wires', 'chrome': CHROMEDRIVER_PATH, 'ie': IEDRIVER_PATH, 'phantomjs': PHANTOMJSDRIVER_PATH}


class UnSupportBrowserTypeError(Exception):
    pass


class Browser(object):
    def __init__(self, browser_type='firefox'):
        self._type = browser_type.lower()
        if self._type in TYPES:
            self.browser = TYPES[self._type]
        else:
            raise UnSupportBrowserTypeError('仅支持%s!' % ', '.join(TYPES.keys()))
        self.driver = None

    def get(self, url, maximize_window=True, implicitly_wait=30):
        self.driver = self.browser(executable_path=EXECUTABLE_PATH[self._type])
        self.driver.get(url)
        if maximize_window:
            self.driver.maximize_window()
        self.driver.implicitly_wait(implicitly_wait)
        return self

    def save_screen_shot(self, name='screen_shot'):
        day = time.strftime('%Y%m%d', time.localtime(time.time()))
        screenshot_path = REPORT_PATH   'screenshot_%s' % day
        if not os.path.exists(screenshot_path):
            os.makedirs(screenshot_path)

        tm = time.strftime('%H%M%S', time.localtime(time.time()))
        screenshot = self.driver.save_screenshot(screenshot_path   '\%s_%s.png' % (name, tm))
        return screenshot

    def close(self):
        self.driver.close()

    def quit(self):
        self.driver.quit()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

此间做了极度轻易的卷入,能够依照传入的参数采用浏览器的driver去开发对应的浏览器,何况加了八个封存截图的主意,能够保存png截图到report目录下。

咱俩再封装叁个页面类Page:

from test.common.browser import Browser


class Page(Browser):
    # 更多的封装请自己动手...
    def __init__(self, page=None, browser_type='firefox'):
        if page:
            self.driver = page.driver
        else:
            super(Page, self).__init__(browser_type=browser_type)

    def get_driver(self):
        return self.driver

    def find_element(self, *args):
        return self.driver.find_element(*args)

    def find_elements(self, *args):
        return self.driver.find_elements(*args)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

咱俩仅仅封装了多少个措施,越多的包裹还请读者本身入手,接下去大家须求对页面进行李包裹装,在page目录创造如下多少个文件:

baidu_main_page.py:

from selenium.webdriver.common.by import By
from test.common.page import Page


class BaiDuMainPage(Page):
    loc_search_input = (By.ID, 'kw')
    loc_search_button = (By.ID, 'su')

    def search(self, kw):
        """搜索功能"""
        self.find_element(*self.loc_search_input).send_keys(kw)
        self.find_element(*self.loc_search_button).click()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

baidu_result_page.py:

from selenium.webdriver.common.by import By
from test.page.baidu_main_page import BaiDuMainPage


class BaiDuResultPage(BaiDuMainPage):
    loc_result_links = (By.XPATH, '//div[contains(@class, "result")]/h3/a')

    @property
    def result_links(self):
        return self.find_elements(*self.loc_result_links)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

一个是包裹的百度首页,八个包裹百度结果页,那样,大家的测试用例就足以改为:

import time
import unittest
from utils.config import Config, DATA_PATH, REPORT_PATH
from utils.log import logger
from utils.file_reader import ExcelReader
from utils.HTMLTestRunner import HTMLTestRunner
from utils.mail import Email
from test.page.baidu_result_page import BaiDuMainPage, BaiDuResultPage


class TestBaiDu(unittest.TestCase):
    URL = Config().get('URL')
    excel = DATA_PATH   '/baidu.xlsx'

    def sub_setUp(self):
        # 初始页面是main page,传入浏览器类型打开浏览器
        self.page = BaiDuMainPage(browser_type='chrome').get(self.URL, maximize_window=False)

    def sub_tearDown(self):
        self.page.quit()

    def test_search(self):
        datas = ExcelReader(self.excel).data
        for d in datas:
            with self.subTest(data=d):
                self.sub_setUp()
                self.page.search(d['search'])
                time.sleep(2)
                self.page = BaiDuResultPage(self.page)  # 页面跳转到result page
                links = self.page.result_links
                for link in links:
                    logger.info(link.text)
                self.sub_tearDown()


if __name__ == '__main__':
    report = REPORT_PATH   '\report.html'
    with open(report, 'wb') as f:
        runner = HTMLTestRunner(f, verbosity=2, title='从0搭建测试框架 灰蓝', description='修改html报告')
        runner.run(TestBaiDu('test_search'))
    e = Email(title='百度搜索测试报告',
              message='这是今天的测试报告,请查收!',
              receiver='...',
              server='...',
              sender='...',
              password='...',
              path=report
              )
    e.send()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

近日,大家曾经用PO把用例改写了,这其间还会有众多难点,浏览器的安装、基本功page的包裹、log太少、未有做丰硕管理等等,这么些相信您都足以稳步完备的。

前方大家都以用的UI自动化的用例来兑现的,借使我们想做接口框架如何做?今日就扩张学一年级下接口测试模块,这里大家须要用到requests库(接口是HTTP类型的,别的连串也可能有关照的库卡塔 尔(英语:State of Qatar)

咱俩先在ReadMe.md中补上新加的依赖库。然后在utils中开创一个client.py的文件,在内部创设三个HTTPClient类:

"""
添加用于接口测试的client,对于HTTP接口添加HTTPClient,发送http请求。
还可以封装TCPClient,用来进行tcp链接,测试socket接口等等。
"""

import requests
from utils.log import logger

METHODS = ['GET', 'POST', 'HEAD', 'TRACE', 'PUT', 'DELETE', 'OPTIONS', 'CONNECT']


class UnSupportMethodException(Exception):
    """当传入的method的参数不是支持的类型时抛出此异常。"""
    pass


class HTTPClient(object):
    """
    http请求的client。初始化时传入url、method等,可以添加headers和cookies,但没有auth、proxy。

    >>> HTTPClient('http://www.baidu.com').send()
    <Response [200]>

    """
    def __init__(self, url, method='GET', headers=None, cookies=None):
        """headers: 字典。 例:headers={'Content_Type':'text/html'},cookies也是字典。"""
        self.url = url
        self.session = requests.session()
        self.method = method.upper()
        if self.method not in METHODS:
            raise UnSupportMethodException('不支持的method:{0},请检查传入参数!'.format(self.method))

        self.set_headers(headers)
        self.set_cookies(cookies)

    def set_headers(self, headers):
        if headers:
            self.session.headers.update(headers)

    def set_cookies(self, cookies):
        if cookies:
            self.session.cookies.update(cookies)

    def send(self, params=None, data=None, **kwargs):
        response = self.session.request(method=self.method, url=self.url, params=params, data=data, **kwargs)
        response.encoding = 'utf-8'
        logger.debug('{0} {1}'.format(self.method, self.url))
        logger.debug('请求成功: {0}n{1}'.format(response, response.text))
        return response
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

接下去写个用例,但是我们接口的用例跟UI混在风姿洒脱道延续不好,所以大家得以在test下开创八个interface的目录,里面创设test_baidu_http.py的用例文件。

此处您也能够在test下分成API和UI两层,分别在里面再拓展分层,看状态而定吧。

test_baidu_http.py:

import unittest
from utils.config import Config, REPORT_PATH
from utils.client import HTTPClient
from utils.log import logger
from utils.HTMLTestRunner import HTMLTestRunner


class TestBaiDuHTTP(unittest.TestCase):
    URL = Config().get('URL')

    def setUp(self):
        self.client = HTTPClient(url=self.URL, method='GET')

    def test_baidu_http(self):
        res = self.client.send()
        logger.debug(res.text)
        self.assertIn('百度一下,你就知道', res.text)


if __name__ == '__main__':
    report = REPORT_PATH   '\report.html'
    with open(report, 'wb') as f:
        runner = HTMLTestRunner(f, verbosity=2, title='从0搭建测试框架 灰蓝', description='接口html报告')
        runner.run(TestBaiDuHTTP('test_baidu_http'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

此处我们加了一句断言,未有断言怎么能叫用例,大家事先写的UI用例,也得以友善出手加上断言。

现在我们的框架不仅可以够做UI测量试验,也能做接口测验了。假若您的接口类型不是HTTP的,请自身包裹对应的Client类。socket库测TCP接口、suds库测SOAP接口,无论你是何许项指标接口,总能找到呼应的Python库的。

上次咱们的用例中扩大了断言。断言(检查点卡塔尔这一个事物对测试来说很首要。不然你怎么领会贰个测验结果是对是错吗。unittest为大家提供了比超级多很好的预见,可是对于我们的档案的次序恐怕是非常不足的。大家供给封装自己的预知方法。

此地大家大致包装三个预见,在utils中成立assertion.py文件,在里边创立断言:

"""
在这里添加各种自定义的断言,断言失败抛出AssertionError就OK。
"""


def assertHTTPCode(response, code_list=[200]):
    res_code = response.status_code
    if res_code not in code_list:
        raise AssertionError('响应code不在列表中!')  # 抛出AssertionError,unittest会自动判别为用例Failure,不是Error
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

本条断言传入响应,以至愿意的响应码列表,借使响应码不在列表中,则断言失败。

在test_baidu_http.py中加多此断言:

import unittest
from utils.config import Config, REPORT_PATH
from utils.client import HTTPClient
from utils.log import logger
from utils.HTMLTestRunner import HTMLTestRunner
from utils.assertion import assertHTTPCode


class TestBaiDuHTTP(unittest.TestCase):
    URL = Config().get('URL')

    def setUp(self):
        self.client = HTTPClient(url=self.URL, method='GET')

    def test_baidu_http(self):
        res = self.client.send()
        logger.debug(res.text)
        assertHTTPCode(res, [400])
        self.assertIn('百度一下,你就知道', res.text)


if __name__ == '__main__':
    report = REPORT_PATH   '\report.html'
    with open(report, 'wb') as f:
        runner = HTMLTestRunner(f, verbosity=2, title='从0搭建测试框架 灰蓝', description='接口html报告')
        runner.run(TestBaiDuHTTP('test_baidu_http'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

大家增添断言,响应码在[400]中,实施会开掘fail掉了。

在assertion.py中你能够增加更加多更丰盛的预感,响应断言、日志断言、数据库预感等等,请自行封装。

对接口测试来讲,比很多时候,大家的用例不是三次号令就OK了的,而是四个要求复合的,大家第二个乞求或许会用到第多少个须要重临值中的数据,那就要我们再度开展包装,做三个收取器,从结果中抽出部分新闻。 
那边大家会用到JMESPath库,那是二个让大家经过形似于xpath或点分法来定位json中的节点的库

别忘了大家先在ReadMe.md中添加上重视的库。

咱俩在utils中创造extractor.py文件,实现对响应中数量的抽出

"""抽取器,从响应结果中抽取部分数据"""

import json
import jmespath


class JMESPathExtractor(object):
    """
    用JMESPath实现的抽取器,对于json格式数据实现简单方式的抽取。
    """
    def extract(self, query=None, body=None):
        try:
            return jmespath.search(query, json.loads(body))
        except Exception as e:
            raise ValueError("Invalid query: "   query   " : "   str(e))


if __name__ == '__main__':
    from utils.client import HTTPClient
    res = HTTPClient(url='http://wthrcdn.etouch.cn/weather_mini?citykey=101010100').send()
    print(res.text)
    # {"data": {
    #     "yesterday": {"date": "17日星期四", "high": "高温 31℃", "fx": "东南风", "low": "低温 22℃", "fl": "<![CDATA[<3级]]>",
    #                   "type": "多云"},
    #     "city": "北京",
    #     "aqi": "91",
    #     "forecast": [
    #         {"date": "18日星期五", "high": "高温 28℃", "fengli": "<![CDATA[<3级]]>", "low": "低温 22℃", "fengxiang": "东北风",
    #          "type": "多云"},
    #         {"date": "19日星期六", "high": "高温 29℃", "fengli": "<![CDATA[<3级]]>", "low": "低温 22℃", "fengxiang": "东风",
    #          "type": "雷阵雨"},
    #         {"date": "20日星期天", "high": "高温 29℃", "fengli": "<![CDATA[<3级]]>", "low": "低温 23℃", "fengxiang": "东南风",
    #          "type": "阴"},
    #         {"date": "21日星期一", "high": "高温 30℃", "fengli": "<![CDATA[<3级]]>", "low": "低温 24℃", "fengxiang": "西南风",
    #          "type": "晴"},
    #         {"date": "22日星期二", "high": "高温 29℃", "fengli": "<![CDATA[<3级]]>", "low": "低温 24℃", "fengxiang": "北风",
    #          "type": "雷阵雨"}
    #     ],
    #     "ganmao": "各项气象条件适宜,无明显降温过程,发生感冒机率较低。", "wendu": "25"
    #  },
    # "status": 1000,
    # "desc": "OK"}

    j = JMESPathExtractor()
    j_1 = j.extract(query='data.forecast[1].date', body=res.text)
    j_2 = j.extract(query='data.ganmao', body=res.text)
    print(j_1, j_2)
    # 结果:
    # 19日星期六 各项气象条件适宜,无明显降温过程,发生感冒机率较低。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

像这种类型大家就果熟蒂落了对JSON格式的抽出器,若是回到结果是JSON串,我们能够透过那个抽出器找到大家想要的数码,再拓宽下一步的操作,大概用来做断言。

这里独有完毕了对JSON格式响应的抽出,之后读者能够友善加多XML格式、普通字符串格式、Header的抽取器,稳步展开完美。

不经常接口或UI上流传的数量要求相符钦命的格式,大家在参数化的长河中又不愿意在excel中二次遍去组织那样的数码,这个时候大家能够步向生成器来为大家发出相符有些固定格式的多少。 
那边我引入叁个挺风趣的库,Faker,可以为你发出种种假数据

别忘了在ReadMe.md中添上您要用的库。

在utils中成立二个generator.py,用来生成多少

"""一些生成器方法,生成随机数,手机号,以及连续数字等"""
import random
from faker import Factory

fake = Factory().create('zh_CN')


def random_phone_number():
    """随机手机号"""
    return fake.phone_number()


def random_name():
    """随机姓名"""
    return fake.name()


def random_address():
    """随机地址"""
    return fake.address()


def random_email():
    """随机email"""
    return fake.email()


def random_ipv4():
    """随机IPV4地址"""
    return fake.ipv4()


def random_str(min_chars=0, max_chars=8):
    """长度在最大值与最小值之间的随机字符串"""
    return fake.pystr(min_chars=min_chars, max_chars=max_chars)


def factory_generate_ids(starting_id=1, increment=1):
    """ 返回一个生成器函数,调用这个函数产生生成器,从starting_id开始,步长为increment。 """
    def generate_started_ids():
        val = starting_id
        local_increment = increment
        while True:
            yield val
            val  = local_increment
    return generate_started_ids


def factory_choice_generator(values):
    """ 返回一个生成器函数,调用这个函数产生生成器,从给定的list中随机取一项。 """
    def choice_generator():
        my_list = list(values)
        rand = random.Random()
        while True:
            yield random.choice(my_list)
    return choice_generator


if __name__ == '__main__':
    print(random_phone_number())
    print(random_name())
    print(random_address())
    print(random_email())
    print(random_ipv4())
    print(random_str(min_chars=6, max_chars=8))
    id_gen = factory_generate_ids(starting_id=0, increment=2)()
    for i in range(5):
        print(next(id_gen))

    choices = ['John', 'Sam', 'Lily', 'Rose']
    choice_gen = factory_choice_generator(choices)()
    for i in range(5):
        print(next(choice_gen))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

您还足以加上五花八门标生成器,比方钦点长度普通话、德文、特殊字符的字符串,钦命格式的json串等等,能够节省超多结构测试多少的忧愁。

框架到此地早就很科学了,前边就要求各位自个儿去康健了。比方不时须求需求加密、签名,还也许有生龙活虎部分扶植措施,能够在utils中建个support.py放进去。

在utils中创设二个support.py文件,里面能够放要求的风姿洒脱对协理艺术,大家演示一个加密和签订公约的方法:

"""一些支持方法,比如加密"""
import hashlib
from utils.log import logger


class EncryptError(Exception):
    pass


def sign(sign_dict, private_key=None, encrypt_way='MD5'):
    """传入待签名的字典,返回签名后字符串
    1.字典排序
    2.拼接,用&连接,最后拼接上私钥
    3.MD5加密"""
    dict_keys = sign_dict.keys()
    dict_keys.sort()

    string = ''
    for key in dict_keys:
        if sign_dict[key] is None:
            pass
        else:
            string  = '{0}={1}&'.format(key, sign_dict[key])
    string = string[0:len(string) - 1]
    string = string.replace(' ', '')

    return encrypt(string, salt=private_key, encrypt_way=encrypt_way)


def encrypt(string, salt='', encrypt_way='MD5'):
    u"""根据输入的string与加密盐,按照encrypt方式进行加密,并返回加密后的字符串"""
    string  = salt
    if encrypt_way.upper() == 'MD5':
        hash_string = hashlib.md5()
    elif encrypt_way.upper() == 'SHA1':
        hash_string = hashlib.sha1()
    else:
        logger.exception(EncryptError('请输入正确的加密方式,目前仅支持 MD5 或 SHA1'))
        return False

    hash_string.update(string.encode())
    return hash_string.hexdigest()

if __name__ == '__main__':
    print(encrypt('100000307111111'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 数据报表自动化深入分析,selenium的第三方广告检查实验。18
  • 19
  • 数据报表自动化深入分析,selenium的第三方广告检查实验。20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

基于你实际景况的不等,在里面增添此外扶植办法。

就写这么多了,你能够根据这些思路补充扩张,来促成您本人的测试框架,也能够友善调度框架的分段与构造,框架的指标是为着简化大家用例编写和维护的专门的学业量,也没必要把框架搞的太过复杂。 
不无的代码小编都放到了GITHUB上传送,能够团结下载去上学,有啥好的提出依旧难点,能够留言或许加笔者的QQ群:455478219讨论。

用webdriver运行浏览器登入腾讯网

webdriver的施用其实非常轻巧。能够那样汇报:
1、用驱动器运维浏览器并张开叁个总是
2、根据页面html源码的协会找到钦命的要素(按键、文本框等卡塔 尔(英语:State of Qatar)
3、对指标成分接收目的动作(点击、输入等卡塔 尔(英语:State of Qatar)

使用webdriver需求下载selenium模块浏览器驱动
1、下载安装selenium模块,命令行:

pip install selenium

2、博主用的是chrome浏览器,所以本篇以其对应的驱动chromedriver.exe为例,百度大概google就足以找到下载链接,下载好刺探压到率性路线就能够,代码中内定该路径。

3、应当要保管selenium模块、浏览器驱动、浏览器都是流行版本,以防发生不供给的bug。平日pip指令安装的都以风靡版本的模块。

搞活以上筹划后来,就足以在代码里引进webdriver了,我们先用登陆来打个样儿。代码要做的正是驱动运行浏览器后,get今日头条的主页,用driver的种种find_element方法找到账号和密码输入框,键入账号密码实行登入,临时大概需求表明。以下展现的是账号输入框之处与品质:

图3.账号输入框地点

webdriver的着力使用:
1、可以依照class和id来找到成分,也足以用xpath语法和css选择器来找到成分

driver.find_element_by_id('id')
driver.find_element_by_class_name('classname')
driver.find_element_by_css_selector('input[type="password"]')
driver.find_element_by_xpath('//div[@node-type="textElDiv"]/textarea[@class="W_input"]')

2、用element.click点击成分,用element.send_keys向文本框键入文字,别的动作能够用ActionChains,参照他事他说加以考察selenium之 玩转鼠标键盘操作(ActionChains卡塔尔。
3、详细表明可参照Python爬虫利器五之Selenium的用法,更加的多用法参考互连网教程和文书档案。

报到代码:

driver = webdriver.Chrome(executable_path='../drivers/chromedriver.exe')# chrome浏览器驱动
url='http://weibo.com/'
driver.get(url)# get打开微博主页

input_account=driver.find_element_by_id('loginname')# 找到账号输入框
input_psw=driver.find_element_by_css_selector('input[type="password"]')# 找到密码输入框

#输入账号密码并登录
input_account.send_keys('account')
input_psw.send_keys('password')

bt_logoin=driver.find_element_by_class_name('login_btn')# 找到登录按钮
bt_logoin.click()# 点击登录

唯独上述代码在网络状态倒霉的时候会发出找不到成分的bug,那首倘诺因为页面还平素不加载完结形成的。
相应将find账号输入框的代码改进为:

# 参数10为超时时间,即最大等待时间为10秒,关于lambda就自行百度吧
bt_logoin=WebDriverWait(driver,10).until(lambda x:x.find_element_by_id('loginname'))

关于等待页面加载的别样格局的具体介绍,可以参照Python selenium 两种等待方式精解和WebDriverWait等设置等待时间和过期时间这两篇。

并发验证码的景况:
在点击了登陆按键之后,有的时候会产出验证码。对于这种处境,我们只需求步向多少个论断,尽管点击登入前边世了验证码输入框,就推断供给输入验证码,大家在调节台手动输入并send_keys到验证码输入框就可以。(验证码自动破解相比复杂,不建议在入门阶段探究卡塔尔国

管理验证码的代码:

# 根据验证框的存在与否判断是否要输入验证码
def isVerifyCodeExist(self):
    try:# 如果成功找到验证码输入框返回true
        self.driver.find_element_by_css_selector('input[name="verifycode"]')
        return True
    except:# 如果异常返回false
        return False

# 输入验证码部分,如果无需输入则直接返回,否则手动输入成功后返回        
def inputVerifyCode(self):
    input_verifycode=self.driver.find_element_by_css_selector('input[name="verifycode"]')# 验证码输入框
    bt_change=self.driver.find_element_by_css_selector('img[action-type="btn_change_verifycode"]')# 验证码图片,点击切换
    bt_logoin=self.driver.find_element_by_class_name('login_btn')# 登录按钮
    while self.isVerifyCodeExist():# 如果验证码输入框一直存在,则一直循环
        print u'请输入验证码……(输入"c"切换验证码图片)'
        verifycode=raw_input()
        if verifycode=='c':
            bt_change.click()
        else:
            input_verifycode.send_keys(verifycode)
            bt_logoin.click()
            # 点击完登录以后判断是否成功
            if self.driver.current_url.split('/')[-1]=='home':# 如果连接已经跳转到home
                print u'登录成功'
                break
            else:
                print u'输入的验证码不正确'

在前头的记名代码末尾调用inputVerifyCode方法就能够。

3.安装spreadsheet:

gem install spreadsheet

spreadsheet的GitHub源码地址

澳门新萄京官方网站 4

用webdriver公布带图片的天涯论坛

如若仅发布文字内容的博客园,比较简单,思路与以上同理,先找到文本框成分,用send_keys输入内容,找到'公布'开关,点击按键就可以颁发。

# 上传文字
def upload_txt(self,text):
    # 用xpath语法找到输入框
    input_w=self.driver.find_element_by_xpath('//div[@node-type="textElDiv"]/textarea[@class="W_input"]')
    input_w.send_keys(text)
# 发布
def send(self):
    # 找到发布按钮并点击
    self.driver.find_element_by_class_name('W_btn_a').click()

而对于亟待公布图片的博文,大家还亟需点击图片->点击单图/多图。接着大家能够开掘指标对象不是input型的文书上传开关,input型的文书上传大家能够用send_keys直接键入文件地方,方便快捷。可是和讯这些文件上传是object型的,那不得不依赖第三方工具autoIT来对os弹窗举办一波骚操作了。

图4.图形上传按键

从上海体育场合看,能够窥见那几个object的id满含'swf_upbtn'那样四个字段,之后很刚烈是二个每一天大概变动的数字串,所以我们得以用xpath的contains函数来找到它,点击那么些开关之后会弹出上传文书的窗口,那一个窗口就不是selenium能调整的了,要求编写autoIT脚本来调控文件的上传操作,再在python代码中通过os模块调用那么些本子。

autoIT的装置和利用
参考selenium2 python自动化测验之利用AutoIt工具达成地方文件上传和 selenium借用AutoIt 完毕上传文件这两篇。

小编的autoIT脚本代码:

WinWait("打开","",10000);
ControlFocus("打开", "", "Edit1");
ControlSetText("打开" ,"", "Edit1", $CmdLine[1]);
Sleep(1000)
ControlClick("打开", "","Button1");

上述代码实行的操作是:
1、等待文件上传窗口的现身,最多等待10s(因为chrome浏览器的文件上传窗口标题是"展开",第叁个参数是窗口标题卡塔 尔(阿拉伯语:قطر‎
2、将光标聚集于文件地方编辑框
3、在编辑框里键入参数(约等于大家随后会传播的地点卡塔尔国
4、点击"打开"按钮
详见用法和表达请参阅以上两篇。

$CmdLine[1]能够读取到命令行的首先个参数,通过这些参数大家就足以把公文地方传入。关于参数的表明和此外的完结公文上传的不二秘诀参照他事他说加以考查Python Selenium —— 文件上传、下载,其实很简短。

上传文字和图片的主意封装如下:

# 上传文字
def upload_txt(self,text):
    input_w=self.driver.find_element_by_xpath('//div[@node-type="textElDiv"]/textarea[@class="W_input"]')
    input_w.send_keys(text)
    sleep(1)

#运行上传图片脚步
def upload_img_script(self,time_bef,time_after,path):# path参数需要前后带双引号
    sleep(time_bef)# 等待弹窗时间
    os.system('C:/Users/15850/Documents/GitHub/MyWorkspace/py_study/script/upload.exe ' path)
    sleep(time_after)# 等待图片加载时间

# 上传文字和单图
def upload_txt_img(self,text,img_path):
    self.upload_txt(text)# 将文字上传
    img=self.driver.find_element_by_css_selector('a[action-type="multiimage"]')# 图片按钮
    img.click()# 点击图片按钮
    sleep(1)# 等待加载其他按钮

    #单图/多图按钮,即上传图片按钮
    bt_uploadimg=WebDriverWait(self.driver,10).until(lambda x:x.find_element_by_xpath('//object[contains(@id,"swf_upbtn")]'))
    bt_uploadimg.click()# 点击上传按钮

    self.upload_img_script(1,2,img_path)

# 上传文字和多图    
def upload_txt_multiImg(self,text,img_path_list):
    self.upload_txt_img(text,img_path_list[0])# 将文字和第一张图片上传

    len_imgs=len(img_path_list)# 图片地址list的长度    
    bt_uploadimg=WebDriverWait(self.driver,10).until(lambda x:x.find_element_by_xpath('//li[@node-type="uploadBtn"]/div/object[contains(@id,"swf_upbtn")]'))
    for i in range(len_imgs-1):# 将剩余图片上传 
        bt_uploadimg.click()
        self.upload_img_script(1, 2,img_path_list[i 1])

里面那意气风发行就是调用了编写翻译成exe文件的上传文件的步子,参数字符串先指明脚本路径,空风流倜傥格加上path那个参数。

os.system('C:/Users/15850/Documents/GitHub/MyWorkspace/py_study/script/upload.exe ' path)

注意path传入的字符串必得带双引号,字符串本人也亟需单引号包罗,且分隔符必得为"",如下:

'"C:\Users\15850\Documents\GitHub\MyWorkspace\py_study\img\1.jpg"'

4.安装selenium浏览器驱动driver

  • Chrome
    • 本子对应:ChromeDriver与Chrome版本的关照关系
    • driver下载:ChromeDriver - WebDriver for Chrome
  • Firefox
    • driver下载及版本对应:https://github.com/mozilla/geckodriver/releases

根据自个儿的浏览器版本,接受相应的selenium浏览器驱动版本driver实行下载解压,将下载解压好的driver文件移动到/usr/bin/文件夹下就能够。

上述四步,是linux下运作程序要求的条件布置,必需保管每一步的不易安装。

image.png

完全代码

(源码已上传github:python爬虫入门实战)
1、主要操作步骤写在weibo_transport模块中
2、引入crawl_weibo模块用于爬取原腾讯网数据
3、引入upload_driver模块用于将数据公布到新账号上
4、3个模块分别位居github项目中的crawl与weibo文件夹下

weibo_transport模块

# -*- coding:utf-8 -*-
'''
Created on 2017年6月25日

@author: wycheng
'''
from crawl import crawl_weibo
import upload_driver
from lxml import html
import requests

def getContent(card):# 获取该card下微博的内容
    mblog=card['mblog']
    count_img=0# 每条微博重新计数图片数,用于发送图片的地址

    text= html.fromstring(mblog['text'])
    text=text.xpath('string(.)')#过滤正文中的多余标签

    url_img=''
    if 'pics' in mblog:#有图片的存储图片
        pics=mblog['pics']
        for pic in pics:
            url_img=pic['large']['url']
            ir = requests.get(url_img)
            if ir.status_code == 200:# 如果请求已成功
                count_img =1# 给图片计数
                open('../img/' str(count_img) '.jpg', 'wb').write(ir.content)# 保存在img文件夹下,发送也从这个文件夹下找
            print u'图片:' url_img

    scheme=card['scheme']
    created_at=mblog['created_at']
    source=mblog['source']
    reposts_count=mblog['reposts_count']
    comments_count=mblog['comments_count']
    attitudes_count=mblog['attitudes_count']

    return text,count_img,scheme,created_at,source,reposts_count,comments_count,attitudes_count# 其实返回的是一个list

#登录
uploader=upload_driver.Uploader()
uploader.login('account', 'password')# 填写你的账号密码

crawl_weibo=crawl_weibo.CrawlWeibo()
# 先爬取第34页进行发布,作为范例
# 这里的页码不是微博客户端上的页码,这个接口返回的一页只有10个card
# 博主原微博有370 条微博,所以一共有38页
cards=crawl_weibo.getWeibo('2622535523',34)# 第一个参数是用户id,第二个是页数
len_cards=len(cards)

for j in range(len_cards):
    index=len_cards-1-j

    card=cards[index]

    # (微博的cardtype==9,实战四也有说明,转发的微博mblog里有‘retweeted_status’这个key)
    if card['card_type']==9 and not 'retweeted_status' in card['mblog']:# 如果这是一条非转发的微博的card
        # 获取这条微博的各个数据
        content_list=getContent(card)
        text,count_img,scheme,created_at,source,reposts_count,comments_count,attitudes_count=content_list

        # 发送这条微博的内容到新账号
        # 拼接要发送的文本
        text=created_at u'  来自 ' source 'n' text ' n' u'转发 ' str(reposts_count) u'  评论 ' str(comments_count) u'  点赞 ' str(attitudes_count)

        path_list=[]# 图片地址list
        for i in range(count_img):# 根据图片总数量生成所有图片地址
            path_list.append('C:\Users\15850\Documents\GitHub\MyWorkspace\py_study\img\' str(i 1) '.jpg')
        # 上传内容
        if count_img==0:# 没有图片
            uploader.upload_txt(text)
        elif count_img==1:# 单张图片
            uploader.upload_txt_img(text, path_list[0])
        else:# 多张图片
            uploader.upload_txt_multiImg(text,path_list)

        uploader.send()

upload_driver模块

# -*- coding:utf-8 -*-
'''
Created on 2017年6月25日

@author: wycheng
'''
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from time import sleep
import os

class Uploader:
    driver = webdriver.Chrome(executable_path='../drivers/chromedriver.exe')# chrome浏览器驱动
    # 根据验证框的存在与否判断是否要输入验证码
    def isVerifyCodeExist(self):
        try:# 如果成功找到验证码输入框返回true
            self.driver.find_element_by_css_selector('input[name="verifycode"]')
            return True
        except:# 如果异常返回false
            return False

    # 输入验证码部分,如果无需输入则直接返回,否则手动输入成功后返回        
    def inputVerifyCode(self):
        input_verifycode=self.driver.find_element_by_css_selector('input[name="verifycode"]')# 验证码输入框
        bt_change=self.driver.find_element_by_css_selector('img[action-type="btn_change_verifycode"]')# 验证码图片,点击切换
        bt_logoin=self.driver.find_element_by_class_name('login_btn')# 登录按钮
        while self.isVerifyCodeExist():
            print u'请输入验证码……(输入"c"切换验证码图片)'
            verifycode=raw_input()
            if verifycode=='c':
                bt_change.click()
            else:
                input_verifycode.send_keys(verifycode)
                bt_logoin.click()
                # 点击完登录以后判断是否成功
                if self.driver.current_url.split('/')[-1]=='home':
                    print u'登录成功'
                    break
                else:
                    print u'输入的验证码不正确'

    #打开微博首页进行登录的过程
    def login(self,account,password):
        self.driver.implicitly_wait(10)# 设置隐性等待时间,等待页面加载完成才会进行下一步,最多等待10秒
        url='http://weibo.com/'
        self.driver.get(url)
        #输入账号密码并登录
        WebDriverWait(self.driver,10).until(lambda x:x.find_element_by_id('loginname')).send_keys(account)
        self.driver.find_element_by_css_selector('input[type="password"]').send_keys(password)

        bt_logoin=self.driver.find_element_by_class_name('login_btn')
        bt_logoin.click()

        #如果存在验证码,则进入手动输入验证码过程
        if self.isVerifyCodeExist():
            self.inputVerifyCode()  

    # 上传文字
    def upload_txt(self,text):
        input_w=self.driver.find_element_by_xpath('//div[@node-type="textElDiv"]/textarea[@class="W_input"]')
        input_w.send_keys(text)
        sleep(1)

    #运行上传图片脚步
    def upload_img_script(self,time_bef,time_after,path):# path参数需要前后带双引号
        sleep(time_bef)# 等待弹窗时间
        os.system('C:/Users/15850/Documents/GitHub/MyWorkspace/py_study/script/upload.exe ' path)
        sleep(time_after)# 等待图片加载时间

    # 上传文字和单图
    def upload_txt_img(self,text,img_path):
        self.upload_txt(text)# 将文字上传
        img=self.driver.find_element_by_css_selector('a[action-type="multiimage"]')# 图片按钮
        img.click()# 点击图片按钮
        sleep(1)# 等待加载其他按钮

        #单图/多图按钮,即上传图片按钮
        bt_uploadimg=WebDriverWait(self.driver,10).until(lambda x:x.find_element_by_xpath('//object[contains(@id,"swf_upbtn")]'))
        bt_uploadimg.click()# 点击上传按钮

        self.upload_img_script(1,2,img_path)

    # 上传文字和多图    
    def upload_txt_multiImg(self,text,img_path_list):
        self.upload_txt_img(text,img_path_list[0])# 将文字和第一张图片上传

        len_imgs=len(img_path_list)# 图片地址list的长度    
        bt_uploadimg=WebDriverWait(self.driver,10).until(lambda x:x.find_element_by_xpath('//li[@node-type="uploadBtn"]/div/object[contains(@id,"swf_upbtn")]'))
        for i in range(len_imgs-1):# 将剩余图片上传 
            bt_uploadimg.click()
            self.upload_img_script(1, 2,img_path_list[i 1])

    # 发布
    def send(self):
        self.driver.find_element_by_class_name('W_btn_a').click()
        sleep(4)# 等待发送成功字样消失

crawl_weibo模块
参考python爬虫入门 实战(四卡塔 尔(英语:State of Qatar)---爬“榜姐”话题新浪及热门谈论末尾

Windows下情状布署

windows下的条件布署与Linux下略有例外,但思路是相似的。

PS:须求设置一下Chrome的驱动,谷歌(Google卡塔尔寻找官方网站
步骤:

成效呈现动图

功效展现动图

1.安装ruby

据守这篇小说《Ruby 安装 - Windows》安装ruby就能够,记得勾选Add Ruby executables to your PATH那黄金年代项。同样,要求ruby版本大于等于2.0。

(1卡塔 尔(阿拉伯语:قطر‎前往chromedriver 下载页面
官方网站地址:
https://sites.google.com/a/chromium.org/chromedriver/downloads
任哪儿方:
https://github.com/DaemonFG/IntrotoPython-Think-Tank/blob/master/P2/ChromeDriver_Download.md

参考

1、python爬虫入门 实战(四卡塔 尔(阿拉伯语:قطر‎---爬“榜姐”话题今日头条及抢手商议
2、selenium之 玩转鼠标键盘操作(ActionChains卡塔 尔(英语:State of Qatar)
3、Python爬虫利器五之Selenium的用法
4、Python selenium 二种等待格局精解
5、WebDriverWait等装置等待时间和过期时间
6、selenium python find_element_by_css_selector方法运用
7、selenium2 python自动化测量检验之利用AutoIt工具完结当羊眼半夏件上传
8、selenium借用AutoIt 实现上传文件

2.安装ruby版本的selenium

cmd中执行:

gem install selenium-webdriver  

selenium-webdriver的Github源码地址

(2卡塔尔将下载好的chromedriver_win32.zip解压后是二个exe文件,将其复制到Python安装目录,

3.安装spreadsheet:

gem install spreadsheet

spreadsheet的GitHub源码地址ß

澳门新萄京官方网站 5

4.安装selenium浏览器驱动driver

  • Chrome
    • 本子对应:ChromeDriver与Chrome版本的相应关系
    • driver下载:ChromeDriver - WebDriver for Chrome
  • Firefox
    • driver下载及版本对应:https://github.com/mozilla/geckodriver/releases

依照本身的浏览器版本,选取相应的selenium浏览器驱动版本driver实行下载解压,将下载解压好的driver文件放在对应的浏览器安装目录下,之后须求对Windows情形变量举行计划。
Windows下须要在系统变量的path变量中加多exe文件的岗位,配置情况变量可参照他事他说加以考察这篇随笔:Win7怎么样增添情形变量,注意路径中不用有粤语。

一直以来,那四步也是Windows下必备的情况布置。但在和谐的测量检验进度中,由于有个别安然照旧主题材料,Windows下的chrome始终未曾调通,但Firefox是足以采取的。

image.png

三.前后相继编写制定


注意事项:Chrome版本和chromedriver 接济的驱动难点

系列规划思路

  1. 为了能使脚本检查测量检验大批量网址,我们运用四个公文,二个txt文件,一个xls表格文件和富含全数逻辑功能的ruby文件。
    • weburl.txt:在文件中,种种网站占生龙活虎行,ruby文件会挨个按行读取此文件中的网站进行检查测验
    • ad_file.xls:用于保存数据,最后的数据会写入那几个文件
    • detection_ad.rb:全部的多寡逻辑管理均含有在这里个文件中,担当检验页面中的第三方广告。
  2. 其三方广告都在iframe标签中,大家的指标是找到这一个iframe标签中的src,即正是第三方广告的网站。因而大家得以将思路变化为:首先通过selenium获取网页的源代码,之后经过ruby正则表明式来落实对第生机勃勃音讯的领取。
  3. 对此selenium和spreadsheet八个gem的使用,大家不作过多解释,能够参见以下两篇文章,给出了八个gem的着力使用办法。
    • selenium对浏览器的简易操作(webdriver ruby卡塔尔国
    • rails导出excel插件 spreadsheet的正规化应用

2:然后使用浏览器门路对象调用相关API进行展开浏览器等消息进行操作
browser.get('http://www.baidu.com')

代码达成

代码内容我们分成将四片段来分别证实。

全体示例代码:

(生龙活虎卡塔 尔(英语:State of Qatar)加载库文件

require 'rubygems'  
require 'selenium-webdriver' 
require 'spreadsheet'
from selenium import webdriver

# browser  = webdriver.Firefox()
browser  = webdriver.Chrome()

browser.get('http://www.baidu.com')
print(browser.page_source)
browser.close()

(二卡塔尔伊始化部分

# 存放网址的文件
web_file = "weburl.txt"

# 创建excel表格实例
Spreadsheet.client_encoding = "UTF-8" 
excel_fil = Spreadsheet::Workbook.new  
sheet = excel_fil.create_worksheet :name => "ads_show"

# 创建浏览器driver实例
# driver = Selenium::WebDriver.for :chrome
driver = Selenium::WebDriver.for :firefox

# 创建三个全局变量
# web_num:excel表单中的行数
# all_ads_num:所有网页的广告总数
# hide_ads_num:所有网页的隐藏广告总数
$web_num = 1
$all_ads_num = 0
$hide_ads_num = 0

起先测量试验示例:

(三卡塔 尔(英语:State of Qatar)网页检查测量检验部分

那有的的法力是检查测量检验多个网页中的全部第三方广告,找到广告的域并计算广告的数目,进一层要求分离出页面中遮盖的第三方广告。
我们将那部分定义为二个措施:search_ads(driver, web_url_para, sheet),那些方式供给多少个参数:

  • driver:已经创办的浏览器driver实例,如driver = Selenium::WebDriver.for :firefox
  • web_url_para:待检查实验网页网站url
  • sheet:已经创办的excel表单实例,如sheet = excel_fil.create_worksheet :name => "ads_show"

接下去会从多个模块来介绍那豆蔻梢头局地内容。

澳门新萄京官方网站 6

功用块风姿浪漫

    web_url = web_url_para
    #--------------------------------------------------------
    #web_url_domain:the domian of the web page
    #--------------------------------------------------------
    web_url_domain_raw = web_url.match(/https?://(.*?)/.*?/)
    web_url_domain = web_url_domain_raw[1]

那豆蔻梢头部分行使正则匹配获得待检查测验网站的域,有多个着重的点须求表明。

image.png

1.差异的域

所谓第三方,指的是在iframe中寄放的网页的域与近期网页的域分歧。那么如何是域呢?在自家早前介绍跨域应用方案rack-cors作品里,举了如此多少个事例:

这就是说怎么样是同源?我们精晓,U景逸SUVL由谐和、域名、端口和路径组成,如若五个UTiggoL的商业事务、域名和端口相仿,则意味着他们同源。

咱俩用贰个事例来表明:
URL: http://www.example.com:8080/script/jquery.js
在此个url中,各样字段分别表示的意义:

www——子域名
example.com——主域名
8080——端口号
script/jquery.js——供给之处
当左券、子域名、主域名、端口号中恣意一各不雷同偶然候,都算不相同的“域”。分裂的域之间人机联作供给能源,就叫跨域。

于是,必要拿到当前网页的域,来和iframe中的网站作比较,来判定是不是属于第三方。

无界面浏览器驱动测验:phantomJS 无分界面浏览器神器

2.MatchData对象的分组捕获

此间不对ruby中的正则表达式的语法举行详述,仅对其MatchData对象中的分组捕获相关的几点做轻巧的印证。

  • match方法

    • 能够双向使用match方法,即正则表达式和字符串对象均能够响应match方法。match方法会将字符串参数调换为正则表明式
    • match与=~的界别:正则表明式相称后重临值分裂,=~归来字符串相称中十分的启幕地方的数字索引,而match则赶回MatchData实例:

      2.2.7 :017 > "The alphabet starts with abc" =~ /abc/
       => 25 
      2.2.7 :018 > /abc/.match("The alphabet starts with abc")
       => #<MatchData "abc"> 
      
  • MatchData对象

    • 当正则表明式通过match方法相配时,重返三个MatchData对象;当正则表达式不相称时,重临nil

      2.2.7 :019 > /abc/.match("abcd")
       => #<MatchData "abc"> 
      2.2.7 :020 > /abc/.match("bcd")
       => nil 
      
    • 分组捕获

      • 正则表达式通过圆括号点名捕获(capture卡塔尔国。当叁个字符串和方式里面实行正则相称测量检验时,日常是想利用字符串,只怕更普及的是用字符串的风流倜傥局地产生都部队分操作。捕获表示法让客商能够从能够相配特殊子方式的字符串中,抽出和保存字符子串。
      • 从MatchData对象中获取捕获结果的二个方式是一向通过数组的办法索引对象:0索引会重回相配的所有的事字符串;从1带头以后,n的索引会基于从左侧包车型大巴括号开端计数,再次来到第n个捕获结果。关于“从左开始计数圆括号”的周期性,用三个例子来阐明:

        a=/((a)((b)c)(d)?)/.match("abce")
            => #<MatchData "abc" 1:"abc" 2:"a" 3:"bc" 4:"b" 5:nil> 
        a[0]                => "abc"
        a[1]                => "abc" 
        a[2]                => "a" 
        a[3]                => "bc" 
        a[4]                => "b" 
        a[5]                => nil        (不匹配)
        a[6]                => nil        (超出范围)
        a[-2]               => "b" 
        

        可以一定的是,上式中,从侧边开首计数的成对圆括号之间相称的结果,与结果严俊对应。

1:去官方网站进行下载phantomJS
http://phantomjs.org/download.html

效能块二

    driver.get web_url
    sleep 3
    #--------------------------------------------------------
    #get <iframe ...>...<iframe>
    #--------------------------------------------------------
    html_source = driver.page_source
    match_iframe = html_source.scan(/(<s*iframes.*?>.*?<s*/s*iframes*>)/)

那豆蔻梢头部分功用是探问指标网页,获取网页源代码,并获取源代码中享有的iframe标签中的数据。

澳门新萄京官方网站 7

作用块三

    #--------------------------------------------------------
    #select the third party hide ads url from iframe.src
    #iframe_src_hide:hide ad url
    #ad_hide_num: number
    #--------------------------------------------------------
    iframe_src_hide_raw = match_iframe.map do |ifr|
        if (src_match = ifr[0].to_s.match(/(<s*iframes.*?(src="(.*?)".*?>))/) )
            src_matched_hide = src_match[1].gsub(/&amp;/,"&")
            hide_condition_1 = src_matched_hide.match(/.*?swidths*=s*"s*0s*pxs*"s.*?heights*=s*"s*0s*pxs*".*/)
            hide_condition_2 = src_matched_hide.match(/.*?sheights*=s*"s*0s*pxs*"s.*?widths*=s*"s*0s*pxs*".*/)
            hide_condition_3 = src_matched_hide.match(/.*?styles*=s*".*?widths*:s*0s*pxs*;.*?heights*:s*0s*px.*?"/)
            hide_condition_4 = src_matched_hide.match(/.*?styles*=s*".*?heights*:s*0s*pxs*;.*?widths*:s*0s*px.*?"/)
            hide_condition_5 = src_matched_hide.match(/.*?sdisplays*=s*"s*nones*"s*/)
            hide_condition_6 = src_matched_hide.match(/.*?styles*=s*".*?displays*:s*nones*.*?"/)
            if (hide_condition_1 || hide_condition_2 || hide_condition_3 || hide_condition_4 || hide_condition_5 || hide_condition_6)
                # alert("123");
                src_matched = src_match[3].gsub(/&amp;/,"&")
                src_matched = src_matched.match(/https?://(.*)/.*/)
                if src_matched
                    domain_judge_raw = src_matched[0].to_s.match(/https?://(.*?)/.*?/)
                    domain_judge = domain_judge_raw[1]
                    if domain_judge.to_s == web_url_domain.to_s
                        #the same domain
                        src_matched = nil
                    else
                        #not the same domain
                        src_matched[0]
                    end
                end
            else
                src_matched = nil
            end
        end
    end
    iframe_src_hide = iframe_src_hide_raw.compact
    ad_hide_num = iframe_src_hide.size
    $hide_ads_num = $hide_ads_num   ad_hide_num

那有的功能是:检验页面中颇负的第三方掩盖广告。所谓遮盖广告,正是其iframe标签中的heightwidth品质的值均为0px,或者display天性的值为none,当时在页面中并不显示那一个第三方广告。
那后生可畏都部队分代码中,有八个点必要注解:

src_matched_hide = src_match[1].gsub(/&amp;/,"&")

这句代码的法力是将获得的src网站中的&amp;替换为&。这是因为,在HTML中,预先留下字符必须被交换为字符实体。这里对HTML字符实体举办了比较详细的介绍。
在本例中,我们透过正则表明式获得的url中,最常用的&被转义成了&amp;,由此要求对其张开修正。而其余的字符实体因为在url中使用比较少,此处未有进展越多的校验。

image.png

功效块四

    #--------------------------------------------------------
    #select the third party ads url from iframe.src
    #iframe_src:ad url
    #ad number
    #--------------------------------------------------------
    iframe_src_show_raw = match_iframe.map do |ifr| 
        if (src_match = ifr[0].to_s.match(/(<s*iframes.*?(src="(.*?)".*?>))/) )
            src_matched_hide = src_match[1].gsub(/&amp;/,"&")

            hide_condition_1 = src_matched_hide.match(/.*?swidths*=s*"s*0s*pxs*"s.*?heights*=s*"s*0s*pxs*".*/)
            hide_condition_2 = src_matched_hide.match(/.*?sheights*=s*"s*0s*pxs*"s.*?widths*=s*"s*0s*pxs*".*/)
            hide_condition_3 = src_matched_hide.match(/.*?styles*=s*".*?widths*:s*0s*pxs*;.*?heights*:s*0s*px.*?"/)
            hide_condition_4 = src_matched_hide.match(/.*?styles*=s*".*?heights*:s*0s*pxs*;.*?widths*:s*0s*px.*?"/)
            hide_condition_5 = src_matched_hide.match(/.*?sdisplays*=s*"s*nones*"s*/)
            hide_condition_6 = src_matched_hide.match(/.*?styles*=s*".*?displays*:s*nones*.*?"/)

            unless (hide_condition_1 || hide_condition_2 || hide_condition_3 || hide_condition_4 || hide_condition_5 || hide_condition_6)
                src_matched = src_match[3].gsub(/&amp;/,"&")
                src_matched = src_matched.match(/https?://(.*)/.*/)
                if src_matched
                    domain_judge_raw = src_matched[0].to_s.match(/https?://(.*?)/.*?/)
                    domain_judge = domain_judge_raw[1]
                    if domain_judge.to_s == web_url_domain.to_s
                        #the same domain
                        src_matched = nil
                    else
                        #not the same domain
                        src_matched[0]
                    end
                end
            else
                src_matched = nil
            end 

        end
    end
    iframe_src_show = iframe_src_show_raw.compact
    ad_show_num = iframe_src_show.size

    #--------------------------------------------------------
    #all ads 
    #--------------------------------------------------------
    iframe_src = iframe_src_hide   iframe_src_show
    ad_num = iframe_src.size

    $all_ads_num = $all_ads_num   ad_num

这有的功效是:拿到全部非隐瞒的第三方广告的数码,计算其数据;之后与隐蔽的广告数据整合,获得任何广告的多寡。

2:下载解压

功用块五

    #--------------------------------------------------------
    #select ad domian 
    #src_domain:ad url domain
    #--------------------------------------------------------
    src_domain_raw = iframe_src.map do |sr| 
        if (domain_match = sr.to_s.match(/https?://(.*?)/.*?/) )
            domain_matched = domain_match[1]
        end
    end
    src_domain = src_domain_raw.compact

那部分效果是:依照获得的富有广告数据,拿到这么些广告的域。

澳门新萄京官方网站 8

效率块六

    #--------------------------------------------------------
    #file operation
    #--------------------------------------------------------
    sheet[$web_num   0,0] = "Web url"
    sheet[$web_num   0,1] = web_url
    sheet[$web_num   1,0] = "The num of ads"
    sheet[$web_num   1,1] = ad_num
    sheet[$web_num   1,2] = "The num of hide ads"
    sheet[$web_num   1,3] = ad_hide_num
    sheet[$web_num   2,0] = "The url domain of ads"
    sheet[$web_num   2,1] = "The url of ads"   "(The top "   String(ad_hide_num)   " are hidden ads)"
    ad_num.times do |n|
        i = n   3   $web_num
        sheet[i,0] = src_domain[n]
        sheet[i,1] = iframe_src[n]
    end
    $web_num = $web_num   ad_num   3   1
    puts "This page has searched successfully: #{web_url_para}"

那有个别效能是文件操作,负担将获取的多少写入表格中。

到现在,这么些点子的内容早已全体介绍完了。尽管大家将那部分剧情全方位位于七个格局中,但出于全局变量的引进,那有的内容并不可能完全的独立。

image.png

(四卡塔 尔(英语:State of Qatar)代码实施部分

File.open(web_file) do |fil|
    if fil
        fil.each do |url|
            begin
                search_ads(driver, url, sheet)
            rescue
                puts "This page has searched unsuccessfully: #{url}"
                puts "Please waiting process..."
                driver.quit
                # driver = Selenium::WebDriver.for :chrome
                driver = Selenium::WebDriver.for :firefox
                puts "Start the next web url"
                next
            end
        end
    end
end


sheet[0,0] = "The ads number of all pages"
sheet[0,1] = $all_ads_num
sheet[0,2] = "The hide ads number of all pages"
sheet[0,3] = $hide_ads_num

excel_fil.write "ad_file.xls"

puts "Detection is complete!"

driver.quit  

那部分担当读取txt文件中的网站,并逐项实施上述办法,得到大家所需的多寡后将其写入报表中。
此处,我们进入了十二分管理。对于大家的效果与利益,一些网址会禁绝通过selenium访谈,有的时候由于互连网原因也会促成访谈时间过长而输球,由此需求增多极度管理,进而确定保证程序能够正确地运维下去。

3:配置情形变量路线
把下部的路径参与到蒙受变量中:

四.脚本使用


早已形成的脚本文件在条件布署成功后,能够一直动用,整个工程中国共产党有多个文件:

  • detection_ad.rb:
    可实施文件,在极端terminal中(windows下为cmd卡塔 尔(英语:State of Qatar)试行命令:

    >  ruby detection_ad.rb
    

    工程就可以平常运转。

  • weburl.txt:
    其一文件用来放置待检查评定的网页网站,每生机勃勃行仅能放置三个网站。程序运维后,脚本会张开weburl.txt文本,并相继对文件中的全体网站举行检查实验。
    当须求改革此文件名称时,要求在剧本中期维改过相关代码,将weburl.txt改正成团结索要的称号:

    web_file = "weburl.txt"
    
  • ad_file.xls:
    那么些文件用于保存数据,脚本运维后管理获得的全数数据会全体写入那几个文件中。借使急需将最后数额写入到任何名指标xls文件中,只要求改良detection_ad.rb文本中相关代码,将ad_file.xls改为协和索要的称谓:

    excel_fil.write "ad_file.xls"
    
D:phantomjs-2.1.1-windowsphantomjs-2.1.1-windowsbin

五.总结


到此地,我们的满贯工程就全体到位了,我们愿意到达的目标也都完毕了。但那边还会有豆蔻梢头部分疑点或是难题有待清除:

  • 频率难题:就算能够达成第三方网页检验,但程序实行的快慢相对极慢
  • 代码并从未包装的很好,且引进了全局变量,当以此本子用在可比大型的且复杂的工程中时,相当的大概现身难点
  • 代码品质有待增长
  • 出于时日对比急,对代码中变量的称谓未有接纳的很精确,注释亦非很清晰,必要改正

一时想到那样多,后续必要认真改善和上学。

4:使用CMD测验是不是布署成功

澳门新萄京官方网站 9

image.png

如图展现表达已经配备成功!

5:把phantomjs.exe也复制到python安装目录下:

澳门新萄京官方网站 10

image.png

6:代码示例:

from selenium import webdriver

# browser  = webdriver.Firefox()
# browser  = webdriver.Chrome()
browser  = webdriver.PhantomJS()
browser.get('http://www.baidu.com')
print(browser.page_source)
browser.close()

补给表达:

设若不复制对应的驱动文件到通晓python安装目录下的来讲,也能够平素的第一手的加载对应的目录文件
如下:

from selenium import webdriver

# browser  = webdriver.Firefox()
# browser  = webdriver.Chrome()
# browser  = webdriver.PhantomJS()
browser = webdriver.PhantomJS("D:/phantomjs-2.1.1-windows/phantomjs-2.1.1-windows/bin/phantomjs")
browser.get('http://www.baidu.com')

# driver = webdriver.PhantomJS("D:/phantomjs-2.1.1-windows/phantomjs-2.1.1-windows/bin/phantomjs")

print(browser.page_source)
# browser.close()

本文由澳门新萄京官方网站发布于www.8455.com,转载请注明出处:数据报表自动化深入分析,selenium的第三方广告检

关键词: