python反爬虫 自定义字体1

在进行数据抓取时,有些网页会使用一些特殊的字符来将我们所需要的数据进行替换显示。我们以实习僧网站为例,
![在这里插入图片描述](https://img-blog.csdnimg.cn/20190427110913479.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyMjkzNzU4,size_16,color_FFFFFF,t_70在网页中我们可以看到我们所要的数据,但是当我们查看源码时,他却显示的是,显然,该网页把我们所需要的数据给隐藏起来了。我们不妨继续查看源码,会发现有如下的代码
在这里插入图片描述
从上图中我们可以知道,网页中是把我们所需要的数据给用别的类似代码的东西给替换掉了,我们只要能够将它反向给替换回来就能够得到我们的数据了。

根据在上图中的显示,我们可以知道’&#xe139’对应的是’师’,但是我们不可能把每个对应的字符都人工找出来,这样的话就和我们爬取数据的初衷违背了,那有没有什么方法可以把网页中的所有编码以及对应的真实字符给全部找到呢?答案当然是有。

我们在源码中搜索font字符,会找到如下的内容
在这里插入图片描述
这上面的那一场串的看不懂的东西便是本网页中所使用的字体文件。由于这里使用base64来进行加密了,所以我们将这串字符复制下来并通过base64.b64decode解密保存到本地,注意须将其保存为woff或ttf文件。由于所得到的文件无法直接打开,我们可以将其转化为xml文件来查看。
在这里插入图片描述
仔细观察该文件,我们可以知道上面的code编码对应的值便是在网页中所替换的值,而name所对应的值便是我们所要的真实值。由于实习僧网页是直接使用的字符编码,直接将真实字符使用uni编码,所以我们只要将name的值转化为真实的值即可(这里我们可以使用python中的`chr``方法)。

我们举几个例子

'0xe064':'uni5E74',         '0xe064':'年',
'0xe0df':'uni56',           '0xe0df':'V',
'0xe112':'uni4d',           '0xe112':'M',
根据上述两个映射关系,我们便可以得到当前网页中所使用的编码与真实字符的映射关系
'0xe064':'年',
'0xe0df':'V',
'0xe112':'M',
之后再根据上述映射,将网页源码中的内容进行替换即可

多尝试几次字体文件的抓取,并通过xml文件观察,我们会发现实习僧网站中所使用的编码codename的值在一段时间内不会发生变化,因此,在一段时间内,我们只要把所有编码的映射找出来就行了。当然也可以自己手写一个映射表,这里我们可以借助High-Logic FontCreator软件,他可以直接把网页中的字体文件显示为真实的字符,如下
在这里插入图片描述
把鼠标放在字符上便可以看到其对应的编码(如果没有显示的话,按下Alt键)。

一般来说对于这种固定的自定义字体的网页来说,自己把所有的编码字体映射写出来过于麻烦,当然有些网页使用的字体会一直变化,这就需要我们都写出来了,这个我们以后再讲。因此在确定编码字体映射时一般会借助fontTools库来实现。其首先通过getBestCmap()方法来获取所有的code:name键值对,然后再根据我们所确定的name:真实值映射表,来确定当前网页中所使用的编码字体映射。

完整代码如下:

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

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 abnormal(f):  # 异常装饰器
	@functools.wraps(f)
	def func(*args, **kwargs):
		try:
			return f(*args, **kwargs)
		except Exception as e:
			print('==== insert exception -->>> %s'% e)
	return func

@abnormal
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')

@abnormal
def font_map(content):
	"""
	用于获取当前页面自定义字体所使用的映射表,供后面替换使用
	:param content: 所获得的网页源码
	:return: 当前网页中所使用的字符代码和真实字符映射
	"""
	font_face = re.findall(r'font-face.*?base64,(.*?==?=?)', content, re.M)   # 获取当前页面所使用由base64加密的字符串 
	font_decode = base64.b64decode(font_face[0])   # 使用base64解密
	with open('shixiseng.woff', 'wb') as f:    # 将解密得到的内容保存到本地
		f.write(font_decode)
	font = TTFont('shixiseng.woff')
	# font.saveXML('shixiseng.xml')  # 由于ttf文件需要一些专门的软件才能够打开,为能够直接的对其内容进行观察,我们可以将其转化为xml文件后可以直接查看
	font_map = {}         # 用于存储当前页面所使用的自定义字体的映射表
	for key, value in font.getBestCmap().items():   # 使用getBestCmap方法来获取字体文件中包含的映射关系
	# 这里需要注意的是,由于getBestCmap()会将内容转化为10机制,因此在后面存入字典的时候还要转化为16进制,使用hex(), 或者使用'\u{:x}'.format(x)
		if value.startswith('uni'):                 # 判断是否是uni编码
			font_map[hex(key)] =  chr(int(value[3:], 16))    # 由于实习僧网页中直接使用的是字符编码,所以可以直接用chr方法显示出真实字符
		else:
			font_map[hex(key)] = value
	font_map.pop('0x78')  # 由于第一行的map没有用,将其去除
	new_font_map = {}
	for key, value in font_map.items():        # 根据网页源码显示内容将映射表中的内容进行相应的替换
		key = key.replace('0x', '&#x')
		new_fonew_font_mapnt_map[key] = value
	# print(new_font_map)
	return new_font_map

@abnormal
def font_replace(content, new_font_map):
	"""
	将网页中的自定义字体使用我们得到的字体映射进行替换
	判断寻找映射中的键是否在未处理的网页源码中,若存在,则用相应的值进行替换
	:param content: 有编码字体的网页源码
	:param new_font_map: 网页中所使用的自定义字体映射
	:return: 根据自定义字体映射进行替换后得到的网页源码
	"""
	for key, value in new_font_map.items():
		if key in content:
			content = re.sub(key, value, content)
	return content

@abnormal
def parse_html(content):
	"""
	提取我们所需要的数据信息
	:param content_replace: 替换之后的网页源码
	"""
	doc = pq(content)
	for result in doc('div.info1.clearfix').items():
		position_name = result('a.position-name').text()
		position_salary = result('span.position-salary').text()
		print(position_name, position_salary)

def main(url):
	"""
	爬虫入口
	:param url: 当前抓取页面的链接
	"""
	html = download_html(url)
	new_font_map = font_map(html)
	content_replace = font_replace(html, new_font_map)
	parse_html(content_replace)

if __name__ == '__main__':
	url = 'https://www.shixiseng.com/interns/c-None_st-None_?k=python'
	main(url)

得到的结果为
在这里插入图片描述
发现与网页中显示的结果一致,这样我们便解决了一个简单的自定义字体的反爬虫。

好好学习,天天向上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值