前言

我们都知道,HTTP 协议即超文本传输协议,是 Web 应用的基础,HTTP 协议又是基于 TCP 协议的,而 TCP 连接的建立是需要时间和资源的。当网页加载时,会需要下载图片资源,如果有非常多的小图片,就需要建立很多 TCP 连接。

但勤劳勇敢的前端工作者们,想到把所有小图片放到一张图片里面去,这样就可以通过一次 TCP 连接,下载所有的小图片,再通过前端的奇技淫巧,来展示正确的图片。这种由很多小图片组成的图片,被称为雪碧图,雪碧图在节约 TCP 连接的同时,也为爬取带来了难度。

定义

CSS 雪碧图集 CSS Sprite,也被称为 CSS 精灵,是一种 CSS 图像合成技术,该技术是将小图标和背景图像合成到一张图片中,然后利用 CSS 的背景定位来显示需要显示的图像部分。

CSS 雪碧的基本原理是把你的网站上用到的一些图片整合到一张单独的图片中,然后使用 CSS 中的 background 和 background-position 属性进行渲染,但当图片数量更多更复杂时,定位就需要更加准确,可能就会用到更多的数值来到达更准的定位。

雪碧图的优缺点

通过前面的描述,可以很清楚地知道雪碧图有如下优点:

  • 减少加载网页图片时对服务器的请求次数,降低服务器压力,同时提高了页面的加载速度,节约服务器的流量;
  • 减少图片加载所需要的时间,提高页面的加载速度。

除了上述优点,雪碧图还有一些无法避免的缺点:

  • 雪碧图的最大问题是内存使用,因为雪碧图中会有大量的留白空间;
  • 影响浏览器的缩放功能,如果使用雪碧图的页面缩放了,就需要做一些额外的工作来纠正图片边缘;
  • 拼图维护比较麻烦,无论是拼图合成,还是修改图片,都会很麻烦不便于操作;
  • 使 CSS 的编写变得困难,尤其是当图片数量较多时,会大大增加 CSS 的代码量和复杂度。

破解实例

1、站点分析

该站点的链接为:http://www.glidedsky.com/level/web/crawler-sprite-image-1。 打开网站,打开开发者工具,选择查看网页上的数字,发现这些数字其实都是 div,通过 CSS 来显示图片:

再查看该元素的 CSS 样式,发现除了宽高之外还有 background-position-x 属性,该属性就是用来控制显示的数字。除此之外,我们可以看到 sprite 类里面定义了一个背景图,打开链接后发现这个背景图如下:

每次加载网页时,都会下载类似上图的包含0-9十个数字的背景图,再通过 CSS 样式中的 background-position-x 属性来显示所需要的数字。

2、破解思路

要应对这种使用雪碧图来实现反爬的措施,有如下思路:

1)获取所有 background-position-x 并求对应的数字

因为每个数字对应的 background-position-x 的数值是一样的,所以思路一是获取所有 background-position-x 的数值,再求集合,并根据数值从小到大排列,每个数值就对应一个数字。

但这种思路是有问题的,例如上面的截图中并没有数字0,也就没有数字0对应的位置,这就会导致我们获取到的数据是不完整的,也就无法正确表示了。

2)下载图片,根据 background-position-x 的值进行划分

首先是将图片下载下来,并计算出图片的大小,然后根据从 CSS 样式中获取到的 background-position-x 的数值进行划分,就能得到每个数字对应的位置区间。

但这种思路也无法解决数字不全所带来的问题,尤其是数字是扭曲的,大小也不一样。

3)下载图片,估算每个数字所占的宽度

将图片下载下来,得到图片的宽度,因为每个数字的宽度其实是差不多的,所以我们可以简单地将图片的宽度除以10来估算每个数字的宽度,再用 background-position-x 的值和这个宽度进行整数除法,就能得到对应的数字了。

使用这种方法,即使数字是不全的,也能够计算出来。

破解步骤

1、下载图片

前面已经说过在 sprite 类中指明了背景图片,截图如下:

在上面的 url() 中,data 表示取得数据的协定名称,image/png 是数据类型名称,base64 是数据的编码方法,逗号后面就是这个 image/png 文件 base64 编码后的数据。

使用这种方式就把图像文件的内容直接写在了 HTML 文件中,这样做的好处是,节省了一个 HTTP 请求。

要将这个图片下载下来,首先要做的就是得到这个使用 base64 编码后的数据,可以使用正则表达式进行匹配,然后进行解码,再将图片下载到本地,打开并得到该图片的宽度。

下载 base64 编码图片的代码如下:

 def save_img(img_data):"""save image in local directory:param img_data: image base64 data:return: width of image"""img = base64.urlsafe_b64decode(img_data)filename = "{}.{}".format(uuid.uuid4(), "png")filepath = os.path.join("./Images", filename)with open(filepath, "wb") as f:f.write(img)image = Image.open(filepath)return image.width

2、获取位置-数字字典

我们可以知道 background-position-x 都定义在 CSS 代码中了,要获取所有 background-position-x 的数值,可以使用正则表达式 re 模块中的 findall() 方法进行匹配,使用方法如下:

re.findall(r"background-position-x:-?(\d+)?px", html)

前面已经得到图片宽度了,除以10的结果就可以当做每个数字所占的宽度,再用 background-position-x 的数值和这个宽度进行整数除法,得到的结果就是这个 CSS 所对应的数字。

为了方便后面将数字进行组合,还要转换成 str 形式。

具体代码如下:

 def parse(num_list: list, gap: int):"""translate position to digit:param num_list: number list:param gap: average gap between numbers:return:"""return {str(num): str(int(num // gap)) for num in num_list}

3、获取数字并求和

在示例的网址中有十二个三位数,也就有三十六个数字,我们要做的就是获取每个数字的 CSS 类名,再根据这个类名得到 background-position-x 的数值,再根据前面得到的字典就能得到每个数字,将三个数字组成一个三位数,最后使用 sum() 方法进行求和。

下面就是获取每个数字并进行求和的代码,其中 pos_dict 就是位置和数字对应的字典:

 def get_digits(html, pos_dict):"""get digit according to the class and sum up the numbers:param html: html:param pos_dict: position to digit:return:"""et = etree.HTML(html)pos_classes = et.xpath('//*[@id="app"]/main/div[1]/div/div/div/div/div/@class')digits, d = [], ""for pos in pos_classes:if len(d) == 3:digits.append(d)d = ""pos_x = re.findall(pos.split(" ")[0] + r" { background-position-x:-?(\d+?)px }", html)d = d + pos_dict[pos_x[0]]digits.append(d)result = sum([int(i) for i in digits])print("The result is : {}".format(result))

文源网络,仅供学习之用,如有侵权请联系删除。

在学习Python的道路上肯定会遇见困难,别慌,我这里有一套学习资料,包含40+本电子书,800+个教学视频,涉及Python基础、爬虫、框架、数据分析、机器学习等,不怕你学不会! https://shimo.im/docs/JWCghr8prjCVCxxK/ 《Python学习资料》

关注公众号【Python圈子】,优质文章每日送达。

python大佬教你爬虫反爬:破解雪碧图反爬相关推荐

  1. glidedsky挑战-图片式反爬(雪碧图)

    为了避免某某官方网站,本次记录同样也是 "glidedsky" 网站中的反爬虫题目,只要明白,其它网站理论都差不一样. 相关网站:http://glidedsky.com/leve ...

  2. 【反爬】某网站雪碧图反爬

    想要获取这里的库存值,查看审查元素,发现这里的数字不是文本,而是css渲染出来的 1.随便点一个数字看看css样式呢 2.这里第一个数字1的样式,发现是由图片偏移量得出的 3.查看一下这个svg 4. ...

  3. 猿人学web端爬虫攻防大赛赛题解析_第四题:雪碧图、样式干扰

    第四题:雪碧图 - 样式干扰 1.前言 2.题目理解 3.解析过程 3.1.初窥门径 3.2.深入探究 3.2.1.确定原理 3.2.2.逆向破解 3.2.代码实现 4.结语 1.前言 久违的第四题终 ...

  4. python多张图片合并拼接,python制作sprite图、雪碧图

    python多张图片合并拼接,python制作sprite图.雪碧图 整理图片集 找两个文件夹,yangying和zhaoliying,分别放上照片8张,共16张照片. 创建sprite.py # 多 ...

  5. 一篇文章教你学会如何使用CSS中的雪碧图(CSS Sprite)

    一篇文章教你学会如何使用CSS中的雪碧图(CSS Sprite) 一.什么是雪碧图? 雪碧图(CSS Sprite)又叫CSS精灵图,是一种网页图片应用处理方式,他允许你将一个页面设计到 所有零星图片 ...

  6. 手把手教你用Python搭建IP代理池,轻松破解请求频率限制反爬虫~

    我们所写的爬虫,它对服务器发出的网络请求频率要比正常用户的高的多,从而开发者可以将请求频率过高的用户视为爬虫程序,从而来限制爬虫程序. 今天志斌就来给大家分享一下,如何用Python搭建一个IP代理池 ...

  7. python 北上资金_python爬虫技术:北向资金数据自动爬取!

    好久不见!今天我们继续python的话题啦.python现在势头凶得很,没事刷抖音.刷朋友圈.看公众号,弹出的广告总少不了python."python带你发家致富,财富自由!"广告 ...

  8. 做实验、修电脑、命题相亲……Python大佬教你七夕如何撩妹

    在Google上输入Love,可以搜到12,220,000,000条结果. 关于爱情,中国古诗有"愿得一人心 白首不相离"这样的美句,西方有Love never fails的谚语. ...

  9. python微信公众号爬虫_微信公众号推送信息爬取---python爬虫

    问题描述 利用搜狗的微信搜索抓取指定公众号的最新一条推送,并保存相应的网页至本地. 注意点 搜狗微信获取的地址为临时链接,具有时效性. 公众号为动态网页(JavaScript渲染),使用request ...

最新文章

  1. Java重写equals和hashCode方法
  2. WPF 与Surface 2.0 SDK 亲密接触 - ScatterView 数据绑定篇
  3. ToolBarManager可任意选择你想要的菜单
  4. VHDL电子密码锁设计
  5. 分区式存储管理c++_分区机要变形缝,纵横交接卫浴厨:防火阀参数的高效记忆口诀...
  6. mongodb副本集_设置MongoDB副本集分为4个步骤
  7. 如何限制浏览器使用_论如何优雅地使用chrome 浏览器
  8. 【笔记3】二维码扫码数据埋点
  9. 视觉SLAM十四讲学习笔记-第三讲-旋转矩阵和Eigen库
  10. IIS服务器多站点 的 https证书使用443端口 解决方案
  11. 小程序:版本更新后获取用户信息变更
  12. DBSCAN聚类︱scikit-learn中一种基于密度的聚类方式
  13. 树莓派做服务器装什么系统安装,树莓派 安装 群晖系统安装教程
  14. 使用Visual Studio命令提示查看cad中的重整函数
  15. ROS智能车定位导航仿真(已实现)
  16. 一篇文章带你认识【集线器、网桥、交换机、路由器、网关】
  17. redux的原理、工作流程及其应用
  18. 【讲座】02 写作英文学术论文
  19. 赵小楼《天道》《遥远的救世主》深度解析(93)究竟真理真Xiang的踪迹
  20. 模电笔记4 半导体三极管及放大电路基础

热门文章

  1. 用80行代码数1000个孔——《Python也可以》之四
  2. 全球与中国轨道交通制动闸片市场深度研究分析报告
  3. python编程计算器_python编写计算器功能
  4. Pintech品致静电放电发生器的原理和试验环境要求
  5. Python自动发邮件总结及说明
  6. C语言第11次有道巴巴,C语言上机指导(第11次实验)(附答案).doc
  7. html瀑布流布局原理,css 实现瀑布流布局效果
  8. 遍历字典,以及遍历列表总结
  9. PostgreSQL安装初始化集群失败
  10. go语言接口并发量测试