python爬取带stonefont字体网页的经历

一、问题描述

在爬取某电影网站票价信息时,使用selenium定位票价元素信息时,发现票价显示“□□”,如下图所示:

python爬取带stonefont字体网页的经历_第1张图片

而通过chrome浏览器“查看网页源代码”方式查看该元素数值时,显示的是非正常票价数值,如下图所示:

python爬取带stonefont字体网页的经历_第2张图片

二、 问题解决思路

百度查询相关解决方案,发现该网页使用了web-font字体,网页在打开时调用美团字体库对页面中数值进行渲染,需要找出当前网页使用的字体库,因为每次打开网页调用的字体库不一样, 所以需要每次都与基本库字形进行对比,找出实际对应的数字。在该网页源代码中字体库地址如下图所示:

python爬取带stonefont字体网页的经历_第3张图片

三、解决流程

1、环境

from  selenium import webdriver
from selenium.webdriver.chrome.options import Options
from fontTools import ttLib

FontCreator软件,用于查看下载的字体库文件,可以比较直观的查看字形定义和字形代码。

2、解决流程

1)下载字体文件

下载网页字体库文件woff,保存到电脑中(文件后缀为woff),用于建立用于后期对比的基本字形库(字形名和字形定义),只下载一次即可。需要使用正则表达式搜索网页源代码中字体下载地址。这部分功能用的requests库,其它用的selenium,其实也可以全部用selenium,requests和selenium在解决该类问题时的区别在后面再说一下。

tem_re = re.compile(r"vfile.*?woff")
font_url = r'http://' + tem_re.findall(driver.page_source)[0] #获取当前页面字体库下载地址
print('当前页面字体文件地址:', font_url)
resp = requests.get(font_url)
with open(r'd:\current.woff', 'wb') as fontfile:              #将当前页面字体库下载至current.woff
    fontfile.write(resp.content)

2)字体文件格式说明

(1)用FontCreator打开下载的字体文件,如下图:

python爬取带stonefont字体网页的经历_第4张图片

字形文件共12个元素,主要看10个数字对应的编号关系,建立每个数字和编号的对应关系。自定义的基本字体库:

base_woff_list=['uniE4C4','uniF2B6','uniEABA','uniF682','uniE663','uniF89C','uniF612','uniE2B5','uniF133','uniEA59']
base_num_list=['7','1','8','4','0','2','5','6','3','9']

(2) 字体库的字形定义

可以将下载的woff文件解析为xml文件,命令:

 
  
current_woff=ttLib.TTFont(r"*.woff")
base_font_woff.saveXML() # base_font_woff是字体文件对象,将字体文件解析出XML文件

用浏览器查看字形定义,方框中就是某个数字的字形定义,也是之后用于与其他网页票价信息中某个数字字形相比较,从而确定到底对应的是0-9哪个数字。“uniE18F”是这个数字对应的ID

python爬取带stonefont字体网页的经历_第5张图片

(3)字形比较

current_woff['glyf']['字符ID']==base_woff['glyf']['字符ID']
current_woff['glyf']['字符ID'] #该字符ID的字形定义对象,  也就是上图中大方框中的内容,像素瞄点

字形比较是程序中的核心部分,也就是字符解码。

四、其他问题

1)网页源代码问题

chrome浏览器用"检查元素"和“查看网页源代码”两种方式获得的网页内容不一样,前者对使用字体库的票价数字只显示“□□”,而查看网页源代码可以获得该数字的unicode编码。那么问题来了,如何通过selenium的xpath方式得到该数字的unicode编码,如何你使用如下语句,用print方式无法显示正常字符:

price_list=driver.find_elements_by_xpath("//span[@class='price-num red']") #获取当前页面票价list
print(price_list[0].text[0])#输出票价的第一位数字,实际什么也不显示

这里面需要使用str到unicode(class is byte)的转码,在把转码结果强制转换为str,最后把str截取后四位字符ID,再与“uni”字符串结合确定该数字对应的字符ID。核心对比代码如下:

current_woff['glyf']['uni'+str(temp_font_tag.encode('unicode_escape'))[5:9].upper()]!=base_woff['glyf'][base_woff_list[z]]

2)其他

为了得到票价数字的unicode破费一番周折,应为webdriver对象的page_source也无法正常显示。BeautifulSoup对象也无法正常显示。只有requests对象可以直接显示票价数字的unicode码。好累啊,哈哈。

总结:python业余爱好者,非科班出身,也不从事编程工作,纯粹爱好,遇到这类stonefont字体问题也百度了几篇参考文献,自己梳理的自认为核心问题在这里总结,写的不全面勿喷,全部代码就不贴了。

参考文档:

https://blog.csdn.net/FengHuaJianShi/article/details/78404216

https://blog.csdn.net/qq_31032181/article/details/79153578

你可能感兴趣的:(Python)