编译环境:win10+python3.6+pycharm2017
目标:获取猫眼票房的电影名称和票房数据
目标网址:https://piaofang.maoyan.com/?ver=normal
网址页面:
大概思路:猫眼票房获取完整HTML的话只需要添加user-agent即可,但是HTML中我们可以发现通过beautifulsoup库对HTML进行解析之后的得到的电影名称是对的但是里面的数据如上映总票房却并不是我们所看到的那样,而是用一些特定的字符代替的,这也就是猫眼票房的难点,所以我们首先要做的就是对这些字符进行解析,得到字符和数字的对应关系。
检察源代码我们可以看到数字对应的字符,因为猫眼电影的字体是有多套的,所以我们直接去记录数字和字符的对应关系是没有多大意义的。
在源代码里搜索font我们可以看到网页里的字体是通过base64编码的,我们可以通过正则获取这些编码,然后通过base64写入到本地文件,这样我们就可以获取当前网页的ttf字体文件。
s=re.findall(r'@font-face.*?base64,(.*?)\)',html)
# print(s[0])
b=base64.b64decode(s[0])
with open("e.ttf","wb") as f:
f.write(b)
fontcreator下载地址:http://fastsoft.onlinedown.net/down/FontCreatorSetup_88758.zip直接点击链接即可下载
我们可以通过fontcreator来查看ttf字体文件中字符和数字的对应关系
因为网页有多套字体文件所以我们单纯的记录这个对应关系是不能实现我们的目的的,这里就需要引入一个字体库fonttools,安装方法也很简单,直接pip install fonttools 即可,通过fonttools我们可以对字体文件做一些处理,我们首先可以通过fonttools把字体文件转化为XML格式,这样我们就可以通过浏览器查看里面的内容
from fontTools.ttLib import TTFont
font=TTFont("c.ttf")
font.saveXML("d.xml")
通过浏览器打开XML文件我们可以看到ttf字体里面的内容.
在XML中我们可以看到glyphorder里包含了对应的编码信息我们可以通过fonttools读取glyphorder即可获取对应的编码信息,往下翻到glyphname,我们可以看到每一个编码都有对应的x和y坐标仔细分析可以得出这些坐标应该就是用来绘制数字的形状的,那么这个对象就是唯一的,所以我们可以通过比对这个对象来辨别数字,具体思路是保存一个字体文件1读取其中的编码信息,创建一个编码和数字相对应的字典,读取对象信息作为比对,然后爬取网页的时候获取当前网页的字体文件,获取当前字体文件的编码信息和对象信息,通过比对对象信息找到这个对象对应字体2的编码和字典中对应的数字,然后调用str.replace方法把HTML中的编码转换成相对应的数字,然后就可以正常的对网页进行分析了。
源代码如下:
import base64
from fontTools.ttLib import TTFont
import re
import requests
from bs4 import BeautifulSoup
dict={"uniF839":"5",
"uniE9DE":"9",
"uniE03E":"8",
"uniF541":"4",
"uniE565":"2",
"uniF51A":"3",
"uniE099":"0",
"uniF2B6":"6",
"uniE4E2":"1",
"uniED40":"7",
}
font1=TTFont("c.ttf")
uni_list1=font1.getGlyphOrder()[2:]
obj_list1=font1.getGlyphNames()[1:-1]
def get_text(url):
try:
headers={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36'}
r=requests.get(url,headers=headers)
print(r.status_code)
r.raise_for_status()
r.encoding=r.apparent_encoding
# print(r.text)
return r.text
except:
return "11111"
def get_correct_html(html):
s=re.findall(r'@font-face.*?base64,(.*?)\)',html)
# print(s[0])
b=base64.b64decode(s[0])
with open("e.ttf","wb") as f:
f.write(b)
font2=TTFont("e.ttf")
uni_list2=font2.getGlyphOrder()[2:]
obj_list2=font2.getGlyphNames()[1:-1]
for c2 in uni_list2:
obj2=font2["glyf"][c2]
for c1 in uni_list1:
obj1=font1["glyf"][c1]
if obj1==obj2:
code_lower="&#x"+c2[3:].lower()+";"
html=html.replace(code_lower,dict[c1])
print(c2,dict[c1])
return html
def get_info(html):
soup = BeautifulSoup(html, "lxml")
titles = soup.select("#ticket_tbody > ul> li.c1 > b")
name = []
for i in titles:
name.append(i.string)
nums = soup.select("#ticket_tbody > ul> li.c1 > em > i")
pf = []
for t in nums:
pf.append(t.string)
for ii in range(len(pf)):
print(name[ii], pf[ii])
if __name__=="__main__":
url="https://piaofang.maoyan.com/?ver=normal"
html=get_text(url)
html=get_correct_html(html)
get_info(html)