前言我们都知道HTTP协议是超文本传输??协议,是Web应用的基础。HTTP协议是建立在TCP协议之上的,TCP连接的建立需要时间和资源。加载网页时,需要下载图片资源。如果有很多小图像,则需要建立许多TCP连接。但是勤劳勇敢的前端工作者想到了把所有的小图都放到一张图里,这样就可以通过一个TCP连接把所有的小图下载下来,然后利用前端的技巧来显示正确的图片。这种由许多小图片组成的图片称为精灵图片。sprite图片在节省TCP连接数的同时,也给抓取带来了难度。定义CSSSprite图集CSSSprite,也称为CSSsprite,是一种CSS图片合成技术,就是将小图标和背景图片合成为一张图片,然后使用CSS背景定位来显示需要显示的图片部分。CSSSprite的基本原理是将你网站上使用的一些图片整合成一张图片,然后利用CSS中的background和background-position属性进行渲染,但是当图片数量越来越多的时候,定位就很麻烦了需要更准确,可能会用到更多的值来实现更准确的定位。spritemap的优缺点通过前面的描述可以清楚的知道spritemap有以下优点:减少加载网页图片时对服务器的请求次数,减轻服务器压力,提高页面加载速度,节省服务器流量;减少图片加载的时间,提高页面的加载速度。除了以上优点,精灵图还有一些无法避免的缺点:精灵图最大的问题是内存占用,因为精灵图会有大量的空白;会影响浏览器的缩放功能,如果使用sprite图片的页面被缩放,需要做一些额外的工作来修正图片的边缘;拼图的维护比较麻烦,无论是拼图构图还是修改图片,操作起来都会很麻烦,不方便;使得CSS的编写变得困难,尤其是图片数量较多的时候,会大大增加CSS的代码量和复杂度。破解实例1.站点分析该站点的链接是:http://www.glidedsky.com/leve....打开网站,打开开发者工具,选择查看网页上的数字,发现这些数字其实就是div,通过CSS显示图片:然后查看元素的CSS样式,发现除了width和height还有background-position-x属性,用来控制显示的数字。另外,我们可以看到精灵类中定义了一张背景图片。打开链接后,我们发现背景图是这样的:每加载一个网页,就会下载一张与上图类似的包含0到9十个数字的背景图。然后使用CSS样式中的background-position-x属性来显示需要的数字。2、破解思路针对这种使用Sprite图片的防爬措施,有以下思路:1)获取所有的background-position-x,并找到对应的数字,因为每一个对应的background-position-x的值number是一样的,所以第一个思路是获取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编码图片的代码如下:defsave_img(img_data):"""saveimageinlocaldirectory:paramimg_data:imagebase64data:return:widthofimage"""img=base64.urlsafe_b64decode(img_data)filename="{}.{}".format(uuid.uuid4(),"png")filepath=os.path.join("./Images",filename)withopen(filepath,"wb")asf:f.write(img)image=Image.open(filepath)返回image.width2。获取位置-数字字典。我们可以知道background-position-x是在CSS代码中定义的。获取background-position-x的所有值,可以使用正则表达式re模块中的findall()方法进行匹配,使用方法如下:re.findall(r"background-position-x:-?(\d+)?px",html)之前已经得到了图片的宽度,除以10的结果可以看作是每个数字占用的宽度,然后使用background-position的值-x以这个宽度进行整数除法,得到的结果就是css对应的数字。为了方便后面数字的组合,也转成str形式。具体代码如下:defparse(num_list:list,gap:int):"""translatepositiontodigit:paramnum_list:numberlist:paramgap:averagegapbetweennumbers:return:"""return{str(num):str(int(num//gap))fornuminnum_list}3.获取数字并对它们求和。例子的URL中有十二个三位数,所以一共有三十六个数字。我们要做的就是获取每个数字的CSS类名,然后根据这个类名获取background-position-x的值,然后根据前面获取的字典获取每个数字,将三个数字组合成一个三位数,最后用sum()方法求和。下面是获取每个数字并求和的代码,其中pos_dict是位置和数字对应的字典:defget_digits(html,pos_dict):"""根据类别获取数字并求和:paramhtml:html:parampos_dict:数字位置:return:"""et=etree.HTML(html)pos_classes=et.xpath('//*[@id="app"]/main/div[1]/div/div/div/div/div/@class')digits,d=[],""forposinpos_classes:iflen(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)foriindigits])print("结果为:{}".format(result))文源网络,仅供学习,如有请联系删除侵权。学习Python的路上肯定会遇到困难,不要慌张,我这里有一套学习资料,包括40+电子书,800+教学视频,涉及Python基础、爬虫、框架、数据分析、机学习等等,别怕你学不会!https://shimo.im/docs/JWCghr8...《Python学习资料》关注公众号【蟒圈】,每日优质文章推送。
