网址: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. Centos 6.4 安装KSnapshot 和gimp截图工具

    一. # wget http://www.ibiblio.org/pub/Linux/X11/xutils/ksnapshot-0.2.7.tar.gz # tar -zxvf ksnapshot-0 ...

  2. pl/sql案例

    项目生命周期: 瀑布模型 拿到一个项目后,首先:分析需要用到的SQL语句: 其次:分析需要定义的变量初始值是多少,怎么得到最终值: 案例一: 统计每年入职的员工数量以及总数量: SQL语句:selec ...

  3. 如何利用.NETCore向Azure EventHubs准实时批量发送数据?

    最近在做一个基于Azure云的物联网分析项目: .netcore采集程序向Azure事件中心(EventHubs)发送数据,通过Azure EventHubs Capture转储到Azure Blog ...

  4. Cypress与TestCafe WebUI端到端测试框架简介

    近期接触了Cypress和TestCafe,两个测试框架都基于Node.js,都不再使用Selenium+WebDriver,而且开箱即用,非常轻量级,就冲着不再使用WebDriver这一点,极大地勾 ...

  5. js常用删除

    1.对象删除 1.1删除属性 用(delete 对象.属性 )的方式进行: var people={"name":"zhangsan",age:18}; del ...

  6. HDU 4143 A Simple Problem 题解

    题目 For a given positive integer n, please find the saallest positive integer x that we can find an i ...

  7. python学习笔记之装饰器、生成器、内置函数、json(五)

    一.装饰器 装饰器,这个器就是函数的意思,连起来,就是装饰函数,装饰器本身也是一个函数,它的作用是用来给其他函数添加新功能比如说,我以前写了很多代码,系统已经上线了,但是性能比较不好,现在想把程序里面 ...

  8. Halcon采集图像Image Acquisition解析

    很明显,图像的采集是所有机器视觉应用中必须解决的问题,HALCON提供了为各种图像采集设备执行这种交互的接口,图像采集的任务被简化为几行代码,只需几个操作符的调用,更重要的是,这种简单并不是以限制可用 ...

  9. day55 js进阶

    目录 引子 一.BOM操作 1 window对象 2 window子对象 3 history对象 4 location对象(掌握) 5 弹出框 6 计时器相关 二.DOM操作 1 查找标签 1.1 直 ...

  10. day25 作业(ATM第一版)

    目录 conf.setting.py core.src.py db.db_handler.py interface.admin_interface interface.bank_interface i ...