python反爬虫 自定义字体2

上一篇讲的是网页中使用固定的字体映射表,也就是网页中显示的数据编码和真实数据的映射在一段时间内不会发生变化。但是,有的网页中对应的映射会随时发生变化,我们以东方财富网为例,下图是我们一开始所抓取得到的部分信息
在这里插入图片描述
我们在不同的时间内分别下次其网页中使用的字体文件,并将其转化为xml文件来进行查看。

字体1字体2
centered 文本居中right-aligned 文本居右

会发现每个字体文件中的code都会发生变化,并且name也是一些看不懂的字符串,不像我们之前所看到的uni编码的字符可以直接进行转化,那怎么办呢?仔细观察的话可以发现两个字体文件中的name的值都是一样,因此我们可以判断不管你在网页中使用什么样的自定义字体,虽然每一次code都会发生变化,但是其中的name并不会发生变化,多尝试几次后发现事实便是如此。因此我们只需要把name多代表的真实数据的映射给表示出来即可,再通过该映射把网页中使用的自定义字体的code:name映射进行替换即可。

对于name所对应的值,我们可以去查看xml文件中其对应的对象,以bgldyy为例,可以看到
在这里插入图片描述
其中每对(x,y)表示的便是bgldyy所代表的真实数据的坐标,如下
在这里插入图片描述
显然,通过我们自己是无法知道这些坐标的组合所代表的数据到底是多少,因此这个时候就需要借助其他软件了,这里我们使用百度字体编辑器,将我们得到的字体文件导入到其中,可得(论文推导多了,现在不管什么都是写个可得(捂脸))
在这里插入图片描述
因此我们可以写出name与真实数据的映射(上图中的$xxxx为网页中所对应的代码点)

{'zbxtdyc':'4', 'whyhyx':'9', 'wqqdzs':'3', 'bgldyy':'7', 'nhpdjl':'5', 'qqdwzl':'1', 'bdzypyc':'0', 'zwdxtdy':'8', 'sxyzdxn': '6', 'zrwqqdl':'2'}

通过上述映射,我们便可以实现当前网页中所使用的自定义字体的映射表,如

{'0xe273':'nhpdjl',
'0xe375':'bdzypyc',
'0xe426':'bgldyy'}

所对应的真实数据的映射为

{'0xe273':'5',
'0xe375':'0',
'0xe426':'7'}

再将所得到的映射表与网页源码中的显示的代码点(如:&#xE426)进行替换即可得到真实的数据信息。

其他不多说,直接上源码,想说的都写在注释里了:

import requests
from pyquery import PyQuery as pq
import re
from fontTools.ttLib import TTFont

HEADERS = {
		'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36'
	}

def download_html(url):
	"""
	用于下载网页源码,当网页下载失败时,抛出异常
	:param url: 网页链接
	:return: 网页源码
	"""
	response = requests.get(url = url, headers = HEADERS)
	if response.status_code == 200:
		return response.text
	else:
		raise Exception('url download failed, please retry')

def font_map(html):
	"""
	获取当前网页中所使用的自定义字体的映射,其具体步骤为:
	1.获取当前网页中所使用的自定义文件的地址,并对其进行下载
	2.首先在不提取数据的情况下观察字体文件(转化为xml文件观察)内容,得到相应的{name:真实数据}映射
	3.得到当前网页所使用的字体映射{code:name}
	4.根据2中得到的映射表,将3中的映射表进行相应的替换,得到{code:真实数据}映射
	:param html: 当前网页的源码
	:return: 当前网页所使用的自定义字体{code:真实数据}映射
	"""
	font_url = re.findall(r'"WoffUrl":"(.*?woff)', html, re.M)   # 当前网页所使用的自定义字体文件地址 
	font = requests.get(font_url[0], headers = HEADERS).content
	with open('new_font.woff', 'wb+') as f:
		f.write(font)
	font = TTFont('new_font.woff')
	# font.saveXML('new_font.xml')   # 将字体保存为xml文件以方便查看
	fontdict = {'zbxtdyc':'4', 'whyhyx':'9', 'wqqdzs':'3', 'bgldyy':'7', 'nhpdjl':'5', 'qqdwzl':'1', 
		'bdzypyc':'0', 'zwdxtdy':'8', 'sxyzdxn': '6', 'zrwqqdl':'2'}  # 一个基本的{name:真实数据}映射表,供后面使用
	font_map = {}  # 用于存储当前页面所使用的自定义字体映射的字典
	for key, value in font.getBestCmap().items():   # 使用getBestCmap()获取字体文件中包含的映射关系
		if value.startswith('uni'):   # 判断是否是uni编码
			font_map[hex(key).upper()] =  chr(int(value[3:], 16))   # 这里的upper需看网页中显示的代码点是否是大写的,如果是小写的话,就不需要使用这个了 
		else:
			font_map[hex(key).upper()] = value
	font_map.pop('0X78')    # 去掉第一个没用的code
	for key, value in font_map.items():   # 根据之前得到的{name:真实数据}映射,将font_map中的name进行替换
		font_map[key] = fontdict[value]
	new_font_map = {}
	for key, value in font_map.items():  # 根据网页中的code显示格式来进行替换
		key = key.replace('0X', '&#x')
		new_font_map[key] = value
	return new_font_map

def parse_data(html, new_font_map):
	"""
	抓取我们所需要的数据,并将其中的code代码点进行替换为真实数据显示
	这里我们只选用了众多数据中的一条来进行显示
	:param html: 当前网页的源码
	:param new_font_map: 当前网页所使用的自定义字体的{code:真实数据}映射表
	:print: 抓取的数据
	"""
	results = re.findall(r'defjson:.*?data: \[(.*)],font', html, re.S)
	datas = results[0]
	result = re.findall(r'{(.*?)}', datas)[0]
	for key, value in new_font_map.items():   # 根据所得到的{code:真实数据}映射将网页源码进行替换
		if key in result:
			result = re.sub(key, value, result)
	result = result.replace(';', '')
	print(result)

def main(url):
	"""
	爬虫入口
	:param url: 当前访问的网页链接
	"""
	html = download_html(url)
	new_font_map = font_map(html)
	parse_data(html, new_font_map)

if __name__ == '__main__':
	url = 'http://data.eastmoney.com/bbsj/201806/lrb.html'
	main(url)

得到的部分结果为:
在这里插入图片描述
与原始网页比较可知,能够正确的实现字体的替换。

好好学习,天天向上。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值