遇到CSS偏移反爬是不是很头疼?不要慌,手把手教你如何破解。
首先我们先了解一下什么是CSS偏移反爬虫:
CSS偏移反爬虫指的是利用CSS样式将乱序的文字排版为人类正常阅读顺序的行为。当然这么说大家可能还是无法理解,那么为了能够让大家更加清楚的了解什么是CSS偏移反爬虫,在这里直接上图让大家看一下。
大家请看上图中的我圈出来的价格是 ¥950,这个价格正是我们正常浏览时在页面上看到的价格,这里我们按F12,然后在Elements面板中找到这个价格所对应的位置,正常情况下我们应该是直接看到 950 这个价格,或者是按顺序依次看到 ‘9’,‘5’,'0’这三个数字,但是这里竟然有5个数字,而且再仔细一看这5个数字也不是按照规律排列的。这个其实是开发者捣的鬼,他们通过调整CSS的方式将虚假的数据混淆在里面,同时不会影响到用户正常的阅读。这个也就是我今天要为大家讲解的CSS偏移反爬虫。这个时候假如我们什么都不做就去把数据爬下来,按照这种情况我们抓到的数据肯定是’5’,‘9’,‘0’,‘9’,'5’这几个数字,最后肯定会被你的leader骂死。毕竟正常情况下我们一张机票也不可能好几万啊,是不是。
通过上面的一张图我想大家也应该什么是CSS偏移反爬虫,这种情况不会影响到用户正常阅读,但是会对爬虫程序造成极大的困扰,毕竟程序它不会像我们人一样去正常的浏览界面,知道真实的价格是多少。不过不要慌,下面我就为大家介绍如何破解这种反爬。
这里我们多看看几张图,然后分析下这个有没有什么规律。
图一
图二
图三
图四
我们从第一张开始看,价格: 1068,我们再看看 Elements面板中不含有<i>标签的<b>标签中的数字依次是: 0、6、1、8。
然后我们看第二张图,价格: 1539。看不含有<i>标签的<b>标签中的数字是: 1。
第三张图,价格: 950。不含有<i>标签的<b>标签中的数字是: 9、5。
第四张图,价格: 1720。不含有<i>标签的<b>标签中的数字是: 7、1、2。
通过看这个我们是不是发现不含有<i>标签的<b>标签中的数字都是价格中含有的数字。
(为了方便点,这里我统一下, 不含有<i>标签的<b>标签,统一称为<b>标签, 含有<i>标签的<b>标签,我们叫做 i<b>标签好了),如果我们多看几张图也都会有这个共性,那么我们首先可以确定的就是<b>标签中的数字确实是真实价格中所含有的数字。
接下来由于避免图片过多,所以我们只分析第一张图,这次同样是<b>标签中的数字以及我们正常浏览时的价格。我们还是依次从第一张图开始看,这次我们先定位下浏览器中 个十百千位上的数字依次对应哪个<b>标签,先看下面四张图:
(由于是图片,所以这里我用红圈圈出对应的位置以表示我是一 一对应的。)
接下来要说的你们经过多次对比之后是完全可以发现的,这里我找了一张比较全的,并且已经一 一对应起来了,我们看看 <b>标签中的 style , 这里我们只看 style中的 left对应的值。
来张图特写一下:
<b>标签中对应的关系:0:-48px ,6:-32px,1:-64px,8:-16px
这是我们观察到的对应关系,然后我们看看价格 ‘1068’’ ,,
价格中对应的关系:个位:8,十位:6,百位:0,千位:1
大家肯定知道’等量代换’这个词语,这里我们做将得出的两个关系进行等量代换。
个位:-16px,十位:-32px,百位:-48px,千位:-64px
相信我,这里得到的对应关系,只要你们多看几个例子并且对比下就一定能发现 。
我们接着分析,这里再回到上面,看一下不同价格的那几张图,看看图三,这里我是特意放的一个三位数的价格: 950,这里也由于避免图片过多就不再放其他图片进行举例了,我直接讲解如何去分析就好,之后你们自己去找网站对照分析就OK了,我们刚才只看了’不含有<i>标签的<b>标签’,既然如此我们先按照之前得出的,价格对应left的关系: "个位:-16px,十位:-32px,百位:-48px,千位:-64px",先找到 <b>标签(不含<i>标签的<b>标签)中的数字对应价格中 个十百千位中的哪一位。这里我们拿上方价格为: 1539的图片举例,图片如下:
我们观察下,这里的 <b>标签(不含<i>标签的<b>标签)只有一个,然后看到这里<b>标签中 'style里 left的值为:-64px,的数字是 '1’,我们得出这个 '1’是价格中千位上的数字,我们看看来看一看,价格:1539,我们发现这里的千位上的数字正是 '1’,对应关系也就是 , ‘千位’:'1’,既然<b>标签中的答案已经揭晓了,那么我们再来看看<i>标签’是什么情况,这里我们看一下上面几个不同价格的图片,我们能发现,正常浏览显示的是几位数的价格,那么这个<i>标签就有几个(这个规律你们到相关的网站上多看看一定能发现的),这里我们按照正常情况去爬取这个<i>标签的数据,依次爬取到的肯定是 ‘9’、5’、‘3’、'9’,然后我们当做这个数据已经爬下来了来举例,这里就以列表的形式展示出来: [‘9’,5’,‘3’,‘9’],我们知道图片中的价格是1539,这是一个四位数的价格,列表中的也是四位数,同时我们都知道 1539这个价格依次是: 千位、百位、十位、个位来排列的,那么我们列表中也给他按照这样的顺序去排列,并且以列表索引下标的方式来对应,得到对应关系:
千位’:list[0]=‘9’,‘百位’:list[1]=‘5’,‘十位’:list[2]:‘3’,‘个位’:list[3]='9’
这里的对应关系已经出来了,因为我们前面已经确定过<b>标签中所对应的数字肯定是真是价格中的某一个数字,同时也得出了 这里<b>标签中的数字 1是价格中 千位上的数字,我们之前也得到过 1的对应关系, ‘千位’:'1’,然后我们按照程序里的思想,令 list[0]='1’,那么最终得到的列表结果为: [‘1’,5’,‘3’,‘9’]。
我们将这个结果再转换一下就是, 千位:1,百位:5,十位:3,个位:9
我们按正常的读一下是不是就是: 1539。这个结果是不是就是我们正常浏览时看到的结果。
以上就是我们整个 CSS偏移反爬虫破解的过程,下面我再把用代码实现的一个小案例附上:
import requests, re
from lxml import etree
"""
根据观察可以看出:
<b>标签中的都是真实的价格对应的数字,而<i>标签中则混有虚假的价格数字
‘个','十','百','千'所对应的left值依次为:
'个':'left:-16px' '十':'left:-32px' '百':'left:-48px' '千':'left:-64px'
所以只需要拿到<i>标签中的所有数字,然后利用得到的真实价格所对应的数字将<i>标签中虚假的数字替换即可
"""
url = 'http://www.porters.vip/confusion/flight.html'
response = requests.get(url).text
html = etree.HTML(response)
div_list = html.xpath('//div[@class="left col-md-9"]/div')
# 个位:1 十位:2 百位: 3 千位:4
# price_left_seat = {'-16': 1, '-32': 2, '-48': 3, '-64': 4}
for num in range(len(div_list)):
# 先设定一价格为0
price = 0
# 存放价格对应的数字
price_num_list = []
# 先拿到所有<b>标签
b_list = div_list[num].xpath('.//em/b')
# 从第一个<b>标签中获取当前价格是几位数的
fake_price_num_list = b_list[0].xpath('./i/text()')
# -------------先获取真是价格所对应的数字-------------
for index, b in enumerate(b_list[1:]):
# 获取真实价格中所对应的数字
price_num = int(b.xpath('./text()')[0])
# 获取当前价格对应的数字的类名称
style = b.xpath('./@style')[0]
left_value = re.findall('left:(.*?)px', style)[0]
# 根据获得的left值计算该数字在真实价格中的索引位置
price_seat = int(int(left_value) / 16)
# print(price_num, price_seat)
fake_price_num_list[price_seat] = price_num
# 设定一个还原数字各自在价格中对应位置的值
restore_price_num_seak = 1
# 将价格从个位到最高价格位数排列
# reverse() 将列表中的值反转,无返回值。
fake_price_num_list.reverse()
for real_price_num in fake_price_num_list:
price += int(real_price_num) * restore_price_num_seak
restore_price_num_seak *= 10
print('真实价格为:{}'.format(price))
(注意:案例中的网址不是上面图片来源所在的网址,此案例得出的第二个价格和网址上不同,实际上并不是我们的逻辑和代码有错,而是页面显示错误。要注意的是,页面数据显示错误时常发生的事,我们只需要按照正确的逻辑写代码即可。)
欢迎关注公众号:【时光python之旅】 (在这里你能学到我的所见、所闻、所思、所学)
- 点赞
- 收藏
- 关注作者
评论(0)