破解滑块验证码(geetest极验)

破解滑块验证码(geetest极验) 最近写爬虫遇到极验(geetest)的滑块验证码,首先想到的是用Selenium模拟人拖动滑块,那么问题来了其实主要解决下面两个问题 拖动的距离是多少 怎么模拟出像人一样再滑动 滑动距离 先来解决第一个问题,我们怎么计算拖动距离,打开chrome的审查元素查看需要拖动的图片 <div class="geetest_canvas_img geetest_absolute" style="display: block;"> <div class="geetest_slicebg geetest_absolute"> <canvas class="geetest_canvas_bg geetest_absolute" height="160" width="260"></canvas> <canvas class="geetest_canvas_slice geetest_absolute" width="260" height="160"></canvas> </div> <canvas class="geetest_canvas_fullbg geetest_fade geetest_absolute" height="160" width="260" style="display: none;"></canvas> </div> 发现有三个canvas 对应三张图片大小都是 260* 160 ,我们使用selenium执行 js 转成 base64 后再转成图片都保存下来看一下,第一张 geetest_canvas_bg 是有缺口的图片 im_bg_b64 = driver.execute_script( 'return document.getElementsByClassName("geetest_canvas_bg geetest_absolute")[0].toDataURL("image/png");') # base64 encoded image im_bg_b64 = im_bg_b64.split(',')[-1] im_bg_bytes = base64.b64decode(im_bg_b64) with open('./temp_bg.png', 'wb') as f: f.write(im_bg_bytes) 然后第二张 geetest_canvas_slice 根据上面相同的方法保存到本地是这样的,就是一个滑块 第三张 geetest_canvas_fullbg 猜名称也能猜到是图片的全景 有上面三张图片,怎么计算滑动的距离呢,发现只要找到第一张缺口的位置坐标 x1 和第二张滑块的坐标 x2 那么 x1 - x2 就是我们要的距离,主要是找到 x1 的位置可以通过对比第一张和第三张得到,具体的方法是对比两张图像素点不同时即为 x1 的位置。因为 x2 的位置一直在左边差不多固定的位置假设离最左边为 10 个像素所以我们不需要计算 x2,以下是实现两张图片确定 x1 的代码,图片处理使用的是pillow库 ...

May 5, 2021 · 3 min · 579 words · Fython

Flask项目中集成Celery

Flask项目中集成Celery Celery是一个简单高效的实时分布式任务队列系统,我们可以将一些耗时比较长或者计算密集的任务交给celery处理,它也支持定时任务类似于crontab。而web应用中可以将一些任务丢给celery异步处理,比如发邮件消息推送、模型推理等。简单的Flask应用集成Celery比简单,有官方文档可做参考,可较复杂的flask应用如使用了蓝图(blueprint)分了很多模块的怎么组织celery和各种任务就比较复杂官方也没有说明文档,一不小心就会陷入循环导入。下面就介绍一种celery集成方法。 官方文档demo中有一个make_celery的函数 def make_celery(app): celery = Celery( app.import_name, backend=app.config['CELERY_RESULT_BACKEND'], broker=app.config['CELERY_BROKER_URL'] ) celery.conf.update(app.config) class ContextTask(celery.Task): def __call__(self, *args, **kwargs): with app.app_context(): return self.run(*args, **kwargs) celery.Task = ContextTask return celery 这个函数主要用来创建Celery对象,并从flask上更新一些配置加入上下文环境,像文档上单文件是不会出问题的返回的celery对象直接在下面定义任务,然后集成到路由中。如果你flask app是使用app factories和蓝图(blueprint),那在这里定义的task又怎么在路由中引用呢,这就会导致循环引用问题。 我们可以把make_celery拆开来,首先创建celery对象然后等flask app初始化完成后在更新配置,这就解决问题了,任务单独放在tasks.py文件中也便于管理和查看 先来看最终项目结构图,就是flask web项目加入了celery flask-celery-demo ├── app │ ├── api │ │ ├── __init__.py │ │ └── views.py # 视图 │ ├── __init__.py │ └── tasks.py # celery任务 ├── config.py ├── requirements.txt ├── run.sh └── service.py # 应用入口 先解释下主要service.py创建celery对象,然后把对象传入app/__init__.py文件中的create_app函数在里面更新celery配置。app/tasks.py单独存放给celery的任务,视图函数也可以方便导入。下面一个个文件说明 先来看service.py文件也是整个应用的主入口 from app import create_app def make_celery(app_name): broker = getattr(config[os.getenv('FLASK_ENV') or 'default'], "CELERY_BROKER_URL") backend = getattr(config[os.getenv('FLASK_ENV') or 'default'], "CELERY_BACKEND_URL") celery = Celery( app_name, broker=broker, backend=backend ) return celery # share celery object my_celery = make_celery(__name__) flask_app = create_app(os.getenv('FLASK_ENV') or 'default', celery=my_celery) 这里的make_celery函数只返回celery对象未更新配置,供tasks.py导入,并传给create_app,接下来看app/__init__.py文件 ...

May 24, 2020 · 2 min · 238 words · Fython

通过谷歌gRPC部署线上机器学习模型

通过谷歌gRPC部署线上机器学习模型 gRPC是谷歌开发的远程过程调用(RPC)系统,它使用HTTP/2通信,Protocol Buffer作为接口描述语言。分为服务端和客户端,跨平台不受语言限制。 本文主要在http服务中(以下代码使用的是flask),使用gPRC Python远程调用训练好的模型返回RESTful接口,机器学习模型是一个已训练好的人脸检测模型(mtcnn)作为演示。 所有源码托管在github,可按需要查看获取,下文只列出部分主要的代码提供一些思路。 Proto定义 使用gRPC必须先使用protocol buffers定义序列化的结构包括各对象、服务等所有类型,之后通过grpcio-tools生成服务端和客户端可用的代码,使用proto3格式。首先定义存放图片的Image用于请求参数,也就是入参是一张图片 // request image message Image { bytes raw_data = 1; int32 height = 2; int32 width = 3; string image_id = 4; MetaData _meta_data = 5; } message Image定义了单张图片的存放格式主要包括raw_data存放图片二进制,还有图片的长高和唯一id,_meta_data记录各种元数据具体实现可查看上面github源码infer.proto // each message Result message Result { Box box = 1; Landmarks landmarks = 2; double confidence = 3; } // return results message InferResults { string image_id = 1; MetaData _meta_data = 2; repeated Result results = 3; } message Result定义单张人脸格式每张人脸包括bounding box人脸框,landmarks5个点和置信度confidence,message InferResults定义了单张图上所有人脸和各种元数据。 // run inference service Inference { rpc Predict (Image) returns (InferResults) {} } service Inference定义了一个最简单的服务,输入一张图片输出是包含所有人脸信息的InferResults,就像一个函数调用一样,gRPC还支持复杂的服务比如streaming。 protobuf的具体格式可以查看谷歌官网介绍 定义完.proto文件后就可以生成客户端和服务端可用的接口了,需要安装grpcio-tools包。 python3 -m grpc_tools.protoc \ -I ./protos \ --python_out=./protos \ --grpc_python_out=./protos \ ./protos/infer.proto 以上命令会生成infer_pb2.py和infer_pb2_grpc.py两个文件。 infer_pb2.py中包含了我们在proto文件中定义的所有以message开头的类型,每个都是一个python类 infer_pb2_grpc.py中包含了在proto文件中以service开头的类型,包括服务端需要引用...Servicer的类重写方法,下文重写了Predict方法,add_...Servicer_to_server也是在服务端需要添加服务到grpc.Server,...Stub类是客户端需要导入的类与服务端交互。 加载模型启动gRPC服务 服务端主要是继承上文生成的infer_pb2_grpc.py中的InferenceServicer重写在infer.proto中定义的Predict方法,返回指定的类型也就是InferResults。 ...

December 31, 2019 · 3 min · 517 words · Fython

Python描述符(descriptor)

Python 描述符(descriptor) Python 中有一个很少被使用或者用户自定义的特性,那就是描述符(descriptor),但它是@property, @classmethod, @staticmethod和super的底层实现机制,我今天就扒一扒它,官方文档对描述符的介绍如下 In general, a descriptor is an object attribute with “binding behavior”, one whose attribute access has been overridden by methods in the descriptor protocol: __get__(), __set__(), and __delete__(). If any of those methods are defined for an object, it is said to be a descriptor. 描述符是绑定了行为的对象属性(object attribute),实现了描述符协议(descriptor protocol),描述符协议就是定义了__get__(),__set__(),__delete__()中的一个或者多个方法,将描述符对象作为其他对象的属性进行访问时,就会产生一些特殊的效果。 上面的定义可能还是有些晦涩,一步步来 默认查找属性 在没有描述符定义情况下,我们访问属性的顺序如下,以a.x为例 查找实例字典里的属性就是a.__dict__['x']有就返回 往上查找父类的字典就是a.__class__.__dict__['x']有就返回 上面都没有就查找父类的基类(不包括元类(metaclass)) 如果定义了__getattr__就会返回此方法 最后都没有抛出AttributeError >>> class A: ... x = 8 ... ... >>> class B(A): ... pass ... >>> class C(B): ... def __getattr__(self, name): ... if name == 'y': ... print("call getattr method") ... else: ... raise AttributeError ... ... ... >>> C.__mro__ (<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>) >>> a = C() >>> a.x 8 >>> a.y call getattr method >>> a.__dict__ {} >>> a.x = 99 >>> a.x 99 >>> a.__dict__ {'x': 99} __getattr__是实例访问没有定义的属性时调用的方法,需要特别定义 ...

December 17, 2019 · 6 min · 1135 words · Fython

Python实现单例(Singleton)的几种方法

Python实现单例(Singleton)的几种方法 单例是一种比较简单的设计模式,每次实例化只提供一个相同的实例对象,对于保证实例唯一和节约系统资源的时候十分有用,下面就看看python中实现单例的几种方法 使用__new__方法 因为在类的实例化过程中__new__方法会比__init__提前调用,我们在类属性中保存一个_singleton每次只返回这个。 class Singleton: def __new__(cls, *args, **kwargs): if not getattr(cls, '_singleton', None): cls._singleton = super().__new__(cls, *args, **kwargs) return cls._singleton class MyClass(Singleton): pass a = MyClass() b = MyClass() print(id(a)) # 4433117872 print(id(b)) # 4433117872 print(a is b) # True 使用装饰器 from functools import wraps def singleton(cls): _singleton = {} @wraps(cls) def wrapper(*args, **kwargs): if not _singleton.get(cls): _singleton[cls] = cls(*args, **kwargs) return _singleton[cls] return wrapper @singleton class MyClass: pass 利用装饰器中的_singleton变量存储所有类的实例 利用python模块 python模块(module)是天然的单例模式 # singleton.py class Singleton: def foo(self): print("I'm singleton") instance = Singleton() del Singleton 然后利用模块导入 from single import instance instance.foo() # I'm singleton

February 27, 2019 · 1 min · 96 words · Fython