了解熟悉雪碧图反爬策略
一、审查
二、分析 通过观察雪碧图,发现数字有大有小,那么是否有不一样的逻辑呢 小数字处理 大数字处理
首先,我们知道css限定了宽高, 通过观察,发现高相同为15px, 那么如何才能表现为大呢, 那么只有宽数值越大,字体显示越大三、汇总
1.源网页请求 2.获取css链接 3.正则提取所有类及宽高位置信息 4.雪碧图的值是固定的为0-9,本地赋值就可以 5.雪碧图区别在大小数字不同,但是以分析的逻辑进行处理可以映射为正确的数值 if 高-宽>1: 小数字处理逻辑 else: 大数字处理逻辑上面的思路一,在实际操作中发现存在特殊情况,映射错误,那么就有了思路二
一、审查
参考思路一:审查二、分析
已知情况分析: 1.雪碧图固定数字:0123456789 2.css中的类映射数字 3.pox值表示位置 由此,有一个猜想,多个css类映射同一pox值,pox值与雪碧图数字一一映射 那么,只需要构建好pox值与雪碧图一一映射关系就好发现规律,随之数字的增大,pox值也随之增大(负的) 猜想,获取所有的pox值,进行排序,那么pox值下标则一一映射为数字
正则提取,进行去重,及排序后如图所示
经过验证,发现是可行的,实现pox值与数字的一一映射,多个页面检测均无误 这里是正常的理想情况: 获取pox值列表,有10个元素,分别对应0-9十个数字 映射思路: 1.获取一个去重,排序,元素数量为10的列表,如上图所示 2.查询pox值在列表的下标 3.下标的值即为映射的值 猜想,另一种情况, 页面中只用7个数字进行拼接,那么只能获取7个pox值, 那么这个时候,通过pox值下标映射数字的方法就不可用了,中间有断档 无法获取7的pox值, 那么利用列表查找pox元素获取index,index值就是pox映射值的思路就会映射错误 列表元素9个,丢失1个 如果按照以往的思路进行映射 1.查找-104pox值下标 2.-104的下标为7,即映射为7 但实际上在前面缺失一个值,即7的pox值 结果造成-104映射8变成7 解决:7的pox值在数字映射中没有出现,也代表没什么用,可以为任意值, 需要作的就是添加一个pox,用于占位,占住index为7的地方,那么就可以构成一一映射 那么解决思路如下: 1.通过规律观察,列表前一个-后一个的数值<15,则表示正常连续,无中断 2.列表前一个-后一个数值>15,则表示中断, 3.那么就在此处添加占位pox值,pox值为前一值-15 那么可以了,又可以实现一一映射三、汇总
1.请求源网页 2.正则提取所有pox值 3.pox值去重排序列表 4.pox列表中断检测及处理 5.提取所有css类 6.实现:类-pox-index的映射一、审查
参考思路一
二、分析
参考思路二
三、图片的解码与保存
def base64_image(self): '图片的解密与保存' base_png = re.findall(';base64,(.*?)"', self.html, re.S)[0] b = base64.b64decode(base_png) # base64解密,保存为本地图片 with open('59.png', 'wb') as f: f.write(b) img = cv2.imread("59.png") w = img.shape # 图片的属性 self.height = w[0] # 高度 self.width = w[1] # 宽度四、图片切割
依据中断处的postion值,进行图片切割,即传入的cutwidth值
def pngcut(self,cutwidth): '图片切割' img = cv2.imread("59.png") # 要被切割的开始的像素的高度值 beH = 0 # 要被切割的结束的像素的高度值 hEnd = self.height # 要被切割的开始的像素的宽度值 beW = cutwidth # 要被切割的结束的像素的宽度值 wLen = self.width # 对图片进行切割 dstImg = img[beH:hEnd, beW:wLen] cv.imwrite("60.png", dstImg)五、OCR识别
这里使用的百度AI开发者平台提供的文字识别API,大家可自行百度
def baidu_api(self): """定义常量""" # time.sleep() time.sleep(2) APP_ID = '22847322' API_KEY = 'xxxxxxxxx' SECRET_KEY = 'xxxxxxx' """初始化对象""" client = AipOcr(APP_ID, API_KEY, SECRET_KEY) """读取图片""" from os import path # 保存在本地的图片路径 images = path.join(path.dirname(path.abspath(__file__)), '60.png') image = self.get_file_content(images) """调用通用文字识别接口, 识别本地图像""" try: # result = client.webImage(image) #网络图片识别 result = client.basicGeneral(image) #通用文字识别 # result = client.numbers(image) #数字识别 print(result) mum_list = result['words_result'][0]['words'] return int(mum_list[0]) except Exception as e: print(e) if 'Open api qps request limit reached' in str(e): return self.baidu_api()六、汇总
1.请求源网页 2.正则提取源网页中图片字符并进行解码与保存本地 3.正则提取所有pox值 4.pox值去重排序列表 4.pox列表中断检测及处理(使用OCR) 5.构建postion-值的字典 6.提取所有css类 7.实现:类-postion-值的映射 8.累加计数七、验证
八、源码
应网站维护者要求,可提供思路,部分关键代码,禁止源码