上文解决了起点中文网部分数字反爬的信息,详细链接https://www.cnblogs.com/aby321/p/10214123.html

本文研究另一种文字反爬的机制——猫眼电影实时票房反爬

虽然都是仅仅在“数字”上设置了反爬,相同点与不同点如下:

相同点:

在“数字”上设置了文字反爬
通过浏览器的“检查”显示的是“□”,但是可以在网页源代码中找到映射后的数字
正则爬的是网页源代码,xpath是默认utf-8解析网页数据,用xpath爬出来的也是方框,因此只能使用正则匹配爬取关键数字信息

不同点:

起点中文网:
每次刷新网页,通过正则爬取的数字不发生变化
使用了自定义的文字文件ttf,可爬虫提取ttf的下载地址,通过分析字体文件可以找到映射关系,并且这个映射关系是固定的

猫眼电影:
每次刷新网页(中间间隔几秒时间),通过正则爬取的数字发生变化
无字体文件ttf
在源代码中搜索‘font-face’可查询到一堆字符串,预测应该是base64的编码方式,但是每次刷新网页这段字符串均会发生变化
也就是说即使通过FontTools包将这段字符串转换成ttf文件,但是每次一刷新生成的ttf文件均会发生变化,因此ttf文件中的key和value也都发生了变化

映射关系怎么找呢?

通过研究发现,虽然每次ttf不一样,但是通过ttf生成的xml文件中TTGlyph中的坐标轴所表示的“数”是固定的,这也是我们要寻找的潜在对应关系

举个栗子:
生成的这个ttf通过FontCreator软件查看,例如‘uniE124’对应的是数字‘4’
这个ttf生成的xml文件通过浏览器打开查看‘uniE124’对应的坐标是红色框内的内容;
再次刷新网页,生成了新的ttf文件,重复上两个步骤,可以看到‘uniF878’对应的数字是‘4’,生成的xml文件中‘uniF878’对应的坐标与上个xml中的一样
因此可以断定映射关系为:
任意一次生成的xml中数字潜在对应的坐标是固定的



爬取思路
1. 某次提取网页源代码中的font-face中base64后面一段字符串,生成ttf文件和xml文件,并保存到本地
2. 通过这两个文件研究其坐标和数字的对应关系,这个关系是固定不变的,每次生成的ttt/xml不同但是其内部对应关系都是这个,手动写入字典
本例中的对应关系如下:
    fontdict_local = {
'uniE346':7,
'uniE3DB':2,
'uniE4AC':4,
'uniE6BF':5,
'uniEA17':0,
'uniEBBC':1,
'uniEF7E':9,
'uniF227':3,
'uniF4C0':8,
'uniF551':6
}

3. 通过正则匹配爬取网页源代码中设置了反爬机制的数字,并进行数据前期处理

本例中需要进行以“;”分片,去掉“&#x”,判断是否含有小数点“.”,英文字母大小写转换等

4. 最重要的一步,进行比对

因为每次刷新页面或者重新运行程序都相当于会生成一个新的ttf/xml文件,因此需要将新的文件与第1步生成的文件(已保存到本地)进行坐标比对

比如新文件中若有个数字对应的坐标与本地文件中的坐标是一样的,那么就根据第2步的字典判断这个数字,在程序中坐标可以用编码对象替换

local代表是本地的文件

font_local = TTFont('font_face_local.ttf')
codelist_local = font_local.getGlyphNames()[1:-1]#第一个和最后一元素不是0-9的编码

输出(codelist_local其实就是字典的keys,只不过通过读取ttf文件自动获取,但是注意要判断下这个列表,总共有12个元素,有两个元素不是0-9的key):codelist: ['uniE346', 'uniE3DB', 'uniE4AC', 'uniE6BF', 'uniEA17', 'uniEBBC', 'uniEF7E', 'uniF227', 'uniF4C0', 'uniF551']

    for i in codelist_local:
obj_local = font_local['glyf'][i]#获取本地字体文件数字0-9的编码对象

输出:

obj_local: <fontTools.ttLib.tables._g_l_y_f.Glyph object at 0x03465950>
obj_local: <fontTools.ttLib.tables._g_l_y_f.Glyph object at 0x03465930>
obj_local: <fontTools.ttLib.tables._g_l_y_f.Glyph object at 0x03465A30>
obj_local: <fontTools.ttLib.tables._g_l_y_f.Glyph object at 0x03465970>
obj_local: <fontTools.ttLib.tables._g_l_y_f.Glyph object at 0x03465A50>
obj_local: <fontTools.ttLib.tables._g_l_y_f.Glyph object at 0x034659B0>
obj_local: <fontTools.ttLib.tables._g_l_y_f.Glyph object at 0x034659D0>
obj_local: <fontTools.ttLib.tables._g_l_y_f.Glyph object at 0x03465990>
obj_local: <fontTools.ttLib.tables._g_l_y_f.Glyph object at 0x03465A10>
obj_local: <fontTools.ttLib.tables._g_l_y_f.Glyph object at 0x034659F0>

也就是说本地的编码对象obj_local和codelist_local是一一对应的,并且每次生成的文件获取的编码对象是固定不变的
每次运行生成的文件用同样的方法获取编码对象obj,与obj_local进行比对获取codelist_local值,在通过字典获取可展示的数值,还是通过图说明一下吧



源代码
 """
猫眼电影的票房等数据(数字)设置了文字反爬机制
不同于起点中文网能直接看见ttf文件,猫眼的数字反爬更复杂些,主要表现在:
进行了web上的base64编码,并且每次刷新都会变化
通过FontTools可生成ttf和xml文件,但是每次运行生成的文件都不一样
需要找寻其内部固定的映射关系
"""
import requests, time, re, pprint,base64
from fontTools.ttLib import TTFont
from io import BytesIO
from lxml import etree def get_relation(url):
"""
获取网页源代码中的font—face中的内容,并保存成.ttf格式的文件
:param url: <str> 需要解析的网页地址
:return:<dict> 网页字体(动态变化的)编码与阿拉伯数字的映射关系
"""
#获取网页源代码中的font—face中的内容
font_face = re.findall('base64,(.*?)\) format',html_data.text,re.S)[0]
#print(font_face)
#保存成.ttf格式的文件
b = base64.b64decode(font_face)
with open('font_face.ttf','wb') as f:
f.write(b)
font = TTFont('font_face.ttf')
font.saveXML('font_face.xml')#将ttf文件生成xml文件并保存到本地
codelist = font.getGlyphNames()[1:-1] # 第一个和最后一元素不是0-9的编码
font_local = TTFont('font_face_local.ttf')
font_local.saveXML('font_face_local.xml')
codelist_local = font_local.getGlyphNames()[1:-1]#第一个和最后一元素不是0-9的编码
print('codelist:',codelist_local)
fontdict_local = {
'uniE346':7,
'uniE3DB':2,
'uniE4AC':4,
'uniE6BF':5,
'uniEA17':0,
'uniEBBC':1,
'uniEF7E':9,
'uniF227':3,
'uniF4C0':8,
'uniF551':6
}
key = []
value = []
for i in codelist_local:
obj_local = font_local['glyf'][i]#获取本地字体文件数字0-9的编码对象
print('obj_local:',obj_local)
for k in codelist:
obj = font['glyf'][k]
#print('obj:',obj)
if obj == obj_local:
#print(k,fontdict_local[i])
key.append(k.strip('uni'))
value.append(fontdict_local[i])
dict_relation = dict(zip(key,value))#网页字体(动态变化的)编码与阿拉伯数字的映射关系 #print('网络文字映射关系:')
#pprint.pprint(dict_relation)
return dict_relation def get_decode_font(numberlist,relation):
"""
对反爬数字进行解码
:param numberlist: <list> 直接从网页源代码re获得的需要解码的数字
:param relation: <dict> 解码所需的映射关系
:return: <str> 解码后的数字
"""
data = ''
for i in numberlist:
numbers = i.replace('&#x','').upper()
#print(numbers)
#小数点没有单独成为里列表的元素,与后面的数字写在了一起,需要判断下
if len(numbers)==5:
data += '.'
numbers = numbers.strip('.')
#print('numbers:',numbers)
fanpa_data = str(relation[numbers])
data += fanpa_data
print('实时票房(万元):',data+'\n')
#return data
def get_movie_info(url):
"""
爬取网页的影片名称和实时票房(网页源代码中未解码的数字)
:param url:
:return:
"""
selector = etree.HTML(html_data.text)
infos = selector.xpath('//*[@id="ticket_tbody"]/ul')
boxes = re.findall('<b><i class="cs">(.*?)</i>',html_data.text,re.S)
for info,i in zip(infos,boxes):
movie_name = info.xpath('li[1]/b/text()')[0]
movie_box = i.split(';')[0:-1]
print('影片名称:',movie_name)
#print('网页直接获取的影片实时票房:',movie_box)#一维列表形式
relation = get_relation(url)
get_decode_font(movie_box,relation) url = 'https://piaofang.maoyan.com/?ver=normal'
headers = {
'User-Agent': 'User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
}
html_data = requests.get(url, headers=headers)
get_movie_info(url)

运行结果:


还有一种更加简洁的方法:
找到obj_local和数字的关系写入字典,去掉中间的codelist_local

Python3爬取起猫眼电影实时票房信息,解决文字反爬~~~附源代码的更多相关文章

  1. Python3爬取起点中文网阅读量信息,解决文字反爬~~~附源代码

    起点中文网,在“数字”上设置了文字反爬,使用了自定义的文字文件ttf通过浏览器的“检查”显示的是“□”,但是可以在网页源代码中找到映射后的数字正则爬的是网页源代码,xpath是默认utf-8解析网页数 ...

  2. 一起学爬虫——使用xpath库爬取猫眼电影国内票房榜

    之前分享了一篇使用requests库爬取豆瓣电影250的文章,今天继续分享使用xpath爬取猫眼电影热播口碑榜 XPATH语法 XPATH(XML Path Language)是一门用于从XML文件中 ...

  3. 基础爬虫,谁学谁会,用requests、正则表达式爬取豆瓣Top250电影数据!

    爬取豆瓣Top250电影的评分.海报.影评等数据!   本项目是爬虫中最基础的,最简单的一例: 后面会有利用爬虫框架来完成更高级.自动化的爬虫程序.   此项目过程是运用requests请求库来获取h ...

  4. requests爬取豆瓣top250电影信息

    ''' 1.爬取豆瓣top250电影信息 - 第一页: https://movie.douban.com/top250?start=0&filter= - 第二页: https://movie ...

  5. Python进阶练习与爬取豆瓣T250的影片相关信息

    (一)Python进阶练习 正所谓要将知识进行实践,才会真正的掌握 于是就练习了几道题:求素数,求奇数,求九九乘法表,字符串练习 import re #求素数 i=1; flag=0 while(i& ...

  6. python requests库网页爬取小实例:亚马逊商品页面的爬取

    由于直接通过requests.get()方法去爬取网页,它的头部信息的user-agent显示的是python-requests/2.21.0,所以亚马逊网站可能会拒绝访问.所以我们要更改访问的头部信 ...

  7. Python 002- 爬虫爬取淘宝上耳机的信息

    参照:https://mp.weixin.qq.com/s/gwzym3Za-qQAiEnVP2eYjQ 一般看源码就可以解决问题啦 #-*- coding:utf-8 -*- import re i ...

  8. 爬取豆瓣网图书TOP250的信息

    爬取豆瓣网图书TOP250的信息,需要爬取的信息包括:书名.书本的链接.作者.出版社和出版时间.书本的价格.评分和评价,并把爬取到的数据存储到本地文件中. 参考网址:https://book.doub ...

  9. 使用Xpath爬取酷狗TOP500的歌曲信息

    使用xpath爬取酷狗TOP500的歌曲信息, 将排名.歌手名.歌曲名.歌曲时长,提取的结果以文件形式保存下来.参考网址:http://www.kugou.com/yy/rank/home/1-888 ...

随机推荐

  1. Maven的学习资料收集--(二)安装m2eclipse插件

    在Eclipse中可以安装Maven插件,可以更方便的使用: 官网地址:http://www.eclipse.org/m2e/ 可以在线安装或者离线下载,之前在线安装总是失败,可能是网速的原因,找到了 ...

  2. Eclipse下git如何创建分支

    1.项目–Team–Switch To –New Branch 2.Branch name 填写自己的版本号,然后Finish即可 3.将分支内容Push到远程服务器上

  3. Spring整合Struts2 注解版

    1.jar包 <!--spring配置--> <dependency> <groupId>org.springframework</groupId> & ...

  4. IOS NSTimer 定时器用法总结

    NSTimer在IOS开发中会经常用到,尤其是小型游戏,然而对于初学者时常会注意不到其中的内存释放问题,将其基本用法总结如下: 一.初始化方法:有五种初始化方法,分别是 + (NSTimer *)ti ...

  5. 【java】Cookie购物车实现

    前言 一个基于Cookie的购物车实现 话不多说,直接上代码 导包 import java.net.URLDecoder; import java.util.ArrayList; import jav ...

  6. (已解决)Arduino mega2560 R3插在电脑上没有反应

           OK,话不多说.网上找了一些资料,感觉都说的不够清晰.自己琢磨了下,有了一个简单粗暴的方法. 步骤1:插上Arduino mega2560板子.没有反应. 步骤2:我的电脑-管理-设备管 ...

  7. 更新浏览器,导致编写脚本报错Message: Unable to find a matching set of capabilities

    卸载更新浏览器后,所编写的脚本无法运行,报如下的错误:selenium.common.exceptions.WebDriverException: Message: Unable to find a ...

  8. draggable与overflow同时存在,无法拖拽出父元素问题解决

    在使用jquery-ui的拖拽功能对列表内的选项拖拽时,发现无法将选项拖拽出列表的范围,一出范围就自动隐藏在列表下,查找到最后的原因是css中的overflow的原因,overflow存在则不能将选项 ...

  9. windows 7 X64 提示“com surrogate 已停止工作”的解决方案

    C:\Windows\SysWOW64\dllhost.exe 把以上文件添加至“数据执行保护”.

  10. 【51nod1743】雪之国度(最小生成树+倍增)

    点此看题面 大致题意: 给你一张无向连通图,其中每条边的边权为这条边连接的两点的权值之差.每次询问两点之间是否存在两条不重复的路径,若存在则输出这两条路径上最大值的最小值. 大致思路 这题显然就是要让 ...