python常见面试题

css反爬解析

2020-04-29  本文已影响0人  苦海飘摇

一、概述

      有爬虫,就一定会有反爬虫,也因此一定会有反-反爬虫,双方就是在不断变换策略,但是,只要是是使用代码实现的,也一定会有用代码破解的办法。爬虫终究会战胜反爬虫。

爬虫实战—破解CSS反爬

      此次就是使用python应对猫眼电影的CSS字体反爬措施,以 影片总票房排行榜页为例,分析并破解猫眼对数据的加密,从而获得票房数据。

二、反爬分析

      用户可以看到的总票房界面如下,看这样式,要么是一个表格table标签或者是无序列表ul标签,爬取不是问题。

使用F12Element界面选择一个数据,但是看到的却是方块。

image

由于Element界面会对页面进行一些解析,不是最原始的页面,需要查看源代码

熟悉前端的话,对以&开头的应该不陌生,这是转义字符,说明我们能够直接在网页中看到的是进过某种“编码”后的数字。
再回到Element界面,将红圈中的两个红圈中的钩去掉,则可以看到页面中的数据变为方框了,由基础的CSS知识可知,这里猫眼使用了一种自定义的字体cs,点击一下year:39就可以找到字体的定义了。

可以将url括号中的复制到浏览器中,转到后会下载一个下载.woff文件(什么是"WOFF文件"?),即一个开放字体,但是打开该文件需要专用的软件FontCreator,将woff文件导入后,看到如下界面

比如战狼2的场均人次为38,而源代码中为上图中38为uniE0B4 uniE800,规律显而易见,其他的亦是如此。也就是说只要找到代码与数字的映射关系就可以获取数据,看上去很简单,但是是不是源码数字的映射就一种呢?刷新一下界面,发现源码竟然变了。

重复上述步骤,可以发现woff文件中,数字对应的编码也改变了,也就是说,虽然显示的是一样的,但是相同的数字对不同的src:url()中的编码是不一样的,想要解决这一问题,就要从字体实现的角度来分析。比如7虽然对不同的文件有不同的编码,但是无论什么编码其表示都是先横再斜下来,也就是说如果用坐标表示的话,他们的坐标是一样的,可以先选择一个标准对照组,找到数字-编码-坐标对应关系,对于其他的字体文件,如果坐标和标准对照组中的坐标一样,则意味着两个表示的是同一个数字,由于对照组的对应关系已知,则该字体的对应关系也可推得。在python中,这就需要借助fontTools库。

三、代码实现

首先是建立一个标准对照组

# 选择一个标准字体对照表
standardFont = TTFont("standard_font.woff")
# 使用 "FontCreator字体查看软件" 查看字体的对应关系,然后设置对应关系
standardNumList = ["1", "6", "8", "0", "3", "4", "7", "5", "9", "2"]
standardUnicodeList = ["uniE3CA", "uniF2E0", "uniE667", "uniF6F5", "uniE123","uniF778", "uniE373", "uniF214", "uniE7BB", "uniF19C"]

由于字体是base64,可以直接使用base64解码为woff文件。代码涉及到fontTools库的使用,具体使用可以参考官方文档。

# 字体解析,参数为url中的base64,record为是否保存中间文件
# 返回对照关系
def parse_font(s, record=False):
    data = base64.b64decode(s)
    maoYanFont = TTFont(io.BytesIO(data))
    if record:
        font.saveXML("maoyan.xml")
        font.save("maoyan.woff")
        # maoYanFont = TTFont("maoyan.woff")
    maoYanUnicodeList = maoYanFont["cmap"].tables[0].ttFont.getGlyphOrder()[2:]
    comparisonTable = {".": "."}

    # 外层循环是遍历输入字体的每个数字,对每个数字,去标准对照组中寻找相同坐标的对应的数字
    # maoYanGlyph、baseGlyph可以看作是字体的坐标
    for i in range(10):
        maoYanGlyph = maoYanFont["glyf"][maoYanUnicodeList[i]]
        for j in range(10):
            baseGlyph = standardFont["glyf"][standardUnicodeList[j]]
            if maoYanGlyph == baseGlyph:
                comparisonTable[maoYanUnicodeList[i][3:].lower()]=standardNumList[j]
                break
    return comparisonTable

至于页面的爬取,字体base64的获取相对较简单,但是注意,python大部分库解析html页面时,对&开头的会解析为unicode,例如解析为\ue0b4需要使用repr函数将其转为原始字符串再对应。

四、总结

爬虫本质上是利用HTML是一种标记语言的特性,因此想要深入掌握爬虫,必须对前端HTML+CSS+JS有一定的了解,无需掌握透彻,只需要能够大概知道实现原理即可。比如猫眼的CSS反爬不过是使用CSS的字体而已。

上一篇下一篇

猜你喜欢

热点阅读