admin管理员组文章数量:1026989
镀金天空
镀金天空-CSS偏移
前言:
①仅作学习所用,不可非法利用
②网页结构的变化较多,代码的可用周期较短,仅作学习使用
③如有侵权,请联系我删除!!谢谢
正文:
最近我也是找到了一个有趣的网站,这个网站里有很多爬虫相关的练习题,和ACM赛制相似,采用的是在线OJ的方式来进行答案校检。glidedsky中包含了现在大部分网站所采用的反爬技术,难度较市面上书本上的练习题难上一些,油兴趣的朋友可以加我好友一起冲他,hh。
我也是好久没写博客了,最近是毕业季忙于找工作实习QAQ。目前也算是安定下来了,所以恢复计划博客更新,嘿嘿。好了,回归到正题,今天要讲的是glidedsky的一道练习题–CSS偏移,前端工程师总是用他们的奇淫技巧来防止我们采集数据,而我们也在不断地反爬中进步,css偏移就是前端工程师常用于数字(ps:价格、评论数等)的一种反爬手段,之后还会讲到字体反爬–SVG映射。
css有三种基本的布局机制:普通流、浮动和绝对定位。css利用定位可以准确地定义元素框相对于其正常位置应该出现的位置,或者相对于父元素、另一个元素甚至浏览器窗口本身的位置。但元素究竟如何定位,定位到什么位置,主要依靠top/right/bottom/left这四个偏移属性也就是我们常说的上下左右来敲定。
了解到css是作用,那么前端工程师是如何利用css来进行反爬呢?直接看图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r0TwH421-1618643382081)(.png)]
如图所见浏览器显示的数字为182,而Html源码中缺包含了8、1、3、2四个数字,如果说这个让你不解为什么Html源码中有四个数字而浏览器缺只显示了三个数字呢?没有发现什么明显的特征我们看下一个div下的情况:
在这个div中一共包含三个数字:6、3、8三个数字,按顺序应该显示为638,而浏览器中显示的却是386,这是怎么回事呢??这就是css偏移了,前端工程师利用css代码和class将包含数字的div的顺序打乱了,本应显示为638的被偏移为386了。那么我们该如何获取浏览器所显示的数字呢?
这很好理解,我们将div的class所对应的偏移(top/right/bottom/left)想象为一个字典,key为class,偏移量(offset)为value。事实上我也是如此对付css偏移反爬的。那么浏览器最后的显示结果又是如何呈现的呢?我们不妨再大胆一点,将通过css偏移显示的结果想象为一个数组,当传入一个数字和它所对应的class我们就将class传入字典中获取该数字的偏移量,将其写入列表中偏移后的的位置。
选择这种解决方法之后会很容易的想到几个问题:
- 如果有两个数字经过class的偏移之后定位到了相同的index该如何处理呢?当然是不会出现这样的问题啦,如果出现覆盖情况两个数字会叠在一起分辨不清的,为了有更直观的体验修改了Html源码使两个字体出现重叠。效果就像下图一样:
- 数字的位数可以确定吗?确定是固定只有三位数还是四位数?答案是不确定的,这个我们得通过div的大小和字体的大小来判断,如下图所示,一个div的大小为61.5 * 23,而一个字体是1em,浏览器默认1em大小为16px,所以我们可以确定一个div最多容纳3.8个数字,为了显示效果需要舍弃小数,因此基本可以确定一个div最多显示三位数。
- 有没有特殊情况呢?有的,除了偏移之外还有一个特别的关键字before:{content:“182”}。当出现这个content属性时,浏览器会将182覆盖写入到这个div中。如下图的182覆盖了1:
既然理清了思路那么接下来就是将思路转换为代码了~~
代码
import refrom lxml import etreeimport useragentutil
from glidedskyLogin import logindef leftDict(cssText):dictLetf = {}for text in cssText:leftText = re.findall(r'\.(.*)\{(.*):(.*)\}', text.replace(' ', ''))if leftText != []:outkey = leftText[0][0].replace(':before', '')inkey = leftText[0][1]invalue = leftText[0][2]# print(leftText[0][1])if outkey not in dictLetf.keys():dictLetf[outkey] = {}dictLetf[outkey][inkey] = invalue# for var in dictLetf.items():# print(var)return dictLetfdef getRealNum(numDivs, deviation):result = 0for divs in numDivs:# 初始化div索引位置numIndex = 1# 返回字典{'value':'偏移量'}列表resultList = []for div in divs.xpath('./div'):className = div.xpath('./@class')[0]textNum = ''.join(div.xpath('./text()'))numFlag = numIndexdivDict = deviation.get(className)if divDict.get('content'):num1 = divDict.get('content')# print('content', num1)elif divDict.get('left'):num1 = divDict.get('left')# print('left', num1)numFlag += int(num1.replace('em', ''))elif divDict.get('margin-right'):num1 = divDict.get('margin-right')# print('right', num1)numFlag -= int(num1.replace('em', ''))else:passif textNum == '': numFlag = int(eval(num1))resultList.append({'value': textNum, 'offset': numFlag})numIndex += 1# 字典列表按照offset排序resultList = sorted(resultList, key=lambda i: i['offset'])resultStr = ''for var in resultList[-3:]:value = var.get('value')offset = var.get('offset')if value == '':resultStr = str(offset)breakresultStr += str(value)result += int(resultStr)# print(resultStr)return resultdef code(request, url):req = request.get(url, headers=useragentutil.get_headers())tree = etree.HTML(req.text)cssText = ''.join(tree.xpath('/html/head/style[1]/text()')).split('\n')# 格式化CSS偏移量为字典deviation = leftDict(cssText)# 获取数字框tree = etree.HTML(req.text)numDivs = tree.xpath('//div[@class="col-md-1"]')result = getRealNum(numDivs, deviation)return resultif __name__ == '__main__':count = 0request = login()for page in range(1, 1001):targetUrl = f'={page}'result = code(request, targetUrl)print(result)count += resultprint(count)
镀金天空
镀金天空-CSS偏移
前言:
①仅作学习所用,不可非法利用
②网页结构的变化较多,代码的可用周期较短,仅作学习使用
③如有侵权,请联系我删除!!谢谢
正文:
最近我也是找到了一个有趣的网站,这个网站里有很多爬虫相关的练习题,和ACM赛制相似,采用的是在线OJ的方式来进行答案校检。glidedsky中包含了现在大部分网站所采用的反爬技术,难度较市面上书本上的练习题难上一些,油兴趣的朋友可以加我好友一起冲他,hh。
我也是好久没写博客了,最近是毕业季忙于找工作实习QAQ。目前也算是安定下来了,所以恢复计划博客更新,嘿嘿。好了,回归到正题,今天要讲的是glidedsky的一道练习题–CSS偏移,前端工程师总是用他们的奇淫技巧来防止我们采集数据,而我们也在不断地反爬中进步,css偏移就是前端工程师常用于数字(ps:价格、评论数等)的一种反爬手段,之后还会讲到字体反爬–SVG映射。
css有三种基本的布局机制:普通流、浮动和绝对定位。css利用定位可以准确地定义元素框相对于其正常位置应该出现的位置,或者相对于父元素、另一个元素甚至浏览器窗口本身的位置。但元素究竟如何定位,定位到什么位置,主要依靠top/right/bottom/left这四个偏移属性也就是我们常说的上下左右来敲定。
了解到css是作用,那么前端工程师是如何利用css来进行反爬呢?直接看图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r0TwH421-1618643382081)(.png)]
如图所见浏览器显示的数字为182,而Html源码中缺包含了8、1、3、2四个数字,如果说这个让你不解为什么Html源码中有四个数字而浏览器缺只显示了三个数字呢?没有发现什么明显的特征我们看下一个div下的情况:
在这个div中一共包含三个数字:6、3、8三个数字,按顺序应该显示为638,而浏览器中显示的却是386,这是怎么回事呢??这就是css偏移了,前端工程师利用css代码和class将包含数字的div的顺序打乱了,本应显示为638的被偏移为386了。那么我们该如何获取浏览器所显示的数字呢?
这很好理解,我们将div的class所对应的偏移(top/right/bottom/left)想象为一个字典,key为class,偏移量(offset)为value。事实上我也是如此对付css偏移反爬的。那么浏览器最后的显示结果又是如何呈现的呢?我们不妨再大胆一点,将通过css偏移显示的结果想象为一个数组,当传入一个数字和它所对应的class我们就将class传入字典中获取该数字的偏移量,将其写入列表中偏移后的的位置。
选择这种解决方法之后会很容易的想到几个问题:
- 如果有两个数字经过class的偏移之后定位到了相同的index该如何处理呢?当然是不会出现这样的问题啦,如果出现覆盖情况两个数字会叠在一起分辨不清的,为了有更直观的体验修改了Html源码使两个字体出现重叠。效果就像下图一样:
- 数字的位数可以确定吗?确定是固定只有三位数还是四位数?答案是不确定的,这个我们得通过div的大小和字体的大小来判断,如下图所示,一个div的大小为61.5 * 23,而一个字体是1em,浏览器默认1em大小为16px,所以我们可以确定一个div最多容纳3.8个数字,为了显示效果需要舍弃小数,因此基本可以确定一个div最多显示三位数。
- 有没有特殊情况呢?有的,除了偏移之外还有一个特别的关键字before:{content:“182”}。当出现这个content属性时,浏览器会将182覆盖写入到这个div中。如下图的182覆盖了1:
既然理清了思路那么接下来就是将思路转换为代码了~~
代码
import refrom lxml import etreeimport useragentutil
from glidedskyLogin import logindef leftDict(cssText):dictLetf = {}for text in cssText:leftText = re.findall(r'\.(.*)\{(.*):(.*)\}', text.replace(' ', ''))if leftText != []:outkey = leftText[0][0].replace(':before', '')inkey = leftText[0][1]invalue = leftText[0][2]# print(leftText[0][1])if outkey not in dictLetf.keys():dictLetf[outkey] = {}dictLetf[outkey][inkey] = invalue# for var in dictLetf.items():# print(var)return dictLetfdef getRealNum(numDivs, deviation):result = 0for divs in numDivs:# 初始化div索引位置numIndex = 1# 返回字典{'value':'偏移量'}列表resultList = []for div in divs.xpath('./div'):className = div.xpath('./@class')[0]textNum = ''.join(div.xpath('./text()'))numFlag = numIndexdivDict = deviation.get(className)if divDict.get('content'):num1 = divDict.get('content')# print('content', num1)elif divDict.get('left'):num1 = divDict.get('left')# print('left', num1)numFlag += int(num1.replace('em', ''))elif divDict.get('margin-right'):num1 = divDict.get('margin-right')# print('right', num1)numFlag -= int(num1.replace('em', ''))else:passif textNum == '': numFlag = int(eval(num1))resultList.append({'value': textNum, 'offset': numFlag})numIndex += 1# 字典列表按照offset排序resultList = sorted(resultList, key=lambda i: i['offset'])resultStr = ''for var in resultList[-3:]:value = var.get('value')offset = var.get('offset')if value == '':resultStr = str(offset)breakresultStr += str(value)result += int(resultStr)# print(resultStr)return resultdef code(request, url):req = request.get(url, headers=useragentutil.get_headers())tree = etree.HTML(req.text)cssText = ''.join(tree.xpath('/html/head/style[1]/text()')).split('\n')# 格式化CSS偏移量为字典deviation = leftDict(cssText)# 获取数字框tree = etree.HTML(req.text)numDivs = tree.xpath('//div[@class="col-md-1"]')result = getRealNum(numDivs, deviation)return resultif __name__ == '__main__':count = 0request = login()for page in range(1, 1001):targetUrl = f'={page}'result = code(request, targetUrl)print(result)count += resultprint(count)
本文标签: 镀金天空
版权声明:本文标题:镀金天空 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/IT/1694666308a254806.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论