反爬虫解析-字体替换(天眼查/猫眼电影)

本次以天眼查和猫眼电影为例,解析怎样爬取替换的真实数据,感谢 "两个眼" 。。,本文使用python3。

分析

先来个简单点的:天眼查

  1. 打开天眼查,找到阿里巴巴的页面 https://www.tianyancha.com/company/59837300,可以看到勇哥帅气的照片。。。
    (注意:直接打开需要登陆的话通过百度搜索 “天眼查 阿里” 再点击访问,如果是用python请求,headers 带上 "Referer": "https://www.baidu.com/",伪装成百度跳转过来的)

    页面信息

  2. 查看源代码后发现,注册资本和注册时间是无法直接在源代码中获取正确的值。


    源代码中的值
  3. 这时需要思考原因,应该是 js 修改过或者替换过 字体文件,发现两个值的类都是 ”tyc-num“ ,可以尝试查看一下类的样式。经过搜索,找到样式如下:

@font-face {
    font-family: "tyc-num";
    src: url("https://static.tianyancha.com/web-require-js/public/fonts/tyc-num-ad584829a0.eot");
    /* IE9*/
    src: url("https://static.tianyancha.com/web-require-js/public/fonts/tyc-num-ad584829a0.eot#iefix") format("embedded-opentype"), url("https://static.tianyancha.com/web-require-js/public/fonts/tyc-num-832854095c.woff") format("woff"), url("https://static.tianyancha.com/web-require-js/public/fonts/tyc-num-7f971a8be7.ttf") format("truetype"), url("https://static.tianyancha.com/web-require-js/public/fonts/tyc-num-67f91eabd9.svg#tic") format("svg");
    /* iOS 4.1- */
}

.tyc-num {
    font-family: "tyc-num" !important;
    font-style: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

可以看出,这是用css更改了加载的字体文件,自定义了字体。

  1. 在开发者工具中找到这个这个文件,看一下做了什么改变。


    字体文件

    显然是数字这个地方做了手脚,对比一下正常的字体。


    正常的字体

    好像比正常的还少了一个 "4",多了一个 "." ,猜想 "4" 对应的就是 "." ,所以这样可以得出数字的对应关系。
    对应关系
  2. 把网页中的数据进行对应一下,果然没错。

423176999999万美元 ---> 15298.000000万美元
3995-90-38 ---> 2007-03-26

  1. 之后在提取数据时做一个逻辑判断替换即可得到真实数据了。

猫眼电影

  1. 打开猫眼电影详情页 http://maoyan.com/films/1198214,查看用户评分和累计票房,发现源码中是乱码。

    源码

  2. 他们的class都是 "stonefont" ,找到 "stonefont" 的定义。

    @font-face {
      font-family: stonefont;
      src: url('//vfile.meituan.net/colorstone/1881db7c788dfdf9d2d00a926734d0973168.eot');
      src: url('//vfile.meituan.net/colorstone/1881db7c788dfdf9d2d00a926734d0973168.eot?#iefix') format('embedded-opentype'),
           url('//vfile.meituan.net/colorstone/632958fd02509dc28d915375c3a835e02088.woff') format('woff');
    }

    .stonefont {
      font-family: stonefont;
    }
  1. 刷新几次,看到每次 url 是变化的,确定是动态生成字体,不要紧,生成哪个下载哪个。

  2. 加载一个页面,把这个字体文件下载下来拿去分析,可能是在文件中数字的地方进行了替换。在网上正好有一片是防止爬虫采集的文章: 利用自定义web-font实现数据防采集,看过后恍然大悟,这不正是我们要的吗,嘿嘿,爬虫是防不住的!

  3. 用 python 的 fonttools 库提取字体,fonttools 的用法可以网上查找一下

pip3 install fonttools         # 安装
  1. 把 woff 的文件转换成我们熟悉的 xml 格式
from fontTools.ttLib import TTFont     # 导包

font = TTFont('./632958fd02509dc28d915375c3a835e02088.woff')    # 打开文件
font.saveXML('./6329.xml')     # 转换成 xml 文件并保存
  1. 打开 xml 文件,红框内即为我们要的,略微不同,把 uni 改成 &#x ,后面再加一个分号 。


    xml文件
  2. 跟源代码中对应验证一下可以得出他们的对应关系如下。


    对应关系
  3. 用fonttools 可以直接从文件得到这些值

from fontTools.ttLib import TTFont     # 导包

font = TTFont('./632958fd02509dc28d915375c3a835e02088.woff')   # 打开文件
gly_list = font.getGlyphOrder()     # 获取 GlyphOrder 字段的值
for gly in gly_list[2:]:    # 前两个值不是我们要的,切片去掉
    print(gly)                 # 打印
  1. 最后补充完整代码
    思路:前面知道字体库是随机的,可以一些提前把能刷新到的下载到本地,抓取页面时,如果已经在本地,直接使用,不在的话再下载下来。
    本地目录:字体存在 fonts 目录下
    目录结构

代码

完整代码
import requests
import re
import os
from fontTools.ttLib import TTFont


class MaoYan(object):
    def __init__(self):
        self.url = 'http://maoyan.com/films/1198214'
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36"
        }

    # 发送请求获得响应
    def get_html(self, url):
        response = requests.get(url, headers=self.headers)
        return response.content

    # 创建 self.font 属性
    def create_font(self, font_file):
        # 列出已下载文件
        file_list = os.listdir('./fonts')
        # 判断是否已下载
        if font_file not in file_list:
            # 未下载则下载新库
            print('不在字体库中, 下载:', font_file)
            url = 'http://vfile.meituan.net/colorstone/' + font_file
            new_file = self.get_html(url)
            with open('./fonts/' + font_file, 'wb') as f:
                f.write(new_file)

        # 打开字体文件,创建 self.font属性
        self.font = TTFont('./fonts/' + font_file)

    # 把获取到的数据用字体对应起来,得到真实数据
    def modify_data(self, data):
        # 获取 GlyphOrder 节点
        gly_list = self.font.getGlyphOrder()
        # 前两个不是需要的值,截掉
        gly_list = gly_list[2:]
        # 枚举, number是下标,正好对应真实的数字,gly是乱码
        for number, gly in enumerate(gly_list):
            # 把 gly 改成网页中的格式
            gly = gly.replace('uni', '&#x').lower() + ';'
            # 如果 gly 在字符串中,用对应数字替换
            if gly in data:
                data = data.replace(gly, str(number))
        # 返回替换后的字符串
        return data

    def start_crawl(self):
        html = self.get_html(self.url).decode('utf-8')

        # 正则匹配字体文件
        font_file = re.findall(r'vfile\.meituan\.net\/colorstone\/(\w+\.woff)', html)[0]
        self.create_font(font_file)

        # 正则匹配星级
        star = re.findall(r'<span class="index-left info-num ">\s+<span class="stonefont">(.*?)</span>\s+</span>', html)[0]
        star = self.modify_data(star)

        # 正则匹配评论的人数
        people = ''.join(re.findall(r'''<span class='score-num'><span class="stonefont">(.*?万)</span>(人评分)</span>''', html)[0])
        people = self.modify_data(people)

        # 正则匹配累计票房
        ticket_number = ''.join(re.findall(r'''<span class="stonefont">(.*?)</span><span class="unit">(亿)</span>''', html)[0])
        ticket_number = self.modify_data(ticket_number)

        print('用户评分: %s 星' % star)
        print('评分人数: %s' % people)
        print('累计票房: %s' % ticket_number)


if __name__ == '__main__':
    maoyan = MaoYan()
    maoyan.start_crawl()

效果图
网页浏览效果

爬虫运行完得到的

Github地址:猫眼电影字体加载还原

个人博客:反爬虫解析-字体替换(天眼查/猫眼电影)

---- END ----

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容