手把手教你JS逆向搞定字体反爬并获取某招聘网站信息

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情

下次点击上方“Python爬虫与数据挖掘”,进行关注

回复“书籍”即可获赠Python从入门到进阶共10本电子书

Python让我们相遇。

大家好,我是霖hero。之前给大家分享过手把手教你使用scrapy框架来爬取北京新发地价格行情(理论篇)手把手教你使用scrapy框架来爬取北京新发地价格行情(实战篇)手把手教你使用XPath爬取免费代理IP,今天给大家继续带来干货,JS逆向。

网站的反爬措施有很多,例如:js反爬、ip反爬、css反爬、字体反爬、验证码反爬、滑动点击类验证反爬等等,今天我们通过爬取某招聘来实战学习字体反爬。

今日网站

小编已加密:aHR0cHM6Ly93d3cuc2hpeGlzZW5nLmNvbS8= 出于安全原因,我们把网址通过base64编码了,大家可以通过base64解码把网址获取下来。

字体反爬

字体反爬:一种常见的反爬技术,是网页与前端字体文件配合完成的反爬策略,最早使用字体反爬技术的有58同城、汽车之家等等,现在很多主流的网站或APP也使用字体反爬技术为自身的网站或APP增加一种反爬措施。

字体反爬原理:通过自定义的字体来替换页面中某些数据,当我们不使用正确的解码方式就无法获取正确的数据内容。

在HTML中通过@font-face来使用自定义字体,如下图所示:

b3c16ae528111063309fa1313248b281.png

其语法格式为:

@font-face{
font-family:"名字";
src:url('字体文件链接');
url('字体文件链接')format('文件类型')
}

字体文件一般是ttf类型、eot类型、woff类型,woff类型的文件运用比较广泛,所以大家一般碰到的都是woff类型的文件。

以woff类型文件为例,其内容是怎样的呢,又是以什么编码方式使得数据与代码一一对应的呢?

我们以某招聘网站的字体文件为例,进入百度字体编译器并打开字体文件,如下图所示:

0623155b4861cc2e731bceaeefd924de.png

随机打开一个字体,如下图所示:

66a9f786c5b1019b749df3954c7090ce.png

可以发现字体6放在一个平面坐标里面,根据平面坐标的每个点来得出字体6的编码,这里就不解释如何得出字体6的编码了。

如何解决字体反爬呢?

首先映射关系可以看作为字典,大致有两种常用的方法:

第一种:手动把一组编码和字符的对应关系提取出来并用字典的形式展示,代码如下所示:

replace_dict={
	'0xf7ce':'1',
	'0xf324':'2',
	'0xf23e':'3',
	.......
	'0xfe43':'n',
}
for key in replace_dict:
    数据=数据.replace(key,replace_dict[key])

首先定义字体与其对应的代码一一对应的字典,再通过for循环把数据一一替换。

注意:这种方法主要适用于字体映射少的数据。

第二种:首先下载网站的字体文件,再把字体文件转换为XML文件,找到里面的字体映射关系的代码,通过decode函数解码,然后将解码的代码组合成一个字典,再根据字典内容将数据一一替换,由于代码比较长,这里就不写示例代码了,待会在实战演练中会展示这种方法的代码。

好了,字体反爬就简单讲到这里,接下来我们正式爬取某招聘网站。

实战演练

自定义字体文件查找

首先进入某招聘网并打开开发者模式,如下图所示:

f2f44ab4e43edd83ad0a4edfc65b1489.png

这里我们看到代码中只有生字不能正常函数,而是用来代码来替代,初步判定为使用了自定义的字体文件,这时就要找到字体文件了,那么字体文件在哪里找呢,首先打开开发者模式,并点击Network选项,如下图所示:

88a9846e32e149db139a2e4f98fbb6de.png

一般情况下,字体文件放在Font选卡中,我们发现这里一共有5个条目,那么哪个是自定义字体文件的条目呢,当我们每次点击下一页的时候,自定义字体文件就会执行一次,这时我们只需要点击网页中的下一页即可,如下图所示:

7a3c31ec35ee87462b0d6e61ea619cbf.png

可以看到多了一个以file开头的条目,这时可以初步判定该文件为自定义字体文件,现在我们把它下载下来,下载方式很简单,只需要把file开头的条目的URL复制并在网页上打开即可,下载下来后在百度字体编译器打开,如下图所示:

6e9a0db6de7808df2b887d18f5e404c8.png

这时发现打开不了,是不是找错了字体文件,网站提示说不支持这种文件类型,那么我们把下载的文件后缀改为.woff在打开试试,如下图所示:

28b501f9abe55b0f8185a5a121678d46.png

这时就成功打开了。

字体映射关系

找到自定义字体文件了,那么我们该怎么利用呢?这时我们先自定义方法get_fontfile()来处理自定义字体文件,然后在通过两步来把字体文件中的映射关系通过字典的方式展示出来。

  1. 字体文件下载与转换;

  2. 字体映射关系解码。

字体文件下载与转换

首先自定义字体文件更新频率是很高的,这时我们可以实时获取网页的自定义字体文件来防止利用了之前的自定义字体文件从而导致获取数据不准确。首先观察自定义字体文件的url链接:

https://www.xxxxxx.com/interns/iconfonts/file?rand=0.2254193167485603
https://www.xxxxxx.com/interns/iconfonts/file?rand=0.4313944100724574
https://www.xxxxxx.com/interns/iconfonts/file?rand=0.3615862774301839

可以发现自定义字体文件的URL只有rand这个参数发生变化,而且是随机的十六位小于1的浮点数,那么我们只需要构造rand参数即可,主要代码如下所示:

def get_fontfile():
    rand=round(random.uniform(0,1),17)
    url=f'https://www.xxxxxx.com/interns/iconfonts/file?rand={rand}'
    response=requests.get(url,headers=headers).content
    with open('file.woff','wb')as f:
        f.write(response)
    font = TTFont('file.woff')
    font.saveXML('file.xml')

首先通过random.uniform()方法来控制随机数的大小,再通过round()方法控制随机数的位数,这样就可以得到rand的值,再通过.content把URL响应内容转换为二进制并写入file.woff文件中,在通过TTFont()方法获取文件内容,通过saveXML方法把内容保存为xml文件。xml文件内容如下图所示:

94e03395a801ee6551b976276b10cce2.png

字体解码及展现

该字体.xml文件一共有4589行那么多,哪个部分才是字体映射关系的代码部分呢?

首先我们看回在百度字体编码器的内容,如下图所示:

3eb08d8ebc15d66323eb96e6f7c8bd9b.png

汉字人对应的代码为f0e2,那么我们就在字体.xml文件中查询人的代码,如下图所示:

77cff4f0d2954fbef75c9330a00c2bd6.png

可以发现一共有4个结果,但仔细观察每个结果都相同,这时我们可以根据它们代码规律来获取映射关系,再通过解码来获取对应的数据值,最后以字典的形式展示,主要代码如下所示:

with open('file.xml') as f:
    xml = f.read()
keys = re.findall('<map code="(0x.*?)" name="uni.*?"/>', xml)
values = re.findall('<map code="0x.*?" name="uni(.*?)"/>', xml)
for i in range(len(values)):
    if len(values[i]) < 4:
        values[i] = ('\\u00' + values[i]).encode('utf-8').decode('unicode_escape')
    else:
        values[i] = ('\\u' + values[i]).encode('utf-8').decode('unicode_escape')
word_dict = dict(zip(keys, values))

首先读取file.xml文件内容,找出把代码中的code、name的值并分别设置为keys键,values值,再通过for循环把values的值解码为我们想要的数据,最后通过zip()方法合并为一个元组并通过dict()方法转换为字典数据,运行结果如图所示:

330f9e1f4a8bebc67e12871bf16760e8.png

获取招聘数据

在上一步中,我们成功把字体映射关系转换为字典数据了,接下来开始发出网络请求来获取数据,主要代码如下所示:

def get_data(dict,url):
    response=requests.get(url,headers=headers).text.replace('&#','0')
    for key in dict:
        response=response.replace(key,dict[key])
    XPATH=parsel.Selector(response)
    datas=XPATH.xpath('//*[@id="__layout"]/div/div[2]/div[2]/div[1]/div[1]/div[1]/div')
    for i in datas:
        data={
            'workname':i.xpath('./div[1]/div[1]/p[1]/a/text()').extract_first(),
            'link':i.xpath('./div[1]/div[1]/p[1]/a/@href').extract_first(),
            'salary':i.xpath('./div[1]/div[1]/p[1]/span/text()').extract_first(),
            'place':i.xpath('./div[1]/div[1]/p[2]/span[1]/text()').extract_first(),
            'work_time':i.xpath('./div[1]/div[1]/p[2]/span[3]/text()').extract_first()+i.xpath('./div[1]/div[1]/p[2]/span[5]/text()').extract_first(),
            'company_name':i.xpath('./div[1]/div[2]/p[1]/a/text()').extract_first(),
            'Field_scale':i.xpath('./div[1]/div[2]/p[2]/span[1]/text()').extract_first()+i.xpath('./div[1]/div[2]/p[2]/span[3]/text()').extract_first(),
            'advantage': ','.join(i.xpath('./div[2]/div[1]/span/text()').extract()),
            'welfare':','.join(i.xpath('./div[2]/div[2]/span/text()').extract())
        }
        saving_data(list(data.values()))

首先自定义方法get_data()并接收字体映射关系的字典数据,再通过for循环将字典内容与数据一一替换,最后通过xpath()来提取我们想要的数据,最后把数据传入我们自定义方法saving_data()中。

保存数据

数据已经获取下来了,接下来将保存数据,主要代码如下所示:

def saving_data(data):
    db = pymysql.connect(host=host, user=user, password=passwd, port=port, db='recruit')
    cursor = db.cursor()
    sql = 'insert into recruit_data(work_name, link, salary, place, work_time,company_name,Field_scale,advantage,welfare) values(%s,%s,%s,%s,%s,%s,%s,%s,%s)'
    try:
        cursor.execute(sql,data)
        db.commit()
    except:
        db.rollback()
    db.close()

启动程序

好了,程序已经写得差不多了,接下来将编写代码运行程序,主要代码如下所示:

if __name__ == '__main__':
    create_db()
    get_fontfile()
    for i in range(1,3):
        url=f'https://www.xxxxxx.com/interns?page={i}&type=intern&salary=-0&city=%E5%85%A8%E5%9B%BD'
        get_data(get_dict(),url)

结果展示

637dfe969ca0423fd9f7c2e72149c738.png

好了,学习字体反爬并爬取某招聘就讲到这里了!!!

5ceee2aa4f15be573b8f804a03b999b9.png

    小伙伴们,快快用实践一下吧!如果在学习过程中,有遇到任何问题,欢迎加我好友,我拉你进Python学习交流群共同探讨学习。

cfbc731a9782a85d0964dfbd85830eed.png

------------------- End -------------------

往期精彩文章推荐:

1b5f97b38435bed34ec66507cffd4016.png

欢迎大家点赞,留言,转发,转载,感谢大家的相伴与支持

想加入Python学习群请在后台回复【入群

万水千山总是情,点个【在看】行不行

/今日留言主题/

随便说一两句吧~~

JavaScript虫技巧详细攻略 在互联网时代,网站采取了各种手段来防止被虫抓取数据,其中最常见的就是JavaScript虫技巧。本文将揭示一些常用的JavaScript虫技巧,提供一些实际操作建议,帮助您保护自己的虫免受检测和封禁。 阅读详情

相关推荐

Selenium实战:用本地Chrome Profile绕过Boss直聘,稳定抓取招聘数据

网络虫是自动化获取网页数据的关键技术,其核心原理是通过程序模拟浏览器请求,解析HTML文档以提取结构化信息。在应对动态渲染网站时,传统请求库常因JavaScript执行和加密参数而失效,此时浏览器自动化工具展现出独特的技术价值。Selenium通过驱动真实浏览器,能完整执行页面脚本、处理动态交互,有效应对复杂的机制,广泛应用于数据采集、自动化测试等场景。本文聚焦于结合本地Chrome用户配置文件(Profile),利用其真实的Cookies、历史记录和扩展信息,构建更接近人类行为的浏览器指纹,从而提升

weixin_31842715的博客 528

js

3、js动态网页抓取方式(重点) 许多时候虫取到的页面仅仅是一个静态的页面,即网页的源代码,就像在浏览器上的“查看网页源代码”一样。 一些动态的东西如javascript脚本执行后所产生的信息是抓取不到的,下面两种方案,可用来pythonjs执行后输出的信息。 ① 用dryscrape库动态抓取页面 js脚本是通过浏览器来执行返回信息的,所以,抓取js执行后的页面,一个最直接的方式就是用python模拟浏览器的行为。 WebKit 是一个开源的浏览器引擎,python提供了许多库可以调用这个引擎,d

weixin_40303822的博客 2836

90%的人都不算会虫,这才是真正的技术,从0到高手的进阶

真正的虫高手必须掌握的技术,你会了吗?

龙叔的博客 7850

JS逆向

JavaScript逆向是现代网络数据采集的重要组成部分,适合面对动态内容和复杂数据加载的网站。理解其原理及操作流程,将使开发者能够更有效地获取、分析和利用数据,为决策提供有力支持。

starry-sea1412的弃坑之路 2120

虫的四种常见方式-JS逆向方法论

因为我们已经在陷阱里面了,所以要刷新页面,JS的运行应该停止在设置的断点处,此时该函数尚未运行,我们在Console里面重新定义它,继续运行就可以跳过该陷阱。首先把Chrome浏览器保存的该网站的cookie删除,按F12到Network窗口,把“preserve log”选中(Firefox是“Persist logs”),刷新网页,这样我们就可以看到历史的Network请求记录。JS会响应链接被点击的事件,在打开链接前,先访问cl.gif,把当前的信息发送给服务器,然后再打开被点击的链接。

westlife73的博客 2418

深入解析JS工程逆中的机制

例如,可以使用浏览器自动化工具,如Selenium,来模拟用户操作,执行网页中的JavaScript代码,获取最终的内容。JS逆工程的原理是通过分析网页中的JavaScript代码,还原出网页的动态生成过程,从而获取最终的内容。解决方案:模拟JS执行环境 为了解决JS逆工程中的机制,我们可以模拟JS执行环境,使得虫能够执行网页中的JavaScript代码,获取最终的内容。为了解决JS逆工程中的机制,我们可以模拟JS执行环境,使得虫能够执行网页中的JavaScript代码,获取最终的内容。

Z_suger7的博客 1428

Selenium虫实战:JS加密破解、懒加载处理与对抗

现代网页取已从静态HTML解析升级为浏览器运行时环境的深度交互工程。其核心在于理解JavaScript动态渲染原理——页面依赖fetch请求、Vue/React虚拟DOM更新及IntersectionObserver懒加载机制,导致传统requests失效。Selenium的价值在于提供完整JS执行上下文,支撑JS加密参数复现(如crypto.subtle.digest、performance.now()协同计算)、滚动行为精准模拟以触达全量数据、以及Canvas指纹伪造与鼠标贝塞尔轨迹等穿透技术。这

weixin_29479561的博客 717

虫实战:破解网站字体加密,解决数据抓取中的“口”字难题

在Web数据抓取领域,字体加密是一种常见的虫技术,其原理是通过自定义字体文件,将网页上显示的数字或文字映射到非标准的Unicode码点。当虫程序直接获取HTML源码时,由于缺少对应的字体渲染支持,这些关键信息便会显示为乱码或“口”字。理解破解这种加密机制,对于虫工程师而言,是一项提升数据获取准确性和完整性的核心技能。从技术价值看,掌握字体加密的逆向分析方法,不仅能有效应对如二手车价格、房产信息等敏感数据的抓取挑战,还能为后续处理更复杂的动态渲染和混淆技术打下基础。本文以实战项目为例,深入剖析了利用

weixin_30721077的博客 436

Selenium+Chrome Profile实战:模拟真人行为破解Boss直聘

在数据采集领域,机制是开发者面临的核心挑战之一。其原理是通过分析请求特征、行为模式和浏览器指纹,识别拦截自动化脚本。为了应对这一挑战,技术价值在于构建稳定、可持续的数据采集方案,而非一次性突破。应用场景广泛,尤其在招聘、电商、社交媒体等动态内容丰富的平台。本文聚焦于使用Selenium结合本地Chrome用户配置文件(Profile),通过模拟真实用户的浏览历史、Cookie会话和操作习惯,有效降低被识别风险。该方案强调‘养号’策略与行为随机化,为虫工程实践提供了兼顾效率与安全性的解决思路,是应对如

weixin_34274029的博客 303

90%的人都不算会虫,这才是真正的技术,从0到高手的进阶!

今天就告诉你,**真正的虫高手应该学哪些东西**,就算你毫无基础,你也能知道应该怎么去学习。

2301_78095812的博客 513

这才是真正的技术,从0到高手的进阶!

这才是真正的技术,从0到高手的进阶!

2301_78094861的博客 723

盘点一个Pandas中explode()爆炸函数应用实际案例

点击上方“Python虫与数据挖掘”,进行关注回复“书籍”即可获赠Python从入门到进阶共10本电子书今日鸡汤莫买沃洲山,时人已知处。大家好,我是Python进阶者。前言前几天在学习【...

pdcfighting的博客 3154

怎么在第一个PDF文件的中间,插入第二个PDF文件的内容?

点击上方“Python虫与数据挖掘”,进行关注回复“书籍”即可获赠Python从入门到进阶共10本电子书今日鸡汤昨夜裙带解,今朝蟢子飞。大家好,我是Python进阶者。前言前几天在学习【...

pdcfighting的博客 1414

盘点Pyecharts V1和V0.5之间的切换方法

点击上方“Python虫与数据挖掘”,进行关注回复“书籍”即可获赠Python从入门到进阶共10本电子书今日鸡汤泠泠七弦上,静听松风寒。大家好,我是Python进阶者。前言Pyechar...

pdcfighting的博客 1265

Python动态网页表格取:一行render()解决90%的pandas.read_html空列表问题

HTML表格解析是数据采集的基础能力,其核心原理在于识别语义化<table>标签还原行列结构。传统requests+BeautifulSoup仅能获取静态HTML源码,而现代网页普遍采用React/Vue等框架动态渲染,导致pandas.read_html()返回空列表。该技术通过轻量级JS执行环境补全真实DOM,使静态解析器获得可解析的完整HTML,兼具Selenium的渲染能力与requests的简洁性。适用于务系统、招标平台、股价行情等含AJAX/SPA结构的业务场景,尤其解决初学者‘页面明明有表

weixin_30325487的博客 431

零基础网络安全入门:从Kali Linux到渗透测试实战就业指南

渗透测试作为网络安全领域的核心实践方法,其本质是在合法授权范围内模拟攻击者行为,以发现修复系统漏洞。其技术原理基于对网络协议、系统架构和应用程序的深入理解,通过系统化的信息收集、漏洞扫描、利用验证等阶段,评估目标环境的安全状况。掌握渗透测试不仅能够提升企业安全防护能力,也是网络安全从业者进入行业的关键技能。在实际应用场景中,Kali Linux作为集成了数百种安全测试工具的操作系统,为学习者提供了标准化的实验环境。结合Hack The Box等在线靶场平台,学习者可以在安全可控的环境中进行实战演练,将理论

weixin_34234721的博客 367

篇 | 手把手你处理 JS 逆向字体

本篇文章将聊聊另一种更加常见的方案「 字体 」它的实现原理为通过自定义的字体替换网页元素中的部分内容来实现的策略常见的字体格式包含:ttf、eot、woff,我们一般在网页中通过关键字「 @font-face 」定义字体样式,然后再设置到元素控件样式中去 目前有很多主流网站引入了字体,比如:某 8 同城、某车之家等今天研究的目标对象是:aHR0cHM6Ly93d3cuZ3VhemkuY29tL2J1eQ==1、分析一下打开目标页面及浏览器的开发者工具栏,我们发现汽车价格、首付金额、公里数

sixqingfeng的博客 1276

百度编译器的使用

@{ ViewBag.Title = "TravelNotes"; } <link href="~/Content/trvalYouji.css" /> <script type="text/javascript" charset="utf-8" src="~/utf8-asp/ueditor.config.js"></script> <...

weixin_45932157的博客 462
上一篇: 如何用Python下载百度指数的数据
下一篇: Python处理超强反爬(TSec防火墙+CSS图片背景偏移定位)
Python进阶者
博客等级 码龄9年 5888粉丝 935原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值