Практика противодействия взлому шрифта Autohome

Python рептилия

1. Обзор

Рептилии и антикраулеры всегда были парой естественных противников.Существуют различные методы борьбы с ползаниями, а также методы взлома, как того требует время.

В этой статье в основном представлены технические средства использования пользовательских шрифтов на внешних страницах для обеспечения защиты от сканирования, а также практические способы его взлома с технической точки зрения. (В этот период я ​​много раз падал в яму, сращивался с цепкой настойчивостью и все равно выходил сильным.)

Пользовательские шрифты: @font-face — это модуль в CSS3, в основном предназначенный для встраивания пользовательских веб-шрифтов в определенные веб-страницы. Подробное определение см.CSS @font-face.

2. Найдите источник шрифта

Форум Autohome — это место, где большинство автолюбителей могут поделиться личным опытом, таким как покупка автомобиля, выбор автомобиля, вождение и путешествие на автомобиле. Мы попытались извлечь содержимое некоторых из самых популярных постов пользователей, и первый визит не казался чем-то особенным, пока мы не нашли изображение ниже. Страница здесь отображает обычный текст, но некоторые слова в исходном коде веб-страницы представляют собой невидимый текст, заключенный в диапазон.

Вручную скопировал текст веб-страницы в Noetepad++, а также нашел исключения.

Вышеупомянутое на самом деле является призраком пользовательских шрифтов. Согласно исходному коду веб-страницы,

<span style="font-family: myfont;"></span>

Используя собственный шрифт myfont, мы искали myfont на веб-странице и быстро его нашли, это стандартный метод определения @font-face. И каждый раз, когда вы получаете доступ, адрес доступа к файлу шрифта будет меняться случайным образом.

Мы получаем доступ к адресу файла ttf и загружаем файл шрифта ttf локально.

Файл шрифта обширный и глубокий, и файл ttf является одним из них.Чтобы разобрать шрифт, прежде чем я нашел fonttools, я нашел много кода, который не мог удовлетворить мои простые потребности в разборе.Я почти прочитал определение спецификации ttf и сам написал код разбора. Эта яма.

Три, анализ шрифта

ttf — это наш часто используемый файл шрифта, который можно просмотреть с помощью программы просмотра шрифтов, которая поставляется вместе с системой, но более эффективную информацию увидеть сложно.Для ее просмотра мы используем специальный инструмент Font Creator.

Видно, что это уже не простая путаница чисел, а некоторые китайские иероглифы были перекодированы. В этом шрифте 91 символ (включая один пустой символ), и каждый символ отображает свой глиф и свой глиф-код. Например, первый показанный выше код — 0xEC35, мы используем Notepad++ для просмотра шестнадцатеричного кода скопированного невидимого символа — 0xEEB0B5,

Эти два не то же самое, что здесь происходит. Это другая яма! После поиска это на самом деле кодировка юникода и кодировка utf-8 соответственно.

Таким образом, отношения между ними соответствуют, и мы также знаем причину, по которой страница просматривается правильно, но текст не может быть получен после прочтения веб-страницы. Мы обнаружили, что при каждом посещении страницы форума шрифт один и тот же, но меняется кодировка символов. Следовательно, нам необходимо динамически анализировать файл шрифта для каждого доступа.

После поиска я наконец нашел пакет Python, который специализируется на разборе шрифтов, инструментах шрифтов,

Используйте следующий оператор, чтобы получить последовательное значение кодировки символов:

# 解析字体库font文件
font = TTFont('autohome.ttf')
uniList = font['cmap'].tables[0].ttFont.getGlyphOrder()

В-четвертых, замена контента

Ключевой момент сломан, и вся работа может быть сделана. Сначала посетите страницу для обхода, получите адрес динамического доступа к файлу шрифта, загрузите шрифт, прочитайте текстовое содержимое сообщения пользователя, замените код пользовательского шрифта фактическим текстовым кодом, а затем восстановите веб-страницу до исходного состояния. контент, видимый на странице.

Полный код выглядит следующим образом:

# -*- coding:utf-8 -*-
import requests
from lxml import html
import re
from fontTools.ttLib import TTFont

#抓取autohome评论
class AutoSpider:
    #页面初始化
    def __init__(self):
        self.headers = {
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "zh-CN,zh;q=0.8",
            "Cache-Control": "max-age=0",
            "Connection": "keep-alive",
            "Upgrade-Insecure-Requests": "1",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36"
        }
    # 获取评论
    def getNote(self):
        url = "https://club.autohome.com.cn/bbs/thread-c-2778-69436529-1.html"
        host = {'host':'club.autohome.com.cn',
                'cookie':'your cookie'}
        headers = dict(self.headers.items() + host.items())
        # 获取页面内容
        r = requests.get(url, headers=headers)
        response = html.fromstring(r.text)
        # 匹配ttf font
        cmp = re.compile(",url\('(//.*.ttf)'\) format\('woff'\)")
        rst = cmp.findall(r.text)
        ttf = requests.get("http:" + rst[0], stream=True)
        with open("autohome.ttf", "wb") as pdf:
            for chunk in ttf.iter_content(chunk_size=1024):
                if chunk:
                    pdf.write(chunk)
        # 解析字体库font文件
        font = TTFont('autohome.ttf')
        uniList = font['cmap'].tables[0].ttFont.getGlyphOrder()
        utf8List = [eval("u'\u" + uni[3:] + "'").encode("utf-8") for uni in uniList[1:]]
        wordList = ['一', '七', '三', '上', '下', '不', '中', '档', '比', '油', '泥', '灯',
                    '九', '了', '二', '五', '低', '保', '光', '八', '公', '六', '养', '内', '冷',
                    '副', '加', '动', '十', '电', '的', '皮', '盘', '真', '着', '路', '身', '软',
                    '过', '近', '远', '里', '量', '长', '门', '问', '只', '右', '启', '呢', '味',
                    '和', '响', '四', '地', '坏', '坐', '外', '多', '大', '好', '孩', '实', '小',
                    '少', '短', '矮', '硬', '空', '级', '耗', '雨', '音', '高', '左', '开', '当',
                    '很', '得', '性', '自', '手', '排', '控', '无', '是', '更', '有', '机', '来']
        # 获取发帖内容
        note = response.cssselect(".tz-paragraph")[0].text_content().encode('utf-8')
        print note
        print '---------------after-----------------'
        for i in range(len(utf8List)):
            note = note.replace(utf8List[i], wordList[i])
        print note

Обратите внимание, что wordList напрямую пишет'один', не надо писатьты один, поскольку и note, и utf8List[i] являются типами str, wordList также должен быть типа str, а не типа unicode, иначе будет сообщено об ошибке. Это другая яма.

5. Справочные статьи

1. Рептилии и странные шрифты (zhuanlan.zhihu.com/p/28183190)

2. исходный код шрифтовых инструментов (GitHub.com/инструменты для шрифтов/…)

3, анализ структуры файла ttf

(блог woo woo woo.cn on.com/mobile numberrun 2001/…)

приложение

Исходный код практики антисканирования шрифтов:кликните сюда, пароль: gxf7