python进阶之Fraction,pil,Counter,BytesIO,eval妙用......

最近在处理微博的汉字点选验证遇到一些问题,用了之前没用过的包,此处算是记录。另外今后不再写爬虫详细的过程只对新技术做笔记
一PIL也就是pillow 图片处理

#导包
from PIL import Image
#open打开文件返回一个携带通道和size的Image对象
#win上要注意路径后缀,当然写好的绝对路径函数另一说
img=Image.open("G:\spider\platform_demo\\1.png","r")#<PIL.PngImagePlugin.PngImageFile image mode=RGBA size=515x692 at 0x271D3DBE588>
print(im.size,im.format,im.mode,im.format)#对像包含图片的size:宽高,mode:颜色的通道'L'(luminance)表示灰度图像,'RGB'表示真彩图像,'CMYK'表示预先压缩的图像,format返回文件的类型比如png。这个不细说
im.show()#在对图片处理,展示图片
im.save(self, fp, format=None, **params)#存储图片对象,fp:存储的位置,format:保存的文件格式
by_arry = BytesIO()
sad.save(by_arry, format='PNG')#也可以这样写不用写路径了,代码中可以直接使用这个对象

#缩放图,第二个是采样
thumbnail(size,resample=BICUBIC)(创建缩略图)只能缩小,直接改变,按比例缩小
img.resize(size, resample=NEAREST, box=None)可放大可缩小,不改变对象返回新的对象,直接按size缩小

#截图
crop(box)#剪矩形区域的左上角x,y坐标,右下角的x,y坐标,规定图像的最左上角的坐标为原点(0,0),宽度的方向为x轴,高度的方向为y轴,每一个像素代表一个坐标单位
实际用法:#j截取的顺序是固定的,这是验证码的一部分
left,top,right,bottom =int(locations['x'])+10, int(locations['y']), int((locations['x'] + sizes['width']))+10,int((locations['y'] + sizes['height']))
img=screent.crop((left,top,right,bottom))

#旋转图片,某种情况下的验证码是可以用到的
transpose(method)(图像翻转或者旋转)
im.transpose(Image.ROTATE_180)
    - Image.FLIP_LEFT_RIGHT,表示将图像左右翻转
    - Image.FLIP_TOP_BOTTOM,表示将图像上下翻转
    - Image.ROTATE_90,表示将图像逆时针旋转90°
    - Image.ROTATE_180,表示将图像逆时针旋转180°
    - Image.ROTATE_270,表示将图像逆时针旋转270°
    - Image.TRANSPOSE,表示将图像进行转置(相当于顺时针旋转90°)
    - Image.TRANSVERSE,表示将图像进行转置,再水平翻转
 
paste(region,box,mask)(将一个图像粘贴到另一个图像)#im.paste(region,(100,100),None)#好吧这让我想起了opencv。。

split()(颜色通道分离)
 r,g,b = im.split()
 r.show()
 g.show()
 b.show()
 
merge(mode,channels)(颜色通道合并)#im_merge = Image.merge("RGB",[b,r,g])#

convert(mode,matrix,dither,palette,colors)(mode转换)#convert方法可以改变图像的mode,一般是在'RGB'(真彩图)、'L'(灰度图)、'CMYK'(压缩图)之间转换。

#filter方法可以将一些过滤器操作应用于原始图像,比如模糊操作,查找边、角点操作等。filter是过滤器函数,在PIL.ImageFilter函数中定义了大量内置的filter函数,比如BLUR(模糊操作),GaussianBlur(高斯模糊),MedianFilter(中值过滤器),FIND_EDGES(查找边)等
filter(filter)(应用过滤器)###很酷
from PIL import ImageFilter
im_blur = im.filter(ImageFilter.BLUR)
im_find_edges = im.filter(ImageFilter.FIND_EDGES)

point(lut,mode)(对图像像素操作)
im_point = im.point(lambda x:x*1.5)
####其他还有很多模块#############py入门到放弃

我这里对图片处理为了追求缩放比例的精度,引入了分数库
Fraction

分数部分
from fractions import Fraction
#以传入分子和分母(可以是int|float|str|Decimal|Fraction)
Fraction(1, 2)
Fraction(Fraction(1, 2),Fraction(1, 2))#也可以的
#也可以以实例传入
f = Fraction(1, 2)
print(Fraction(f)#1/2实际的返回值是一个约等数方便向下传递
#可以使用一个字符串实例化Fraction类
Fraction('9/16')#9/16这样就更方便了#该字符串以分子/分母的格式出现可以允许两边有空格,但是不允许其他字符包括/只能有一个
可以像对待整数和浮点数一样,在Fraction对象上执行二元运算,进行加减乘除#Fraction(3, 2)最后返回这个,就是最后实际上是一个分数,这样就可以解决python当中除法丢失精度的情况,
当然在幂运算时候会出现精度丢失
Fraction(1, 8) ** Fraction(1, 2)#0.3535533905932738这样直接计算除了对运算是一种影响
解决方案:Fraction(f).limit_denominator()#Fraction(235416, 665857)返回一个近似值的分数,当然这个问题是所有语言都存在的问题,能到这一步很不错了
#以属性的方式访问
Fraction.numerator#分子和Fraction.denominator分母
##偶还有负号最后是放在分子上的Fraction(-2,1)

最大公约数
from fractions import gcd
gcd(100, 75)#25
#不过这个函数应该是要被弃用了,原作者是直接掉了math.gcd

#精确的将float转为分数,说是这么说他只是某种意义上让计算结果更趋近,float本身精度上就有缺失
Fraction.from_float(0.3)#5404319552844595/18014398509481984,它和Fraction(1,3)的意义不同
#精确地将有限的十进制实例转换为有理数。
Fraction.from_decimal(dec)
实际上这两种可能不如:Fraction(f).limit_denominator(max_denominator)#猜想##最接近自我的分数,分母最多为最大分母#原文的阐释谁知道了,应该就是分子分母的位数
Fraction('3.141592653589793').limit_denominator(10)#Fraction(22, 7)
Fraction('3.141592653589793').limit_denominator(100)#Fraction(311, 99)
Fraction(4321, 8765).limit_denominator(10000)#Fraction(4321, 8765)
#################原文的算法,#max_denominator必须是比0大的整数
p0, q0, p1, q1 = 0, 1, 1, 0
n, d = self._numerator, self._denominator
while True:
     a = n//d
     q2 = q0+a*q1
     if q2 > max_denominator:
         break
     p0, q0, p1, q1 = p1, q1, p0+a*p1, q2#关键一步,这种传递方式好吧脑子转不过来。研究的话最好纸上就行
     n, d = d, n-a*d
 k = (max_denominator-q0)//q1
 bound1 = Fraction(p0+k*p1, q0+k*q1)
 bound2 = Fraction(p1, q1)
 if abs(bound2 - self) <= abs(bound1-self):
     return bound2
 else:
     return bound1
其他的魔术方法就算了把

以上了是我在对验证码图片的处理上的一点探索
因为我使用的selenium模拟点 ##这个目前对于行为检测作用不大,在wait方法例可供选择api太多。我又想集成一个api以至能如臂般使用。在下面这种情况下ec的方法可变的,参数by也是可变得那么在这时候大量的判断就无法达到我的想法。我这里使用了eval将字符串对象变成一个函数或对象
wait.until(Ec.element_to_be_clickable((By.CLASS_NAME, ‘geetest_commit’)))
目前我的解决方案,勿喷大佬。这个方案有老哥说耦合太高不易改。

  def wait_select(self,driver,content,ec="element_to_be_clickable",selector="ID"):
        """
        :param ec: ec得函数,在ec_list中可供选择这里只是一个示例#默认节点可点击"element_to_be_clickable"
        :param selector: 选择器得关键词,在selecttor_list可供选择,默认"ID"
        :param content: 提取文本得selector得对应定位字符串
        :return:
        """
        selecttor_list=["XPATH","ID","CLASS_NAME","NAME","LINK_TEXT","CSS_SELECTOR"]
        ec_list=["element_to_be_clickable","presence_of_element_located","presence_of_all_elements_located","title_contains"]
        assert isinstance(selector,str) and isinstance(selector, str),'this selector is not str'
        if selector in selecttor_list and ec in ec_list:
            e,select ="Ec."+str(ec),"By." + str(selector)#如此就可以当成一个对象使用
            wait = WebDriverWait(driver=driver, timeout=20)
            try:
                l=eval("wait.until(" +e+ "((" + select+",'"+content + "')))")
                return l
            except Exception as e:
                print(str(e))
                return False
        else:
            return False
 那么这里就万事大吉了?如果么有这个判断if selector in selecttor_list and ec in ec_list:,这个代码将是不安全的,比如你这么做了刚好别人输入rm-rf   jj我是说类似数据库或者系统环境的接口#某种特殊情况下。所以eval慎用
 ast.literal_eval:#ast模块就是帮助Python应用来处理抽象的语法解析的。而该模块下的 literal_eval() 函数:则会判断需要计算的内容计算后是不是合法的python类型,如果是则进行运算,否则就不进行运算
 ast.literal_eval('1+1')#报错抛异常ValueError: malformed node or string: <_ast.BinOp object at 0x0000026C1C9BE550>
 ast.literal_eval("open(r'D://filename.txt', 'r').read()")#同样
 
 #应该是不带系统性操作都可以尝试了下
f = '''{"isSucess":true, "rm-rf": '[{"name":"yoyo", "status": "200"}]'}'''
f1 = f.replace("true", "True").replace("false", "False").replace("null", "None")
print(ast.literal_eval(f1))#{'isSucess': True, 'rm-rf': '[{"name":"yoyo", "status": "200"}]'}
 
#我这种需求就不行最后改成这样就会报错
import ast
return ast.literal_eval(l)

看了下源码literal_eval这个函数内置检测一些对象,不是这些都会直接抛异常。
所以这个基于业务eval当然灵活点不过用的话一定给定条件。爬虫的时候转内型的时候就要注意最好使用literal_eval,
最起码别人放个rm-rf诸如此类问题应该不大。sql注入这里不太懂可能要从其他方解决

Counter一个快速计数得模块还比较好使,也可以操作dict

from collections import Counter
c = Counter('abcdeabcdabcaba')#Counter({'a': 5, 'b': 4, 'c': 3, 'd': 2, 'e': 1})返回的得实际上是一个字典
c.most_common(3)#[('a', 5), ('b', 4), ('c', 3)]#返回一个列表并按照统计得字符次数大小排序most_common里面的参数是返回几个值,
sorted(c) #['a', 'b', 'c', 'd', 'e']#返回元素中唯一存在得值
sorted(c.elements()))#对元素中重复的值按照字符顺序排序#['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'e']
#sum(c.values())对元素中值的个数求和,##不是len
c['a'] 返回元素中某一个元素的计数
# 把'shazam'中所有的元素加入到c中并重新计数
for elem in 'shazam':
    print(c[elem])
    c[elem] += 1
print(c)#Counter({'a': 7, 'b': 4, 'c': 3, 'd': 2, 'e': 1, 's': 1, 'h': 1, 'z': 1, 'm': 1})
del c['b']  删除一个元素
#修改c相当于合并c,d重新统计
d = Counter('simsalabim')
c.update(d)
c.clear() #清空计数器
c['b'] -= 2 #减少某个值的计数

c.subtract('ah')
print(c)#减去c中某个元素的计数不存在的从0开始计数,#Counter({'a': 4, 'b': 4, 'c': 3, 'd': 2, 'e': 1, 'h': -1})

嗯差不多了

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值