网址:http://www.porters.vip/confusion/food.html

打开开发者工具后

页面源码并不是真实的数字,随便点一个d标签查看其样式

我们需要找到两个文件,food.css和food.svg文件,点开第一个红框会在Sources面板打开该文件,鼠标放到food.css文件名上,显示的就是food.css的地址

鼠标放到第二个红框的url上面,得到的就是food.svg的地址,也可以右键Copy link address获取地址

svg_url = 'http://www.porters.vip/confusion/font/food.svg'
css_url = 'http://www.porters.vip/confusion/css/food.css'

这里我们打开svg的地址后是这样的

我们会看到四行毫无规律的数字,查看源码发现又是一堆看着像加密的代码(其实不是,这里是svg-font的坐标)

然后打开css文件

这里的background的css渲染数字的坐标

到此,需要解释一下为什么会有两个坐标,及字符定位的问题:

浏览器根据css样式中设定的坐标和元素宽高来确定svg中对应的数字。

接下来我们就只获取下面图中的电话号码

因为获取d标签的class属性比较容易,这里就简单构造一个电话号SVG列表

获取svg文件和css文件,以及构造电话号svg列表(这里比较简单,没什么解释的)

def get_file(url):
resp = requests.get(url=url)
content = resp.text
return content svg_url = 'http://www.porters.vip/confusion/font/food.svg'
css_url = 'http://www.porters.vip/confusion/css/food.css'
css_content = get_file(css_url)
svg_content = get_file(svg_url) # 获取源码中电话号的SVG列表
svg_list = ['vhkbvu', 'vhk08k', 'vhk08k', 'vhk84t', 'vhk6zl', 'vhkqsc', 'vhkqsc', 'vhk6zl']
for svg_name in svg_list:
  print(svg_name)
  ...

在上一步,我们已经可以通过循环拿到每一个svg_name,接下来就是通过正则获取css文本中,对应的svg_name的样式(坐标)

def get_css_coordinates(css_content, svg_name):
res = re.findall('\.%s\s{\s+background:\s-(\d+)px\s-(\d+)px;\s}' % svg_name, css_content)
if bool(res):
x, y = res[0]
     return (int(x), int(y))

得到css_x和css_y坐标后,拿着css_y坐标去定位上面svg文件中四行数字,获取css_x,css_y坐标对应的数字

from parsel import Selector
def get_svg_text_content(svg_content, css_y):
# 获取svg中字符的font-size属性,后面会用到
font_size = svg_content.split('font-size:')[1].split('px;')[0]
svg_data = Selector(svg_content)
# 获取svg文件 text元素的y属性列表
svg_y_list = svg_data.xpath('//text/@y').getall()
# 取到大于css_y且最近的一个
new_svg_y_list = [svg_y for svg_y in svg_y_list if css_y <= int(svg_y)]
# print(new_svg_y_list[0])
# 获取目标svg_y在原svg_y_list中的下标
index = svg_y_list.index(new_svg_y_list[0])
# print(svg_data.xpath('//text/text()').getall())
text_content = svg_data.xpath('//text/text()').getall()[index]
return text_content, font_size

解释一下,在上面所示代码中,在电话号svg列表中第一个元素vhkbvu,对应的css_y的值为97,而我们获得的svg_y_list为 ['38', '83', '120', '164'],在此列表大于97且最近接的就是120,

因此我们确定svg_y的值为120,同时也确定了我们需要的是第三行数据,通过svg_y,也就是纵坐标的值已经确定

现在我们获取到了text_content为:671260781104096663000892328440489239185923,也就是上图中的第三个text标签中的文本,而font-size为14px

font-size也可以打开svg文件后找到style,查看里面font-size的值

下面我们来确定横坐标,横坐标确定后,我们就可以找到具体的数字值,从而完成破解

def get_char(text_content, css_x, font_size):
text_chars = list(text_content)
# 利用x轴的坐标确定是第几个元素
n = css_x // int(font_size)
print(text_chars[n])
return text_chars[n]

至此,我们的svg反爬破解完成,下面是完整代码

import requests
import re
from parsel import Selector def get_file(url):
resp = requests.get(url=url)
# print(resp.text)
content = resp.text
return content def get_css_coordinates(css_content, svg_name):
res = re.findall('\.%s\s{\s+background:\s-(\d+)px\s-(\d+)px;\s}' % svg_name, css_content)
if bool(res):
x, y = res[0]
return (int(x), int(y)) def get_svg_text_content(svg_content, css_y):
# 获取svg中字符的font-size属性,后面会用到
font_size = svg_content.split('font-size:')[1].split('px;')[0]
svg_data = Selector(svg_content)
# 获取svg文件 text元素的y属性列表
svg_y_list = svg_data.xpath('//text/@y').getall()
# 取到大于css_y且最近的一个
new_svg_y_list = [svg_y for svg_y in svg_y_list if css_y <= int(svg_y)]
# print(new_svg_y_list[0])
# 获取目标svg_y在原svg_y_list中的下标
index = svg_y_list.index(new_svg_y_list[0])
# print(svg_data.xpath('//text/text()').getall())
text_content = svg_data.xpath('//text/text()').getall()[index]
return text_content, font_size def get_char(text_content, css_x, font_size):
text_chars = list(text_content)
# 利用x轴的坐标确定是第几个元素
n = css_x // int(font_size)
print(text_chars[n])
return text_chars[n] def get_phone():
result = ''
svg_url = 'http://www.porters.vip/confusion/font/food.svg'
css_url = 'http://www.porters.vip/confusion/css/food.css'
css_content = get_file(css_url)
svg_content = get_file(svg_url) # 获取源码中电话号的SVG列表
svg_list = ['vhkbvu', 'vhk08k', 'vhk08k', 'vhk84t', 'vhk6zl', 'vhkqsc', 'vhkqsc', 'vhk6zl']
for svg_name in svg_list:
coordinate = get_css_coordinates(css_content, svg_name)
if coordinate is not None:
css_x, css_y = coordinate
print(css_x, css_y)
text_content, font_size = get_svg_text_content(svg_content, css_y)
num = get_char(text_content, css_x, font_size)
result += num
print(result) if __name__ == '__main__':
get_phone()

最后说明:此案例只是我在学习《Python3反爬虫原理与绕过实战》里面svg反爬的学习心得以及实践,供参考,不喜勿喷

记一次svg反爬学习的更多相关文章

  1. 字体反爬--css+svg反爬

    这个验证码很恶心,手速非常快才能通过.. 地址:http://www.dianping.com/shop/9964442 检查一下看到好多字没有了,替代的是<x class="xxx& ...

  2. 记一次CSS反爬

    目标网址:猫眼电影 主要流程 爬取每一个电影所对应的url 爬取具体电影所对应的源码 解析源码,并下载所对应的字体 使用 fontTools 绘制所对应的数字 运用机器学习的方法识别对应的数字 在源码 ...

  3. js反爬学习(一)谷歌镜像

    1. url:https://ac.scmor.com/ 2. target:如下链接 3. 过程分析: 3.1 打开chrome调试,进行元素分析.随便定位一个“现在访问” 3.2 链接不是直接挂在 ...

  4. 记一次css字体反爬

    前段时间在看css反爬的时候,发现很多网站都做了css反爬,比如,设置字体反爬的(58同城租房版块,实习僧招聘https://www.shixiseng.com/等)设置雪碧图反爬的(自如租房http ...

  5. Python爬虫入门教程 63-100 Python字体反爬之一,没办法,这个必须写,反爬第3篇

    背景交代 在反爬圈子的一个大类,涉及的网站其实蛮多的,目前比较常被爬虫coder欺负的网站,猫眼影视,汽车之家,大众点评,58同城,天眼查......还是蛮多的,技术高手千千万,总有五花八门的反爬技术 ...

  6. 【Python3爬虫】大众点评爬虫(破解CSS反爬)

    本次爬虫的爬取目标是大众点评上的一些店铺的店铺名称.推荐菜和评分信息. 一.页面分析 进入大众点评,然后选择美食(http://www.dianping.com/wuhan/ch10),可以看到一页有 ...

  7. k 近邻算法解决字体反爬手段|效果非常好

    字体反爬,是一种利用 CSS 特性和浏览器渲染规则实现的反爬虫手段.其高明之处在于,就算借助(Selenium 套件.Puppeteer 和 Splash)等渲染工具也无法拿到真实的文字内容. 这种反 ...

  8. 【Python必学】Python爬虫反爬策略你肯定不会吧?

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 正文 Python爬虫反爬策略三部曲,拥有这三步曲就可以在爬虫界立足了: ...

  9. 破解另一家网站的反爬机制 & HMAC 算法

    零.写在前面 本文涉及的反爬技术,仅供个人技术学习,禁止并做到: 干扰被访问网站的正常运行 抓取受到法律保护的特定类型的数据或信息 搜集到的数据禁止传播.交给第三方使用.或者牟利 如有可能,在爬到数据 ...

随机推荐

  1. [USACO11JAN]Roads and Planes G【缩点+Dij+拓补排序】

    题目 Farmer John正在一个新的销售区域对他的牛奶销售方案进行调查.他想把牛奶送到T个城镇 (1 <= T <= 25,000),编号为1T.这些城镇之间通过R条道路 (1 < ...

  2. Js数据类型、Json格式、Json对象、Json字符串

    数据类型,从结构上看,所有的数据最终都可以分成三种类型: 第一种类型是scalar(标量),也就是一个单独的string(字符串)或数字(numbers),比如“北京”这个单独的词. 第二种类型是se ...

  3. jQuery动态生成<select>下拉框

    前一阵在项目里需要动态生成下拉框,找了一下用jQuery实现比较方便,这里整理一下. 下文所述方法只是本人在项目中遇到问题的解决方法,场景较为简单,也希望能帮助有需要的朋友 1.动态生成下拉框的两种方 ...

  4. 带你认识网站图片img懒加载和预加载的区别

    懒加载 什么是懒加载? 懒加载也就是延迟加载.当访问一个页面的时候,先把img元素或是其他元素的背景图片路径替换成一张大小为1*1px图片的路径(这样就只需请求一次,俗称占位图),只有当图片出现在浏览 ...

  5. Blazor带我重玩前端(二)

    概览 Blazor目前有两种托管模式,一种是Server-Side模式,一种是WebAssembly模式.官方首先支持的是Service-Side模式,使用WebAssembly模式,需要更新到最新版 ...

  6. OldTrafford after 102 days

    THE RED GO MARCHING ON   One Team One Love Through the highs and the lows   One hundred and two long ...

  7. Github Actions简单部署一个vue/react项目

    大体介绍 本文对github actions部署前端项目做一个简单的总结,总体来说,我感觉用它想要部署一个前端项目,可以说非常简单,简单得令人震惊

  8. day13 作业

    目录 1.编写文件修改功能,调用函数时,传入三个参数(修改的文件路径,要修改的内容,修改后的内容)既可完成文件的修改 2.编写tail工具 3.编写登录功能 4.编写注册功能 选做题:编写ATM程序实 ...

  9. cas客户端流程详解(源码解析)--单点登录

    博主之前一直使用了cas客户端进行用户的单点登录操作,决定进行源码分析来看cas的整个流程,以便以后出现了问题还不知道是什么原因导致的 cas主要的形式就是通过过滤器的形式来实现的,来,贴上示例配置: ...

  10. kubernetes系列(十五) - 集群调度

    1. 集群调度简介 2. 调度过程 2.1 调度过程概览 2.2 Predicate(预选) 2.3 Priorities(优选) 3. 调度的亲和性 3.1 node亲和性 3.1.1 node亲和 ...