首先看看css3的字体,http://www.runoob.com/css3/css3-fonts.html
正文开始:打开https://piaofang.maoyan.com/?ver=normal
很高兴,又是一个字体反爬的网站,和标题对应的来了,
将其复制,并通过base64解密后保存为ttf文件,再通过fontTools,将其打开,并保存为xml文件
import base64
from fontTools.ttLib import TTFont
a=base64.b64decode('d09.........')
with open('2.ttf','wb')as f:
f.write(a)
font = TTFont('2.ttf')
font.saveXML('2.xml')
并用High-Logic FontCreator打开,效果如下
;对应的是4,很明显,就是‘uni’+''.replace('&#x','').replace(';','')。不信?多对应几个
再来打开刚刚保存的xml
<GlyphOrder>....</GlyphOrder>内包含着所有编码信息,注意前两个是不是0-9的编码,需要去除,另外不要误以为id就是对应的值,很明显是对应不上的,这里的name对应的是字符对象<TTGlyph>的name
<glyf>... </glyf>内包含着每一个字符对象<TTGlyph>,这里是第一个和最后一个不是0-9的字符,需要祛除。 画框框的才是真正对应的数字,那怎么对应起来呢?
例如打开有用的第一个,信息如下,xy可以看做是坐标,画出线图,那是否就出现具体的字体了?
出动matplotlib
import matplotlib.pyplot as plt
import re
a='''
<TTGlyph name="uniE044" xMin="0" yMin="-12" xMax="510" yMax="719">
<contour>
<pt x="410" y="534" on="1"/>
<pt x="398" y="586" on="0"/>
<pt x="377" y="609" on="1"/>
<pt x="341" y="646" on="0"/>
<pt x="289" y="646" on="1"/>
<pt x="247" y="646" on="0"/>
<pt x="215" y="623" on="1"/>
<pt x="173" y="592" on="0"/>
<pt x="150" y="535" on="1"/>
<pt x="138" y="506" on="0"/>
<pt x="125" y="423" on="0"/>
<pt x="125" y="369" on="1"/>
<pt x="157" y="418" on="0"/>
<pt x="248" y="464" on="0"/>
<pt x="299" y="464" on="1"/>
<pt x="386" y="464" on="0"/>
<pt x="510" y="334" on="0"/>
<pt x="510" y="232" on="1"/>
<pt x="510" y="165" on="0"/>
<pt x="452" y="49" on="0"/>
<pt x="352" y="-12" on="0"/>
<pt x="286" y="-12" on="1"/>
<pt x="176" y="-12" on="0"/>
<pt x="38" y="147" on="0"/>
<pt x="38" y="335" on="1"/>
<pt x="38" y="543" on="0"/>
<pt x="114" y="637" on="1"/>
<pt x="181" y="719" on="0"/>
<pt x="294" y="719" on="1"/>
<pt x="379" y="719" on="0"/>
<pt x="433" y="671" on="1"/>
<pt x="486" y="625" on="0"/>
<pt x="498" y="541" on="1"/>
</contour>
<contour>
<pt x="139" y="232" on="1"/>
<pt x="139" y="188" on="0"/>
<pt x="178" y="103" on="0"/>
<pt x="247" y="60" on="0"/>
<pt x="285" y="60" on="1"/>
<pt x="339" y="60" on="0"/>
<pt x="420" y="150" on="0"/>
<pt x="420" y="227" on="1"/>
<pt x="420" y="300" on="0"/>
<pt x="341" y="387" on="0"/>
<pt x="223" y="387" on="0"/>
<pt x="139" y="301" on="0"/>
</contour>
<instructions/>
</TTGlyph>
'''
x=[int(i)for i in re.findall('x="([-]{0,1}\d+)" y="',a)]
y=[ int(i) for i in re.findall('y="([-]{0,1}\d+)" on="',a)]
plt.plot(x, y)
plt.show()
额。。。这个是6,不是8,8如下图
很高心,将uni编码与具体的数字对应起来不需要看ttf文件了
特别提示:每次访问网页的ttf文件里内容是不一样的,数字顺序不一样,uni编码也不一样。那不是需要每次画出图,通过机器视觉识别(高大上,不会的东西),答案是不需要,虽然uni与数字顺序不一样,都是每个数字对于的xy坐标是不变的,哈哈,意思就是我们将一组对应起来,之后再根据这组数据与每次访问得到的新数据的TTGlyph对象做对比即可
再对比两个6对应的TTGlyph对象
结论:一模一样,好到这就分析完了,开始代码
import requests
import re
import base64
from fontTools.ttLib import TTFont
from bs4 import BeautifulSoup
def analysis(movie_price:list,maps:list,font):
data=[]
for i in movie_price:
analysis_befores=i
analysis_before_Datas=re.findall('[a-tw-z0-9]{4}',i)
# 获取所有<TTGlyph>的name,去除首尾
for analysis_before_Data in analysis_before_Datas:
analysis_before='uni'+analysis_before_Data.upper()
obj2 = font['glyf'][analysis_before]#获取对应坐标对象
if obj2 in maps[0] : # 坐标是一样的,那么对应的字体也是一样的
index=maps[0].index(obj2)
print('\\u' + analysis_before_Data, str(maps[1][index]))
analysis_befores=analysis_befores.replace('\\u' + analysis_before_Data, str(maps[1][index]))
data.append(analysis_befores)
return data
def down_ttf_xml(ttf_Data:str):
data=base64.b64decode(ttf_Data)
with open('new_request.ttf','wb')as f:
f.write(data)
font = TTFont('new_request.ttf')
font.saveXML('new_request.xml')
font.close()
def get_page(url:str,maps:list):
data=[]
headers = {
"User-Agent": "Mozilla/5.0....",
}
response=requests.get(url,headers=headers,verify=False)
ttf_Data=re.findall('charset=utf-8;base64,(.*?)\)',response.text)[0]
down_ttf_xml(ttf_Data)
soup = BeautifulSoup(response.text, "html.parser")
movie_name=[]
name_tags=soup.select('#ticket_content div.content > ul > li.c1 > b')
for name_tag in name_tags:
movie_name.append(name_tag.string)
movie_time=[]
time_tags=soup.select('#ticket_content div.content > ul > li.c1 > em:nth-of-type(1)')
for time_tag in time_tags:
movie_time.append(time_tag.string)
movie_price=[]
price_tags=soup.select('#ticket_content div.content > ul > li.c1 > em:nth-of-type(2) > i')
for price_tag in price_tags:
# 防止自动转义
movie_price.append(repr(price_tag.string))
font = TTFont('new_request.ttf')
movie_price=analysis(movie_price,maps,font)
for i in range(len(movie_name)):
data_1=[]
data_1.append(movie_name[i])
data_1.append(movie_time[i])
data_1.append(movie_price[i])
data.append(data_1)
return data
if __name__=='__main__':
url='https://piaofang.maoyan.com/?ver=normal'
data_source = {'uniE113': 3, 'uniE3AD': 4, 'uniF55D':5, 'uniED36': 2, 'uniF57A': 8,
'uniF7E0': 0, 'uniEB7B': 1,'uniF0ED': 9, 'uniE044': 6, 'uniF8C5': 7}
maps=[[],[]] #建立映射
font = TTFont('2.ttf')
# 获取所有<TTGlyph>的name,去除首尾
uni_list1 = font.getGlyphNames()[1:-1]
for uni1 in uni_list1:
# 获取编码uni1在1.ttf中对应的对象,暂时可以理解为那一大堆坐标
obj1 = font['glyf'][uni1]
maps[0].append(obj1)
maps[1].append(data_source[uni1])
data=get_page(url,maps)
for i in data:
print(i)
'''
['惊奇队长', '上映3天', "'4.90亿'"]
['夏目友人帐', '上映4天', "'7091.2万'"]
['绿皮书', '上映10天', "'2.71亿'"]
['驯龙高手3', '上映10天', "'3.05亿'"]
['阿丽塔:战斗天使', '上映17天', "'8.47亿'"]
['流浪地球', '上映34天', "'45.97亿'"]
['熊出没·原始时代', '上映34天', "'7.09亿'"]
['飞驰人生', '上映34天', "'17.12亿'"]
['醒来之爱的呼唤', '上映3天', "'116.9万'"]
['魔神Z', '上映3天', "'27.5万'"]
['江海渔童之巨龟奇缘', '点映', "'23.6万'"]
['新喜剧之王', '上映34天', "'6.23亿'"]
['老师·好', '点映', "'1.7万'"]
['浴血广昌', '上映222天', "'9722.5万'"]
['朝花夕誓-于离别之朝束起约定之花', '上映17天', "'1712.9万'"]
['比悲伤更悲伤的故事', '点映', "'72.0万'"]
['一吻定情', '上映25天', "'1.73亿'"]
['古井凶灵', '上映17天', "'478.7万'"]
['逆罪', '上映10天', "'18.5万'"]
['我们的爱情', '上映3天', "'8.1万'"]
'''