Python pandas库的用法

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
 
S1 = pd.Series(["a", "b", "c", "d"])
S1 = pd.Series([1,2,3,4], index=["a", "b", "c", "d"])
S1 = pd.Series({"a": 1, "b":2, "c":3, "d":4})
print(S1.index)
print(S1.values)
#原始数字索引
df1 = pd.DataFrame([["a", "b", "c", "d"], ['A', 'B', 'C', 'D']])
print(df1)
df2 = pd.DataFrame([["a", "A"], ["b", "B"], ["c", "C"], ["d", "D"]])
print(df2)
#这个有报错
#df3 = pd.DataFrame(("a", "A"), ("b", "B"), ("c", "C"), ("d", "D"))
#print(df3)
 
#这个例子不错, 设置列索引
df4 = pd.DataFrame([["a", "A"], ["b", "B"], ["c", "C"]], columns = ["小写", "大写"])
print(df4)
 
#这个例子不错,设置行索引
df5 = pd.DataFrame([["a", "A"], ["b", "B"], ["c", "C"]], index = ["一", "二", "三"])
print(df5)

#列名-列值
data = {"小写":["a", "b", "c", "d"], "大写": ["A", "B", "C", "D"]}
df6 = pd.DataFrame(data)
print(df6)
 
#设置行索引
df7 = pd.DataFrame(data, index = ["(1)", "(2)", "(3)", "(4)"])
print(df7)

#获取列索引
print(df7.columns)

#获取行索引
print(df7.index)
import pandas as pd
 
#读excel
#第二个参数是sheet名或sheet的index
df = pd.read_excel(r"C:\Users\clarkhu\Desktop\py\9月数据.xls")
print(df)

#当指定索引时,索引变成了指定的那一列
df = pd.read_excel(r"C:\Users\clarkhu\Desktop\py\9月数据.xls", sheet_name = 0, index_col = 2)
print(df)
df = pd.read_excel(r"C:\Users\clarkhu\Desktop\py\9月数据.xls")
print(df)
df = pd.read_excel(r"C:\Users\clarkhu\Desktop\py\9月数据.xls", sheet_name = "10月")
print(df)
 
#展示前几行,默认为5
s = df.head()

#打印行列数
print(df.shape)
 
#输出每个字段的类型等信息
df.info()
 
#判断是否有缺失值,如果是缺失值则为True, 否则则为false
s = df.isnull()
print(s)
print(s.shape)
 
#dropna()方法,删除有NaN的行
g1 = df.dropna()
print(g1)
 
#删除指定列存在NaN的行
g2 = df.dropna(subset=["性别"])
print(g2)
 
#删除全NaN的行
g3 = df.dropna(how="all")
print(g3)
 
#填充缺省值
print('==========g4============')
g4 = g3.fillna({"性别":"男", "手机号": "123456789"})
print(g4)
 
#重复值处理
print('xxxxxxxxxxxxxxx')
df.drop_duplicates() #删除所有值相同的
df.drop_duplicates(subset = "xxx") #删除单字段相同的行
#keep=first, keep=last, keep=false
print(df.drop_duplicates(subset = ["昵称", "性别"],keep="last"))
print(df.drop_duplicates(subset = ["昵称", "性别"],keep=False))

生成证书请求、证书和私钥脚本

!/bin/sh
create self-signed server certificate:
read -p "Enter your domain [www.example.com]: " DOMAIN
echo "Create server key…"
openssl genrsa -des3 -out $DOMAIN.key 2048
echo "Create server certificate signing request…"
 SUBJECT="/C=CN/ST=Guangdong/L=Shenzhen/O=Clark/OU=Clark/CN=$DOMAIN/emailAddress=xxx@clarkhu.net"
openssl req -new -subj $SUBJECT -key $DOMAIN.key -out $DOMAIN.csr
echo "Remove password…"
mv $DOMAIN.key $DOMAIN.origin.key
openssl rsa -in $DOMAIN.origin.key -out $DOMAIN.key
echo "Sign SSL certificate…"
openssl x509 -req -days 3650 -in $DOMAIN.csr -signkey $DOMAIN.key -out $DOMAIN.pem
echo "TODO:"
echo "Copy $DOMAIN.pem to /usr/local/nginx/conf/$DOMAIN.pem"
echo "Copy $DOMAIN.key to /usr/local/nginx/conf/$DOMAIN.key"
echo "Add configuration in nginx:"
echo "server {"
echo "    …"
echo "    listen 443 ssl;"
echo "    ssl_certificate     /usr/local/nginx/conf/$DOMAIN.pem;"
echo "    ssl_certificate_key /usr/local/nginx/conf/$DOMAIN.key;"
echo "}"

openssl证书请求和自签名命令详解

文章出处:https://linux.cn/article-7248-1.html
最近在做https改造,所以最近几篇的文章都是关于https证书相关的

1、密钥、证书请求、证书概要说明

在证书申请签发过程中,客户端涉及到密钥、证书请求、证书这几个概念,初学者可能会搞不清楚三者的关系,网上有的根据后缀名来区分三者,更让人一头雾水。我们以申请证书的流程说明三者的关系。客户端(相对于CA)在申请证书的时候,大体上有三个步骤:

  • 第一步:生成客户端的密钥,即客户端的公私钥对,且要保证私钥只有客户端自己拥有。
  • 第二步:以客户端的密钥和客户端自身的信息(国家、机构、域名、邮箱等)为输入,生成证书请求文件。其中客户端的公钥和客户端信息是明文保存在证书请求文件中的,而客户端私钥的作用是对客户端公钥及客户端信息做签名,自身是不包含在证书请求中的。然后把证书请求文件发送给CA机构。
  • 第三步:CA机构接收到客户端的证书请求文件后,首先校验其签名,然后审核客户端的信息,最后CA机构使用自己的私钥为证书请求文件签名,生成证书文件,下发给客户端。此证书就是客户端的身份证,来表明用户的身份。

至此客户端申请证书流程结束,其中涉及到证书签发机构CA,CA是被绝对信任的机构。如果把客户端证书比作用户身份证,那么CA就是颁发身份证的机构,我们以https为例说明证书的用处。

为了数据传输安全,越来越多的网站启用https。在https握手阶段,服务器首先把自己的证书发送给用户(浏览器),浏览器查看证书中的发证机构,然后在机器内置的证书中(在PC或者手机上,内置了世界上著名的CA机构的证书)查找对应CA证书,然后使用内置的证书公钥校验服务器的证书真伪。如果校验失败,浏览器会提示服务器证书有问题,询问用户是否继续。

例如12306网站,它使用的自签名的证书,所以浏览器会提示证书有问题,在12306的网站上有提示下载安装根证书,其用户就是把自己的根证书安装到用户机器的内置证书中,这样浏览器就不会报证书错误。但是注意,除非特别相信某个机构,否则不要在机器上随便导入证书,很危险。

openssl req 命令

发现其参数多而复杂,还有许多没有用到过的参数。但是在实际应用中我们使用到的参数很有限,我们根据req的基本功能来学习。

req的基本功能主要有两个:生成证书请求和生成自签名证书。其他还有一些校验、查看请求文件等功能,示例会简单说明下。参数说明如下

[new/x509]

当使用-new选取的时候,说明是要生成证书请求,当使用x509选项的时候,说明是要生成自签名证书。

[key/newkey/keyout]

key和newkey是互斥的,key是指定已有的密钥文件,而newkey是指在生成证书请求或者自签名证书的时候自动生成密钥,然后生成的密钥名称有keyout参数指定。
当指定newkey选项时,后面指定rsa:bits说明产生rsa密钥,位数由bits指定。指定dsa:file说明产生dsa密钥,file是指生成dsa密钥的参数文件(由dsaparam生成)

[in/out/inform/outform/keyform]

in选项指定证书请求文件,当查看证书请求内容或者生成自签名证书的时候使用
out选项指定证书请求或者自签名证书文件名,或者公钥文件名(当使用pubkey选项时用到),以及其他一些输出信息。
inform、outform、keyform分别指定了in、out、key选项指定的文件格式,默认是PEM格式。

[config]

参数文件,默认是/etc/ssl/openssl.cnf(ubuntu12.04),根据系统不同位置不同。该文件包含生成req时的参数,当在命令行没有指定时,则采用该文件中的默认值。
除上述主要参数外,还有许多其他的参数,不在一一叙述,有兴趣的读者可以查看req的man手册

req使用实例

1、使用已有私钥生成证书请求

使用原有的RSA密钥生成证书请求文件,输入主体相关信息:

根据私钥生成证书请求

使用原有的RSA密钥生成证书请求文件,指定-batch选项,主体信息从配置文件读取:

指定batch 主体信息从配置文件读取

使用原有的RSA密钥生成证书请求文件,指定-subj选项,主体信息由命令行subj指定:

指定subj,主体信息由命令行指定

可以看到公钥和请求信息:

查看公钥和请求信息

2、自动生成密钥,生成证书请求文件

自动生成1024位RSA密钥,并生成证书请求

自动生成1024位RSA密钥,并生成证书请求文件,指定-nodes文件,密钥文件不加密:

自动生成1024位DSA密钥参数:

自动生成1024位DSA密钥,并生成证书请求文件,指定-nodes文件,密钥文件不加密:

3、生成自签名证书

生成自签名证书,与req参数一样,只需要把req修改为x509即可:

查看证书文件:

查看证书文件

4、查看证书请求内容
生成证书请求:

查看证书请求内容,subject指定输出主体:

5、校验证书请求文件

指定verify指令,校验证书请求文件,其操作时提取请求文件中的公钥来验证签名信息:

还有相关比较好的文章说明: https://www.cnblogs.com/guogangj/p/4118605.html

CA证书详解

文章来源: https://www.cnblogs.com/handsomeBoys/p/6556336.html , 此文章个人觉得讲的比较详细到位,之前也有过一些关于https 公钥和私钥分享,
http://www.clarkhu.net/?p=131

1.什么是CA证书。

看过一些博客,写的比较形象具体。

◇ 普通的介绍信

  想必大伙儿都听说过介绍信的例子吧?假设 A 公司的张三先生要到 B 公司去拜访,但是 B 公司的所有人都不认识他,他咋办捏?常用的办法是带公司开的一张介绍信,在信中说:兹有张三先生前往贵公司办理业务,请给予接洽……云云。然后在信上敲上A公司的公章。

  张三先生到了 B 公司后,把介绍信递给 B 公司的前台李四小姐。李小姐一看介绍信上有 A 公司的公章,而且 A 公司是经常和 B 公司有业务往来的,这位李小姐就相信张先生不是歹人了。

这里,A公司就是CA证书

◇ 引入中介机构的介绍信

  好,回到刚才的话题。如果和 B 公司有业务往来的公司很多,每个公司的公章都不同,那前台就要懂得分辨各种公章,非常滴麻烦。所以,有某个中介公司 C,发现了这个商机。C公司专门开设了一项“代理公章”的业务。

  今后,A 公司的业务员去 B 公司,需要带2个介绍信:

  介绍信1

  含有 C 公司的公章及 A 公司的公章。并且特地注明:C 公司信任 A 公司。

  介绍信2

  仅含有 A 公司的公章,然后写上:兹有张三先生前往贵公司办理业务,请给予接洽……云云。

  某些不开窍的同学会问了,这样不是增加麻烦了吗?有啥好处捏?

  主要的好处在于,对于接待公司的前台,就不需要记住各个公司的公章分别是啥样子的;他/她只要记住中介公司 C 的公章即可。当他/她拿到两份介绍信之后,先对介绍信1的 C 公章,验明正身;确认无误之后,再比对介绍信1和介绍信2的两个 A 公章是否一致。如果是一样的,那就可以证明介绍信2是可以信任的了。

◇ 什么是证书?

  “证书”英文也叫“digital certificate”或“public key certificate”(专业的解释看“这里”)。

  它是用来证明某某东西确实是某某东西的东西(是不是像绕口令?)。通俗地说,证书就好比例子里面的公章。通过公章,可以证明该介绍信确实是对应的公司发出的。

  理论上,人人都可以找个证书工具,自己做一个证书。那如何防止坏人自己制作证书出来骗人捏?请看后续 CA 的介绍。

◇ 什么是CA?

  CA是Certificate Authority的缩写,也叫“证书授权中心”。(专业的解释看“这里”)

  它是负责管理和签发证书的第三方机构,就好比例子里面的中介——C 公司。一般来说,CA必须是所有行业和所有公众都信任的、认可的。因此它必须具有足够的权威性。就好比A、B两公司都必须信任C公司,才会找 C 公司作为公章的中介。

◇ 什么是CA证书?

  CA 证书,顾名思义,就是CA颁发的证书。

  前面已经说了,人人都可以找工具制作证书。但是你一个小破孩制作出来的证书是没啥用处的。因为你不是权威的CA机关,你自己搞的证书不具有权威性。

  这就好比上述的例子里,某个坏人自己刻了一个公章,盖到介绍信上。但是别人一看,不是受信任的中介公司的公章,就不予理睬。坏蛋的阴谋就不能得逞啦。

  文本后续提及的证书,若无特殊说明,均指 CA 证书。

2.证书的签发过程:

a.服务方 S 向第三方机构CA提交公钥、组织信息、个人信息(域名)等信息并申请认证;

b.CA 通过线上、线下等多种手段验证申请者提供信息的真实性,如组织是否存在、企业是否合法,是否拥有域名的所有权等;

c.如信息审核通过,CA 会向申请者签发认证文件-证书。

证书包含以下信息:申请者公钥、申请者的组织信息和个人信息、签发机构 CA 的信息、有效时间、证书序列号等信息的明文,同时包含一个签名;

签名的产生算法:首先,使用散列函数计算公开的明文信息的信息摘要,然后,采用 CA 的私钥对信息摘要进行加密,密文即签名;

d.客户端 C 向服务器 S 发出请求时,S 返回证书文件;

e.客户端 C 读取证书中的相关的明文信息,采用相同的散列函数计算得到信息摘要,然后,利用对应 CA 的公钥解密签名数据,对比证书的信息摘要,如果一致,则可以确认证书的合法性,即公钥合法;

f.客户端然后验证证书相关的域名信息、有效时间等信息;

g.客户端会内置信任 CA 的证书信息(包含公钥),如果CA不被信任,则找不到对应 CA 的证书,证书也会被判定非法。

在这个过程注意几点:

1.申请证书不需要提供私钥,确保私钥永远只能服务器掌握;

2.证书的合法性仍然依赖于非对称加密算法,证书主要是增加了服务器信息以及签名;

3.内置 CA 对应的证书称为根证书,颁发者和使用者相同,自己为自己签名,即自签名证书;

4.证书=公钥+申请者与颁发者信息+签名;

3.http存在的问题(引用:http://blog.csdn.net/wangjun5159/article/details/51510594)

http通信存在的问题

  • 容易被监听 
    • http通信都是明文,数据在客户端与服务器通信过程中,任何一点都可能被劫持。比如,发送了银行卡号和密码,hacker劫取到数据,就能看到卡号和密码,这是很危险的
  • 被伪装 
    • http通信时,无法保证通行双方是合法的,通信方可能是伪装的。比如你请求www.taobao.com,你怎么知道返回的数据就是来自淘宝,中间人可能返回数据伪装成淘宝。
  • 被篡改 
    • hacker中间篡改数据后,接收方并不知道数据已经被更改

共享密钥加密和公开密钥加密

后续内容的需要,这里插播一段共享密钥加密和公开密钥加密

  • 共享密钥加密 
    • 共享密钥的加密密钥和解密密钥是相同的,所以又称为对称密钥
  • 公开密钥加密 
    • 加密算法是公开的,密钥是保密的。公开密钥分为私有密钥和公有密钥,公有密钥是公开的,任何人(客户端)都可以获取,客户端使用公有密钥加密数据,服务端用私有密钥解密数据。
  • 异同 
    • 共享密钥加密与公开密钥加密相比,加解密处理速度快,但公开密钥更适应互联网下使用

https解决的问题

https很好的解决了http的三个缺点(被监听、被篡改、被伪装),https不是一种新的协议,它是http+SSL(TLS)的结合体,SSL是一种独立协议,所以其它协议比如smtp等也可以跟ssl结合。https改变了通信方式,它由以前的http—–>tcp,改为http——>SSL—–>tcp;https采用了共享密钥加密+公开密钥加密的方式

  • 防监听 
    • 数据是加密的,所以监听得到的数据是密文,hacker看不懂。
  • 防伪装 
    • 伪装分为客户端伪装和服务器伪装,通信双方携带证书,证书相当于身份证,有证书就认为合法,没有证书就认为非法,证书由第三方颁布,很难伪造
  • 防篡改 
    • https对数据做了摘要,篡改数据会被感知到。hacker即使从中改了数据也白搭。

https连接过程

  • 客户端发送请求到服务器端
  • 服务器端返回证书和公开密钥,公开密钥作为证书的一部分而存在
  • 客户端验证证书和公开密钥的有效性,如果有效,则生成共享密钥并使用公开密钥加密发送到服务器端
  • 服务器端使用私有密钥解密数据,并使用收到的共享密钥加密数据,发送到客户端
  • 客户端使用共享密钥解密数据
  • SSL加密建立………

客户端认证的通信的过程

  • 客户端需要认证的过程跟服务器端需要认证的过程基本相同,并且少了最开始的两步。这种情况都是证书存储在客户端,并且应用场景比较少,一般金融才使用,比如支付宝、银行客户端都需要安装证书

后续的问题

  • 怎样保证公开密钥的有效性 
    • 你也许会想到,怎么保证客户端收到的公开密钥是合法的,不是伪造的,证书很好的完成了这个任务。证书由权威的第三方机构颁发,并且对公开密钥做了签名。
  • https的缺点 
    • https保证了通信的安全,但带来了加密解密消耗计算机cpu资源的问题 ,不过,有专门的https加解密硬件服务器
  • 各大互联网公司,百度、淘宝、支付宝、知乎都使用https协议,为什么? 
    • 支付宝涉及到金融,所以出于安全考虑采用https这个,可以理解,为什么百度、知乎等也采用这种方式?为了防止运营商劫持!http通信时,运营商在数据中插入各种广告,用户看到后,怒火发到互联网公司,其实这些坏事都是运营商(移动、联通、电信)干的,用了https,运营商就没法插播广告篡改数据了。

    4.比较完整的过程:

    1. 客户端发起HTTPS请求

      这个没什么好说的,就是用户在浏览器里输入一个https网址,然后连接到server的443端口。

      2. 服务端的配置

      采用HTTPS协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面(startssl就是个不错的选择,有1年的免费服务)。这套证书其实就是一对公钥和私钥。如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。

      3. 传送证书

      这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。

      4. 客户端解析证书

      这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随机值。然后用证书对该随机值进行加密。就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。

      5. 传送加密信息

      这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。

      6. 服务段解密信息

      服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密。所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。

      7. 传输加密后的信息

      这部分信息是服务段用私钥加密后的信息,可以在客户端被还原。

      8. 客户端解密信息

      客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容。整个过程第三方即使监听到了数据,也束手无策。

    5.总结整个过程:

    1.服务器向CA机构获取证书(假设这个证书伪造不了),当浏览器首次请求服务器的时候,服务器返回证书给浏览器。(证书包含:公钥+申请者与颁发者的相关信息+签名)

    2.浏览器得到证书后,开始验证证书的相关信息,证书有效(没过期等)。(验证过程,比较复杂,详见上文)。

    3.验证完证书后,如果证书有效,客户端是生成一个随机数,然后用证书中的公钥进行加密,加密后,发送给服务器,服务器用私钥进行解密,得到随机数。之后双方便开始用该随机数作为钥匙,对要传递的数据进行加密、解密。

    Mysqldump使用详解

    最近做项目,需要从库中dump指定条件的数据,又一次将mysqldump详细的看了一遍,记录一下,以便下次不会忘记。

    /* mysqldump 选项 */
       --no-create-info 取消创建表sql(默认存在)
       --add-drop-table 每个数据表创建之前添加drop数据表语句
       --add-drop-database 每个数据库创建之前添加drop数据库语句
       --comments 附加注释信息。默认为打开
       --triggers 导出触发器。该选项默认启用,用--skip-triggers禁用它
       --complete-insert 使用完整的insert语句(包含列名称)。这么做能提高插入效率,但是可能会受到max_allowed_packet参数的影响而导致插入失败
       --quick 不缓冲查询,直接导出到标准输出。默认为打开状态,使用--skip-quick取消该选项
       --skip-add-locks 在每个表导出之前增加LOCK TABLES并且之后UNLOCK  TABLE。(默认为打开状态,使用--skip-add-locks取消选项)
       --replace 使用REPLACE INTO 取代INSERT INTO.
       --where, -w只转储给定的WHERE条件选择的记录。请注意如果条件包含命令解释符专用空格或字符,一定要将条件引用起来
       --default-character-set=utf8
       --single-transaction 该选项在导出数据之前提交一个BEGIN SQL语句,BEGIN 不会阻塞任何应用程序且能保证导出时数据库的一致性状态。它只适用于多版本存储引擎(它不显示加锁通过判断版本来对比数据),仅InnoDB。本选项和--lock-tables 选项是互斥的,因为LOCK TABLES 会使任何挂起的事务隐含提交。要想导出大表的话,应结合使用--quick 选项
    
    For example:
    /usr/local/mysql/bin/mysqldump --set-gtid-purged=OFF  -h'xxxx' -Pyyy -u'user' -p --default-character-set=utf8 --single-transaction --comments=false --no-create-info=true --add-drop-table=false  --triggers=false --complete-insert --quick --skip-add-locks --databases db_name --tables table_name -w'where_condition'>> /tmp/xxxx.sql

    mysqldump -w参数不允许条件过长,会报段错误:
    https://stackoverflow.com/questions/50904161/mysqldump-segmentation-fault-on-large-where-id-in

    解决方案:将in条件的切成多份循环执行dump,比如一个数组,如果是php, 可以用array_chunk切分成多个数组,implode拼接in条件。

    单元测试框架unittest

    unittest是Python语言的单元测试框架,在Python的官方文档中,对unitest单元测试框架进行了详细的介绍。 https://docs.python.org/3/library/unittest.html

    unittest单元测试框架提供了创建测试用例、测试套件和批量执行测试用例的方案。在python安装成功后,unittest单元测试框架就可以直接导入使用,它属于标准库。作为单元测试的框架,unittest单元测试框架也是对程序的最小模块进行的一种敏捷化测试。

    利用单元测试框架,可以创建一个类,该类继承unittest的TestCase,这样可以把每个TestCase看成是一个最小单元,由测试套件组织起来,运行时直接执行即可,同时可引入测试报告。

    • 测试固件

    在unittest单元测试框架中,测试固件用于处理初始化的操作,例如,在对百度的搜索进行测试之前,首先需要打开浏览器并且进入百度首页;测试结束后,需要关闭浏览器。测试固件提供了两种执行方式,一种是每次执行一个测试用例,测试固件都会被执行到;另外一种是不管有多少个测试用例,测试固件只执行一次。

    测试固件每次都执行

    import unittest
     class DemoTest(unittest.TestCase):
       def setUp(self):    #1
             print('start')
       def tearDown(self): #3     
         print('end') 
       def test_add_story(self):   #2     
         print('测试用例1执行') 
       def test_edit_story(self):     
         print('测试用例2执行')
     if name == 'main':
         unittest.main(verbosity=2)

    执行结果:

    执行顺序是先执行setUp方法,再执行具体的测试用例test_add_story, 最后执行tearDown方法,这个过程执行两次,如果在一个测试类中有N个测试用例,那么也就意味着着打开N次浏览器,关闭N次浏览器,而关闭和打开浏览器都会占用一定的资源和时间,很显然,性能不好,执行时间长

    from selenium import webdriver
    import unittest
    import time as t
    class DemoTest(unittest.TestCase):
    def setUp(self):    #1     
        self.driver = webdriver.Chrome()     
        self.driver.maximize_window() 
        self.driver.implicitly_wait(30) 
    
    def tearDown(self): #3     
        t.sleep(5)     
        self.driver.quit() 
    
    def test_add_story(self):   #2     
        print('执行新增需求测试用例')
      …………
    
    def test_delete_story(self):     
        print("执行删除需求测试用例")     
      …………
    
    def _add_data_to_name_and_description(self, name, description):
        …………
     
    if name == 'main':
         # unittest.main(verbosity=2)
         suite = unittest.TestSuite()
         suite.addTest(DemoTest("test_add_story"))
         suite.addTest(DemoTest("test_edit_story"))
         suite.addTest(DemoTest("test_delete_story"))
         #执行测试
         runner = unittest.TextTestRunner()
         runner.run(suite)   

    unittest的main()方法执行用例的顺序是按照测试类、测试方法的名字的ASCII顺序来执行测试方法。如果想要控制执行顺序,有以下两种方式:

    • 通过TestSuite按照顺序添加想要执行的方法,上面的代码用的就是此方法
    • 顺应testunit的执行顺序,就是通过控制方法名字来实现

    测试固件只执行一次

    钩子方法setUp和tearDown虽然经常使用,但是在UI自动化测试中,一个系统的测试用例一般多达五百多条,打开和关闭五百次浏览器,会消耗大量的资源和时间。在unittest单元测试框架中可以使用另外一个测试固件来解决这一问题,它就是setUpClass和tearDownClass方法。该测试固件方法是类方法,需要在方法上面加装饰器@classmethod。使用该测试固件,不管多少个测试用例,测试固件只执行一次,也就是说不管多少个测试用例,执行的时候,浏览器只被打开一次和关闭一次。

    Selenium自动化测试基础

    1.访问页面、find_element_by_name选取元素、访问iframe、提交表单

    #引入webdriver
    from selenium import webdriver
    import time as t
    
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.implicitly_wait(30)
    driver.get("http://xxxxx/yyyy")
    
    #添加需求标题
    driver.find_element_by_name("data[Story][name]").send_keys("添加需求测试用例")
    #添加需求详细描述
    iframe = driver.find_element_by_tag_name("iframe")
    # driver.switch_to_frame(iframe) //旧版切换iframe
    driver.switch_to.frame(iframe)
    #清空详细描述
    driver.find_element_by_tag_name("body").clear()
    #填写需求详细描述
    driver.find_element_by_tag_name("body").send_keys("添加需求测试用例");
    #切换回父页面
    driver.switch_to.default_content()
    # 点击提交按钮
    # driver.find_element_by_id("btn_save_view").click()
    # 提交表单
    driver.find_element_by_id("FormStory").submit()
    t.sleep(5)
    driver.quit()

    2. find_element_by_xpath XPath方式选取元素

    !/usr/bin/python3
     --coding:utf-8 --
    from selenium import webdriver
    import time as t
    
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.implicitly_wait(30)
     driver.get("http://xxxxx/yyyy")
    # find_element_by_xpath选取元素
    a_link = driver.find_element_by_xpath('//*[@id="searchable"]/div[3]/div/ul/li[2]/p[2]/a')
    a_link.click();
    t.sleep(5)
    driver.quit()

    Chrome控制台选中元素,Copy XPath 可以复制出XPath

    3.find_element_by_css_selector方式选取元素,execute_script执行js

    from selenium import webdriver
    from selenium.webdriver.common.action_chains import ActionChains
    import time as t
    #up = "window.scrollTo(0,0)"
    #down = "window.scrollTo(0,document.body.scrollHeight)"
    #tui-b是一个带滚动条的容器
    #滚动到最顶端
    up = "document.querySelector('.tui-b').scrollTop=0"
    #滚动条向下滚100px
    down = "document.querySelector('.tui-b').scrollTop=100"
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.get("http://xxxxx/yyyy");
    #向下滚动,以便看到update_status_btn按钮
    driver.execute_script(down)
    driver.find_element_by_css_selector("#update_status_btn").click()
    t.sleep(4)
    driver.quit()

    4.得到当前页面的地址

    from selenium import webdriver
    
    driver = webdriver.Chrome()
    driver.maximize_window() //最大化窗口
    driver.implicitly_wait(30)
    driver.get("http://xxx.yyyy")
    print('测试地址为: {0}'.format(driver.current_url))
    driver.quit()

    5.得到当前页面的源码

    from selenium import webdriver
    
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.implicitly_wait(30)
    driver.get("http://www.xxxx.com")
    print('页面代码如下: {0}'.format(driver.page_source))
    driver.quit()

    6.得到当前页面的标题

    driver = webdriver.Chrome()
    print('页面标题:{0}'.format(driver.title))

    7.判断元素是否选中

    from selenium import webdriver
    import time as t
    
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.implicitly_wait(30)
    driver.get("www.sss.com")
    login_remember = driver.find_element_by_id("chkWeek")
    print("是否记住login: {0}".format(login_remember.is_selected()))
    login_remember.click()
    print("是否记住login: {0}".format(login_remember.is_selected()))
    driver.quit()

    8.选取链接元素

    from selenium import webdriver
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.implicitly_wait(30)
    driver.get("www.yyy.com")
    obj = driver.find_element_by_link_text(u"添加需求测试用例")
    obj = driver.find_element_by_partial_link_text(u'添加需求测试')
    obj.click()
    driver.quit()

    9.下拉选择框select的定位

    from selenium.webdriver import ActionChains
    import time as t
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.implicitly_wait(30)
    driver.get("http://www.baidu.com")
    t.sleep(3)
    element = driver.find_element_by_link_text(u'设置')
    t.sleep(2)
    ActionChains(driver).move_to_element(element).perform()
    t.sleep(3)
    driver.find_element_by_css_selector('.setpref').click()
    t.sleep(3)
    nr= driver.find_element_by_id('nr')
    select = Select(nr)
    select.select_by_visible_text('每页显示20条')  #按文本选择
    select.select_by_index(2)    #50 按索引值选择
    select.select_by_value('20') #按option的value值选择, 记得要引号
    print('下拉框选择的最新条数是:', nr.get_attribute('value'))
    t.sleep(3)
    driver.quit()

    10.原生alert框的定位

    from selenium import webdriver
    from selenium.webdriver.support.select import Select
    //需要的库
    from selenium.webdriver.common.alert import Alert
    from selenium.webdriver.common.action_chains import ActionChains
    import time as t
    driver = webdriver.Chrome()
    driver.maximize_window()
    driver.implicitly_wait(30)
    driver.get("http://www.baidu.com")
    t.sleep(3)
    element = driver.find_element_by_link_text(u'设置')
    t.sleep(2)
    ActionChains(driver).move_to_element(element).perform()
    t.sleep(3)
    driver.find_element_by_css_selector('.setpref').click()
    t.sleep(3)
    nr= driver.find_element_by_id('nr')
    select = Select(nr)
    select.select_by_visible_text('每页显示20条')
    select.select_by_index(2)    #50
    select.select_by_value('20')
    print('下拉框选择的最新条数是:', nr.get_attribute('value'))
    t.sleep(3)
    driver.find_element_by_css_selector('.prefpanelgo').click()
    t.sleep(2)
    #获取alert框的文本信息  //关键语句
    print('alert框的文本:{0}'.format(driver.switch_to.alert.text))
    #点击alert框的确定按钮  //关键语句
    driver.switch_to.alert.accept()
    driver.quit()

    Scrum详解

    Scrum是迭代式增量软件开发过程,通常用于敏捷软件开发
    用7句话概括一下:[出自《知行合一:实现价值驱动的敏捷和精益开发》一书]

    • 产品经理(Product Owner)负责建立并维护一个按优先级次序排列的、反映客户期望的产品需求列表(Product backlog)
    • 在迭代(sprint)计划时,团队从需求列表中优先级高的需求项中选取一小部分,放入迭代需求列表(sprint backlog)中,并决定如何开发这些需求功能
    • 团队在固定的时间周期内完成一个迭代,通常是2-4周,团队每天会在一起评估项目进展情况(daily scrum)
    • 在这个过程中,Scrum过程经理(Scrum Master)会让团队关注迭代目标的实现并遵循Scrum实践
    • 在每次迭代结束时,团队完成的代码是可以提交的:可以直接让客户使用,或者可以展示给客户或用户代表
    • 迭代的最后两个活动是迭代评审(sprint review)和迭代回顾(sprint retrospective),根据反馈,对产品及团队工作方式(过程)做优化调整
    • 在下个迭代开始时,Scrum团队(Scrum team)又会从产品需求列表中选取一部分优先级高的需求项,开始新一轮的开发工作
    典型的Scrum管理框架

    有人把Scrum简单解释为3个角色,3个文档和5个会议:

    Scrum管理框架中的3个角色是产品经理,Scrum Master(Scrum 过程经理)和Scrum团队(Scrum team)

    产品经理最主要的责任是保证团队开发的功能特性对客户是有价值的,具体来说,他需要做以下5件事:

    • 建立产品的愿景,也就是产品给客户带来的价值
    • 建立维护产品的发布计划/版本计划(release plan)
    • 及时收集用户反馈、优化产品需求
    • 确定每条需求项(User Story)的价值及优先级
    • 明确每个需求项的验收通过标准

    Scrum Master比较特殊,在传统方法中是没有这个角色的,所以这个是经常被误解的角色。一个称职的SM(过程经理)能在3个方面起到重要作用:

    • 让团队关注点始终在实现客户价值上;
    • 让团队在每个迭代中不受干扰(大家都知道封闭式开发能保证效率,Scrum的每一次迭代就是不需要团队成员住酒店的封闭式开发);
    • 帮助产品经理和团队在Scrum的框架下做好各自的工作,并做到有效的沟通。

    SM[Scrum Master]为了实现上面3个目标,SM需求做好以下一些工作:

    • 建立、改进适用于团队的Scrum过程
    • 推动敏捷实践及有效开发实践在开发中的有效应用
    • 推动团队问题障碍的解决
    • 帮助培养团队的自我管理开成良好的团队文化
    • 协调各方的沟通

    SM不是真正意义上的经理,不是传统的项目经理,他和团队成员之间不是管理与被管理的关系。SM更像是团队的过程教练。

    我个人作为SM时,实际需要做的事:

    • 修改各特性小组名称,以作知会
    • 信使会之前与相关产品、技术人员确定本迭代的大致需求范围;(产品需求不需要了解太过细节。但技术类的需要仔细与相关人员确认)
    • 参加信使会,积极参与讨论,发表自己看法,了解需求背景、目的等信息,记录其他特性小组的需求;(包括父需求、阶段目标等)
    • IPM前,提前过一遍下个迭代的用户需求,和产品沟通User Story的可行性和注意点[主要是如何在现有系统的基础上快速实现用户需求,比如哪些是可实现的,哪些是可能需要增加额外工作量的]
    • 参加本特性小组IPM时,在开会之前作其他特性小组的关键需求介绍,并回答其他成员的提问
    • 迭代中,在晨会、讨论会、工作群中关注迭代进度,及时发现潜在风险(如技术、资源、沟通等问题),尤其是在进度方面的问题。对于能够解决的问题进行跟进或组织讨论
    • 在迭代快结束的时候,提醒团队成员及时扭转需求和产品的封版时间
    • 迭代封版后,针对规模是3或者某些重点需求,如果尚未流转,则需要跟负责人进行沟通,了解是否能正常流转,并将之反馈在信使群中
    • 在迭代结束后,组织迭代评审和迭代回顾

    Scrum框架下的最后一个角色是开发团队(Scrum team),开发团队是Scrum过程的核心。这是个规模小(5-9人)的团队,一般是一个Feature Team,团队应具备的软件开发所需要的所有技能:需求分析、设计、编码、测试、技术资料编写等。它的主要责任是通过迭代,不断开发提交对客户有价值的功能特性,同时持续改进提升团队能力,将其潜能最大化。团队主要工作包括:

    • 估计产品需求列表中用户故事的复杂度,考虑用户故事的优先级、依赖关系、实现难度等,选择下个迭代的范围,形成迭代需求列表[这个形成迭代需求列表一般由产品经理来规划,开发只在IPM上估算需求规模工作量]
    • 遵循团队达成的工程实践共识,完成每个用户故事的需求澄清、设计、编码、评审、测试、资料编写等相关工作,不断提交对客户有价值的需求功能
    • 不断总结开发过程中的得与失,持续改进个人能力及团队能力

    Scrum管理框架中的3个文档:

    • 产品需求列表,产品需求列表是Scrum中最重要的文档,它是一个动态的,产品经理可以随时对其进行调整的,包含了客户期望的需求列表清单。大部分敏捷团队用“用户故事”的形式来表示每一个需求项,产品经理会对它们按价值高低排序
    • 迭代需求列表,是由团队负责管理,它定义了Scrum团队某次迭代承诺实现的用户故事或任务。在迭代中,它一般是不变的,偶尔会在IPM上有所调整,比如视成员数的增减,休假情况来调整
    • 燃尽图是Scrum中的第三个文档,它主要是用来监控版本及迭代开发进展情况。版本燃尽图显示本次版本未开发的需求项或剩余的工作,而迭代燃尽图则显示一次迭代中未完成的工作。
    版本燃尽图
    迭代燃尽图

    燃尽图可以清晰的展示版本实现情况和迭代完成情况

    Scrum管理框架中的5个会议:

    • 产品需求列表的细化会议:团队和产品经理一起会细化列在需求列表前面的需求项,为近几次的迭代做好准备,这个在我所在团队由产品经理完成
    • 迭代计划会议(IPM):团队从产品需求列表前面被细化的需求项中选择本次迭代要完成的用户故事或任务,形成迭代需求列表,IPM上一般开发团队一起来就用户故事估算故事规模点/工作量
    • 每日站会
    • 迭代评审会议:showcase 本次迭代中团队完成的需求功能,让产品经理、客户及其他利益相关人加深对产品的理解,调整产品需求列表,逐步识别聚焦到真正对客户有价值的需求特性。
    • 迭代回顾会议:会列出本迭代或是近期迭代中团队的well和less well

    Scrum中的一个重要时间盒体现在固定的迭代周期(一般2-4周),固定时长的产品需求列表细化会议(2-4小时),固定时长的迭代计划会议(半天时长),固定时长的每日站会(5-10分钟),固定时长的迭代评审会议(2-4个钟)和固定时长的迭代回顾会议(2-4个钟)。时间盒是使团队专注、发挥潜能,及早发现问题并做出解决决策的有效手段。

    以上为Scrum的主要内容,Scrum和XP是常见的敏捷开发方法

    Web安全注意事项总览

    Web安全可以分为:系统/服务器安全,DB安全,代码安全,业务安全,登录安全等

    服务器安全

    • php-fpm的启动用户的设置,不要以root启动,master就root,worker不能是root,一般为nobody或www。php-fpm.conf配置文件里设置
    • mysql的启动用户
    • nginx的启动用户,非root启动,一般用nobody启动
    • 上传目录和下载目录的权限的设置,上传文件的文件名校验等
    • php.ini文件,disable_functions设置关闭危险函数,关闭注册全局变量(register_globals off),magic_quotes_gpc on 防止sql注入,display_errors=off 关闭错误显示
    • 脚本,webroot等目录的权限设置
    • 线上debug关掉
    • open_basedir设置,避免php脚本访问不应该访问的文件
    • 服务器的安全组入站规则,iptable设置

    DB安全

    • 账号密码密文存储
    • web账号,运维账号,值班账号分开
    • 每个账号授权的host 设置适宜,不能扩大

    登录安全

    • 校验码+噪点
    • 登录密码的复杂性校验,字母+数字+大小写+非连续数字
    • 多次登录失败(冻结账号)
    • 离职的账号不能登录(如果内部平台的话,可以考虑)
    • 三个月无feed的账号可以冻结(如果是内部平台的话,可以考虑)

    代码安全:

    • 注意人为输入的内容输出到页面的需要clean,防止xss注入
    • 注意sql注入,连接sql时,要对人为输入的内容clean。

    业务安全:

    • 视具体业务情况做适当的校验

    http缓存机制详解

    强制缓存:没缓存数据时,浏览器向服务器请求数据时,服务器会将数据和缓存规则一并返回,缓存规则信息包含在响应header中

    响应头字段:

    • Expires 服务器端返回的到期时间,下一次请求时,请求时间小于服务端返回的到期时间,直接使用缓存数据
    • Cache-control: private, public, max-age, no-cache, no-store

    from memory cache 使用内存中的缓存(一旦进程关闭,进程的内存会清空) 一般js / pictures
    from disk cache -> page -> from disk cache -> from memory cache 一般css文件

    对比缓存:第一次请求数据,服务器将缓存标识与数据一起返回给客户端(客户端将二者备份至缓存数据库中,再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功,返回304,表示客户端比较成功,可使用缓存数据)。返回header部分,不返回报文主体部分。

    响应头字段:

    • Last-Modified, 对应的请求头If-Modified-Since:Last-modifie服务端响应,告诉浏览器资源最后修改修改时间;If-Modified-Since客户端带上这个头,服务器收到这个头,对比,对比成功,返回304,对比不成功,返回200
    • Etag,对应的请求头If-None-Match:Etag 服务器响应请求时,生成浏览器当前资源在server的唯一标识,nginx1.3自动开启;If-None-Match client带上这个头请求server,对比,如果成功返回304,如果不成功,返回200。

    总结:

    强制缓存和对比缓存同时设置,点刷新,走304,ctrl+f5,走200,普通访问:cache-control生效;如果只设置cache-control,不设置last-modified,手动刷新都是200,报文比较大。

    强制缓存
    对比缓存
    总结
    其他