Python爬虫 乐居字体反爬分析 (含源码)

严重声明:本文仅用于学习交流,不得用于商业用途,同时希望大家遵循网络协议,维护网络和谐。

  • 上一篇文章我们分析了一下人人车的字体反爬,但是好像python进行逆向分析没有很全,那么今天我们来看一下乐居的字体反爬是怎么做的,然后讲一下这个代码是怎么走的,还是先看网站(乐居
    ):
    1. 因为我们需要的重要信息都在详情页里面,所以,点开一个新房的详情页。按F12观察网页源码里面和正文的异同。如下图所示,我们可以看到,和人人车一样,都是利用css样式渲染,让源码里面的数字进行变换,让我们看到真实数据。在源码搜索new_font这个样式一共有三个,两个就是图片里里面的,将指导价和开盘时间字体转换。另一个,不是写在样式里面,但是,我们也有用,后面说:
      在这里插入图片描述

    2. 我们打开在F12的控制台里面选Network查看后台给我们发的数据包,选择font直接就能看到一堆字体文件(.woff结尾的),然后打开,最下面一行都是数字,但是,有个名字含有truetype的一看就不一样,果然,里面的数字顺序是打乱的,别的文件数字顺序都是1234567890。这里面肯定存在着什么猫腻,所以我们根据这个文件名字里面有true认为这个顺序是正常顺序,那么源码中的顺序数字就按别的文件中的顺序转换,得到下图中的这个对应关系,红色数字表示源码中的数字:
      在这里插入图片描述

    3. 我们运用上面的对应看看主页,按照上图的规则刚好能得到我们看到的数据,可以看到,对应的上。那么,再将这个套路运用到别的网页,我自己看了十几页都对的上,我认为的话应该就是这么实现的反爬了:
      在这里插入图片描述

  • 那么怎么用代码去实现这种反推呢,下面介绍:
    1. 用到python的第三方库:fontTools,清华镜像,我安装的源码是(你们可能是pip3):
      pip install -i https://tuna.tsinghua.edu.cn/simple fontTools

    2. 请求页面,获取字体变换的源数据,这里我就只获取了指导价格,里面用到的scrapy.Selector()对象,和lxml差不多,但是我觉得会好一点,这段就是为了获取到指导价格那串迷惑文字:

      	# get response
          detail_url = 'https://house.leju.com/dl149612/'
          resp = requests.get(detail_url)
          
          # get  guide price
          from scrapy import Selector
          html = Selector(text=resp.text)
          guide_price = html.xpath("normalize-space(//span[@class='t_l'])").extract_first()
          print(guide_price)  # result: 指导价格: 约52777-59777 元/㎡
      
    3. 利用fontTools对字体文件进行解析,这里我们不需要获取字体文件,因为,乐居将字体文件的base64编码的数据直接放在网页源码里面了,就是我刚开始说的new_font,这里还有个原因就是字体文件其实应用的是哪一个是不固定的,在下面你们会看到,字体文件变了三四次,所以,我不推荐大家直接将字体文件下载下来就不变了,另外,多请求一次浪费资源:
      在这里插入图片描述
      所以,我们就不用再请求一次字体文件了,这里直接利用python的字符串切割获得,获取的是base64字符串,直接编码为字节流,为了之后用:

      	# get font_file_bytes by split html source
          b64_str = resp.text.split("src: url(data:font/truetype;charset=utf-8;base64,")[1].split(") format('woff');")[0]
          font_file_io = base64.b64decode(b64_str)
          print(type(font_file_io))  # result: <class 'bytes'>
      
    4. 利用fonttools获取字体文件,同时保存转换的字体文件关系:

      	# parse font file by fontTools.TTFont
          from fontTools.ttLib import TTFont
          font = TTFont(io.BytesIO(font_file_io))  # this param also can be a path txt
          font.saveXML('leju.xml')  # save the conversion map to the path you want
      

      正常情况下,我们需要找GlyphOrder和cmap这两种对应xml的,我也想解释下对应关系的,但是,好像,他们的coder直接给我们打了注释了,打开这个xml文件,第一个cmap有后台程序员对我们深深的爱意:
      在这里插入图片描述

    5. 在字体文件中获取刚刚看到的第一个对应关系(cmap):

      	# get base conversion map
          font_map = font['cmap'].getBestCmap()
          print(type(font_map))  # result: <class 'dict'>
      

      在这里插入图片描述

    6. 在cmap中获取英文数字列表,同时构造真实对应关系字典,就是将正常顺序的数字做键,上面的那个英文数字列表转成阿拉伯数字后做值,组装成一个字典:

      	# get conversion dict: key: html source num, value: true num
          base_eng_list = {'zero': '0', 'one': '1', 'two': '2', 'three': '3', 'four': '4', 'five': '5',
                           'six': '6', 'seven': '7', 'eight': '8', 'nine': '9'}
          mapping_list = [base_eng_list[_] for _ in list(font_map.values())[:10]]
          base_num_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
          font_dict = dict(zip(base_num_list, mapping_list))
      
    7. 利用映射字典转换网页源码中的数字:

      	# use the map dict converter the html source txt
          true_guide_price = ''.join([_ if not _.isdigit() else font_dict[_] for _ in guide_price])
          font.close()
      
          print(true_guide_price)  # 指导价格: 约15000-16000 元/㎡
      

      最后,也希望大家的技术水平蒸蒸日上,如果喜欢,不妨关注啥的。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值