网络爬虫之字体加密混淆:起点中文网

09/09 12:21
阅读数 395

岁月匆匆,往事如年。经历了前面几篇的基本爬虫(静态与动态),相信看过的小伙伴已经对爬虫的流程有一定的了解。这次小编带大家来解决起点中文网的字体反爬,希望这篇文章能带给你新的知识点,解决你所遇到的难题。

操作环境: Windows10、Python3.6、pycharm2019.3、谷歌浏览器
目标网址: https://book.qidian.com/info/1009704712(牧神记)
相关文章: 爬虫(豆瓣电影拉钩网腾讯zp新笔趣阁链家网),豆瓣分析

==============================================


一、分析网页

1.1、静态数据

  这里以起点中文网的一篇小说为例:宅猪著作《牧神记》。复制需要获取的字段,打开查看网页源码,快捷键Ctrl+F查看字段数据是否存在,存在即静态数据,反之为ajax动态数据。
在这里插入图片描述
  但是由分析得出,汉字字段是正常的数据,而数字字段却被字体文件所加密混淆。如下图可看出,总字数中的数字5为:𘡝
在这里插入图片描述





1.2、基本流程

  1、请求页面
  2、获取加密的字体库
  3、解析字体库,获取字体间的映射关系
  4、获取加密的字体,获取字体间映射关系,一一对应



二、请求解析

2.1、请求目标网址

  导入相关库,设置好请求头信息。

# 导入相关库
import requests

headers = {     # 请求头  伪造身份
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36',
}

if __name__ == '__main__':
    url = 'https://book.qidian.com/info/1009704712'
    # 请求目标网址并编码
    response = requests.get(url=url,headers=headers).text
    print(response)

代码展示部分运行结果,数据无误,请求成功。
在这里插入图片描述



2.2、字体加密

2.2.1、查看字体加密文件

  1、打开检查
  2、鼠标点击查看数字加密位置
  3、class属性KvrLqLSs查看css规则
  4、源码查看font-family


在这里插入图片描述
 一般来说KvrLqLSs属性最有可能是字体加密文件的关键参数。由图片可看出.woff的结尾的链接包含KvrLqLSs属性,最有可能是字体加密文件。
在这里插入图片描述




2.2.2、正则提取

  导入re正则模块import re,定义一个get_font函数用于提取源码中的字体加密文件.woff。

  html参数为传入的目标网页源码。

# 获取加密字体文件url
font_link = re.findall(r"format\('eot'\); src: url\('(.*?)'\) format\('woff'\)",html)[0]    
print(font_link)

输出结果:
在这里插入图片描述

  点击输出获取到的字体加密链接,或者复制链接到浏览器中单独打开,即可在网页中下载字体文件。使用 High-Logic FontCreator 软件打开查看字体加密规则。
在这里插入图片描述






2.2.3、保存字体文件

  split(’’):以 \ 分割。

response_woff = requests.get(url=font_link)     #请求加密字体文件url
filename = font_link.split('/')[-1]     #定义文件名字
with open(filename,'wb') as f:
    f.write(response_woff.content)

2.3、字体映射

  导入fontTools模块中的TTFont函数方法,即from fontTools.ttLib import TTFont。将字节文件转化为xml格式。

  font_name: 为前面所保存的字体文件名字。

# 把字体文件读取为Python能理解的对象
base_font = TTFont(font_name)
# 保存为XML格式
base_font.saveXML('font.xml')

  查看保存好的xml文件的cmap标签里的字体映射规则:(与之前打开的字体文件链接查看的规则十分相似,只是阿拉伯数字变成英文数字
在这里插入图片描述


  自定义规则与映射规则



# 自定义匹配规则
eng_2_num = {
    'period': ".", 'two': '2', 'zero': '0', 'five': '5', 'nine': "9", 'seven': '7', 'one': '1', 'three': '3',
    'six': '6', 'four': '4', 'eight': '8'
}
# 把字体文件读取为Python能理解的对象
base_font = TTFont(font_name)
# 保存为XML格式
base_font.saveXML('font.xml')
# 获取映射规则(在cmap标签内)
map_list = base_font.getBestCmap()
print('映射前的规则:',map_list)
for key in map_list.keys():
    map_list[key] = eng_2_num[map_list[key]]
print('映射后的规则:',map_list)

代码输出结果为:

映射前的规则: {100543: 'eight', 100545: 'four', 100546: 'seven', 100547: 'nine', 100548: 'three', 100549: 'five', 100550: 'two', 100551: 'one', 100552: 'six', 100553: 'zero', 100554: 'period'}
映射后的规则: {100543: '8', 100545: '4', 100546: '7', 100547: '9', 100548: '3', 100549: '5', 100550: '2', 100551: '1', 100552: '6', 100553: '0', 100554: '.'}

2.4、终极替换

  定义一个new_replace函数,传入字体映射规则map_list,以及网页源码old_html。

  将加密规则替换为页面正确数字。注意网页源码中的加密字体是𘣅而字体映射规则map_list中的却是100549,漏缺的&#;需要自行填补上。

# 终极替换正确字体
def new_replace(map_list,old_html):
    new_html = old_html
    for key,value in map_list.items():
        # print(key,value)
        #   𘣅 5
        # 将加密规则替换为页面正确数字
        new_html = new_html.replace('&#' + str(key) + ';',value)
    new = new_html
    print(new)

 查看替换后的网页源码,代码输出结果为:(与网页展示数据一致,字体反爬解决,替换成功。
在这里插入图片描述



三、提取数据

  导入parsel解析库,将网页源码转换为Selector对象,以便使用xpath或者css语法提取数据。
  new: 替换后的正确网页源码

import parsel
selector = parsel.Selector(new)

  使用css语法提取各字段数据。

title = selector.css('div.book-info h1 em::text').extract_first()   #获取小说标题
author = selector.css('div.book-info h1 span a::text').get()    #获取作者
# 获取小说标签
label1 = ','.join(selector.css('p.tag span::text').getall())
label2 = ','.join(selector.css('p.tag a::text').getall())
label = label1 + ',' +label2
tiny = selector.css('p.intro::text').get()
# 获取小说总字数
number1 = selector.css('div.book-info p:nth-child(4)  em:nth-child(1) span::text').get()
number2 = selector.css('p cite:nth-child(2)::text').get()
number = number1 + str(number2)
# 获取总推荐
recom1 = selector.css('div.book-info p:nth-child(4) em:nth-child(4) span::text').get()
recom2 = selector.css('p cite:nth-child(5)::text').get()
recommend = recom1 + str(recom2)
# 获取总推荐
wkmend1 = selector.css('div.book-info p:nth-child(4) em:nth-child(7) span::text').get()
wkmend2 = selector.css('p cite:nth-child(8)::text').get()
wkmend = wkmend1 + str(wkmend2)
intro = ','.join(selector.css('div.book-intro p::text').extract()).strip()    #获取小说简介
print(title,author,'\n',label,'\n',tiny,'\n',number,recommend,wkmend,'\n',intro)

代码输出结果为:(若爬取多个的,即先获取到每个小说的详情页简介链接,传入之前的get_font获取字体映射规则函数即可。)
在这里插入图片描述



四、项目总结

  本次项目重在解决字体反爬,没有写上持久化保存,若想保存数据,参考之前的文章即可。

  字体反爬解决在于找到正确的字体映射规则,然而起点中文网只是静态的字体加密文件,换句话说是规则“写死了”,分析自行定义字体规则即可。若遇到每请求便更新字体文件规则的才是恶心,后续小编会带大家解决这个问题。敬请期待!

  “赠人玫瑰,手有余香”,看完的小伙伴记得点赞收藏,感谢!

  若有小伙伴有疑惑的地方,可在评论区留言,小编看到会尽快一一回复;此项目有需要改进的地方,也请大佬不吝赐教,感谢!

注:本项目仅用于学习用途,若用于商业用途,请自行负责!!




展开阅读全文
打赏
1
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
1
分享
OSCHINA
登录后可查看更多优质内容
返回顶部
顶部