python 人人车字体反爬分析 -含源码

严重声明:本文仅用于学习交流,不得用于商业用途,同时希望大家遵循robots协议,维护网络和谐。
本猿最近在逛一些网站的时间。在打开浏览器的f12查看人家前端代码咋写的时候,经常会发现就是页面上显示的内容和源码里面的不一样,然后自己请求一遍也还是不一样,奇怪,猿,妙不可言?本着猿精神,上网查了下,这种属于字体反爬策略。应用的还是不少的,所以,在这里将在下对字体反爬的见解写一下。

  • 先观察人人车网站: 人人车
    1. 打开一个详情页,看页面标签,直接年款啥的直接都不一样了,查看n多网页后发现,变化的都是数字:
      图1-页面源码不一致
    2. 查看css样式的时候发现,应用了个字体样式,同时名称直接关联:
      图2-css样式显真形
    3. 查看服务器给我们发的包,直接发现一个跟上面标签属性名,以及css样式选择器一样名称的包,利用谷歌浏览器的规范输出,直接查看,发现最下面的一行数字顺序是不太对的,找规律:
      图3-服务器发送字体文件
    4. 发现这样对应就是本应该在6的位置上他换上了8,7的位置换成了6,8换成了7:
      在这里插入图片描述
      5.我们再看首页的源码和展示给我们的标题,利用上面的规则一看,猿来如此:
      在这里插入图片描述
  • 那么,作为一名pythonic,怎么会被这些迷惑操作遮住我们睿智的双眼,下面是本猿利用python代码实现的字体复原(悲惨的利用三天时间,学了爬虫,再加上查资料,终于有了点眉目),代码贴在下面,bug勿喷,安心食用:
# !/usr/bin/python3
# -*- coding: utf-8 -*-
"""
# @Time      :   2020/4/25 13:32
# @Author    :   hupoc
# @File      :   second_hand_car_renrenche.py
# @Desc      :   
"""
import io
import os
import requests
from fontTools.ttLib import TTFont
from scrapy import Selector


def font_transfor(translate_text, html, url):
    """
    网页上使用字体文件的文本转换
    :param translate_text: 需要转换的文本
    :param html: 经过scrapy.Selector()转换后的响应对象
    :param url: 请求的url
    :return: 转换后的文本
    """
    # 获取字体名所在标签文本
    font_interface_str = html.xpath("//div[@class='title']/h1/@class").extract_first()
    if font_interface_str and 'title-name' in font_interface_str:
        # 提取字体文件名称
        font_interface_name = font_interface_str.replace('title-name', '').strip()
    else:
        # 如果没有title-name表示没有应用字体文件
        print('没有提取到字体名所在标签文本,url:{0}'.format(html.url))
        return
    file_name = url.rsplit("/", 1)[-1] + '_' + font_interface_str
    # 拼接字体文件 在本地保存路径
    file_ttf = '/tmp/renrenche_font/{0}.woff'.format(file_name)
    if not os.path.exists(os.path.dirname(file_ttf)):
        os.makedirs(os.path.dirname(file_ttf))
    # 下载字体文件,保存到本地路径
    url = 'https://misc.rrcimg.com/ttf/{0}.woff'.format(font_interface_name)
    resp = requests.get(url)
    if not resp:
        print('请求字体文件失败')
    try:
        font = TTFont(io.BytesIO(resp.content))
    except Exception as e:
        return
    font_obj = font['cmap']
    font_tables = font['cmap'].tables
    uni_list = font['cmap'].tables[0].ttFont.getGlyphOrder()
    # 生成转换规则
    base_num_list = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
    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 uni_list[1:]]
    font_dict = dict(zip(mapping_list, base_num_list))
    # 对需要转换的文本进行转换
    transfor_str = [_ if not _.isdigit() else font_dict[_] for _ in translate_text]
    # 关闭字体文件
    font.close()
    # 返回正确的文本
    return ''.join(transfor_str)


def get_renrenche_detail():
    # 请求页面获取响应
    detail_url = 'https://www.renrenche.com/bj/car/c2d4fdd2902df36b'
    response = requests.get(detail_url)
    if not response or response.status_code != 200:
        print('人人车详情页请求失败')
        return
    # 将响应文本转为lxml对象,为了方便,使用的是scrapy.Selector()
    html = Selector(text=response.text)
    # 获取标题,并规格化标题文本
    titles = html.xpath("//div[@class='title']/h1/text()").extract()
    title = ' '.join(titles).replace('\n', '').strip()
    # 转换标题文字,获取正确文本
    true_title = font_transfor(title, html, detail_url)
    # 打印文本
    print(true_title)


if __name__ == '__main__':
    # 请求人人车的二手车详情页
    get_renrenche_detail()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章