当前位置: 首页 > 后端技术 > Python

奶妈级的反爬教学,字体的JS反爬实现

时间:2023-03-26 01:42:09 Python

大家好,我是Charlie~网站上有很多反爬措施,比如:js反爬,ip反爬,css反爬、字体反爬、验证码反爬、滑动点击验证反爬等等,今天我们通过爬取某招聘来学习字体反爬。字体反爬字体反爬:一种常见的反爬技术,是由网页和前端字体文件共同完成的一种反爬策略。最早的字体反爬技术是58同城、汽车之家等,现在很多主流网站或APP也采用了字体反爬技术,为自己的网站或APP增加了反爬措施。字体反爬的原理:将页面中的部分数据替换为自定义字体,如果不使用正确的解码方式,将无法获取到正确的数据内容。通过@font-face在HTML中使用自定义字体,如下图:语法格式为:@font-face{font-family:"name";src:url('字体文件链接');url('字体文件链接')format('文件类型')}字体文件一般有ttf类型,eot类型,woff类型,woff类型的文件应用比较广泛,所以大家一般都会遇到woff类型的文件。以woff类型的文件为例,它的内容是什么,用什么编码方式使数据与编码一一对应?我们以某招聘网站的字体文件为例,进入百度字体编译器,打开字体文件,如下图:随便打开一个字体,如下图:可以找到字体6放在一个平面坐标中,根据平面坐标font6的每一个点来获取font6的code,如何获取font6的code这里就不多说了。怎么解决字体反爬?首先,映射关系可以看作是一个字典。常用的方法大致有两种:第一种方法:手动提取一组编码与字符的对应关系,并以字典的形式显示出来。代码如下:replace_dict={'0xf7ce':'1','0xf324':'2','0xf23e':'3',......'0xfe43':'n',}forkey在replace_dict中:data=data.replace(key,replace_dict[key])先将字体对应的字典及其对应的代码一一定义,然后通过for循环将数据一一替换。注:该方法主要适用于字体图较少的数据。第二种方法:先下载网站的字体文件,然后把字体文件转成XML文件,在里面找到字体映射关系的代码,通过decode函数解码,然后将解码后的代码组合成字典,然后将数据根据字典的内容一一替换。由于代码比较长,这里就不写示例代码了。该方法的代码将在后面的实战练习中展示。好了,字体反爬就到此为止。接下来我们正式爬取一个招聘网站。实战练习自定义字体文件搜索首先进入一个招聘网站,打开开发者模式,如下图:这里我们看到只有代码中的新词不能正常运行,被代码替换,初步判断是acustomfont使用的是字体文件的字体文件,这个时候就需要找到字体文件,那么在哪里找到字体文件呢,首先打开开发者模式,点击网络选项,如图下图:一般字体文件都放在字体选项卡中,我们发现这里一共有5个入口,那么自定义字体文件的入口是哪一个呢?当我们点击下一页时,自定义字体文件会被执行一次。这个时候我们只需要在网页中点击下一页就可以了,如下图所示:可以看到多了一个以file开头的入口。这时可以初步判断该文件为自定义字体文件。现在我们下载它。下载方法很简单,把文件开头入口的网址复制进去,在网页上打开就可以了。下载后在百度字体编译器中打开,如下图:这时发现打不开。是不是找错了字体文件?网站提示不支持这个。不同的文件类型,那么我们将下载文件的后缀改为.字体映射关系找到了自定义字体文件,那我们应该怎么使用呢?这时候我们先自定义方法get_fontfile()来处理自定义字体文件,然后分两步将字体文件中的映射关系以字典的形式显示出来。字体文件下载和转换;字体映射关系解码。字体文件下载与转换首先,自定义字体文件的更新频率非常高。这时候我们可以实时获取网页的自定义字体文件,防止使用之前的自定义字体文件,导致数据获取不准确。首先观察自定义字体文件的url链接:https://www.xxxxxx.com/intern...https://www.xxxxxx.com/intern...https://www.xxxxxx.com/intern...可以发现,只有自定义字体文件的url的rand参数发生了变化,是一个小于1的随机十六位浮点数,那么我们只需要构造rand参数即可。主要代码如下:defget_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).contentwithopen('file.woff','wb')asf:f.write(response)font=TTFont('file.woff')字体.saveXML('file.xml')首先通过random.uniform()方法来控制随机数的大小,然后通过round()方法来控制随机数的位数,所以即可以得到rand的值,然后通过.content将URL响应的内容转为二进制写入文件。在woff文件中,通过TTFont()方法获取文件内容,通过saveXML方法将内容保存为xml文件。xml文件内容如下图:字体解码和显示字体。xml文件一共有4589行。哪一部分是字体映射关系的代码部分?首先我们回头看一下百度字体编码器的内容,如下图:汉字person对应的编码是f0e2,那么我们在font.xml文件中查询person的编码,如如下图所示:我们可以发现有4个R??esult,但是仔细观察每一个结果都是一样的。这时候我们就可以根据他们的编码规则获取映射关系,然后通过解码获取对应的数据值,最后以字典的形式展示出来。主要代码如下:defget_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).contentwithopen('file.woff','wb')asf:f.write(response)font=TTFont('file.woff')字体.saveXML('file.xml')首先读取file.xml文件的内容,找出代码中的code和name值分别设置为key和value,然后对value进行解码通过for循环放入我们想要的数据,最后通过zip()方法组合成元组,通过dict()方法转换成字典数据。运行结果如图:获取招聘数据上一步我们成功将字体映射关系转化为字典数据,然后开始发送网络请求获取数据,主要代码如下:defget_data(dict,url):response=requests.get(url,headers=headers).text.replace('&#','0')forkeyindict: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')foriindatas: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(),'工资':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(),'公司名称':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(),'优势':','.join(i.xpath('./div[2]/div[1]/span/text()').extract()),'福利':','.join(i.xpath('./div[2]/div[2]/span/text()').extract())}saving_data(列表(数据。values()))首先自定义get_data()方法,接收字体映射关系的字典数据,然后通过for循环将字典内容逐一替换为数据,最后通过xpath()提取出我们想要的数据,最后把数据我们自定义的方法saving_data()中保存的数据已经获取到了,接下来就是保存数据了。主要代码如下:defsaving_data(data):db=pymysql.connect(host=host,user=user,password=passwd,port=port,db='recruit')cursor=db.cursor()sql='插入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()除了:db.rollback()db.close()启动程序。程序写的差不多了。接下来,我们将编写运行程序的代码。主要代码如下:if__name__=='__main__':create_db()get_fontfile()foriinrange(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)结果显示出来,学习字体反爬爬某某就到此结束招聘!!!如果文章对你有帮助,点赞+关注,你的支持是我最大的动力