猫眼网反爬虫策略的处理

2018/12/7测试有效

注意:爬取频繁之后,会根据mac与ip地址封禁,修改为局域网其他ip后,大概5-6次修改,就会封网关

[目录]

一.引入问题

可以看到,猫眼网电影评分,票房等的数据在响应的html中并不是直接提供给你的。这里的xefcf,xef87等数据,是以‘特殊符号’的形式显示出来的。

可以发现这里请求了一个woff字体文件,而xefcf,xef87等数据的规则就是在这其中的。所以我们只需要在请求这个网页的同时,截去这部分style,然后获得woff地址,将它下载到本地,进行解析,就可以实现对评分的解密了。

但是再来看下面,当同一部电影的页面刷新时。

这里的评分编码改变了,下面请求的woff的url也改变了。所以每次请求电影页面使用的woff都不是同一个。

在这种情况下,如何才可以实现评分的爬取呢?

二.分步实现

1.页面爬取

第一步我们需要先将整个html页面获取,其中重要的数据就是评分所在的那个span,还有woff的url所在的那个style.

这里使用requests获取网页内容,用BeautifulSoup进行关键内容解析.

# 请求头设置

header = {

'Accept': '*/*;',

'Connection': 'keep-alive',

'Accept-Language': 'zh-CN,zh;q=0.9',

'Accept-Encoding': 'gzip, deflate, br',

'Host': 'maoyan.com',

'Referer': 'http://maoyan.com/',

'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36'

}

def web(url):

db_data = requests.get(url, headers=header)

# 这里直接将其编码之前部分替换掉,防止之后使用转义

soup = BeautifulSoup(db_data.text.replace("",""), 'lxml')

titles = soup.select(

'body > div.banner > div > div.celeInfo-right.clearfix > div.movie-stats-container > div > div > span > span')

wotfs = soup.select('head > style')

wotflist = str(wotfs[0]).split('\n')

maoyanwotf就是当前页面所使用的woff地址了。

= wotflist[5].replace(' ','').replace('url(\'//','').replace('format(\'woff\');','').replace('\')','')

此时titles就是一个获取了评分span的list,当然它只有一个元素。

maoyanwotf就是当前页面所使用的woff地址了。

2.woff下载

上一步我们得到了maoyanwotf,其中是当前页面所使用的woff地址,所以接下来就要对这个url进行下载,保存到本地。

# 下载请求电影页面的woff字体到本地

def downfont(maoyanwotf):

r = requests.get('http://'+maoyanwotf)

with open("demo.woff", "wb") as code:

code.write(r.content)

font = TTFont("demo.woff")

font.saveXML('to.xml')

这样就下载到了这次请求页面所用的woff了,保存为demo.woff。

3.字体解析规则

那么这个to.xml有什么用呢?

这就是我们在每次刷新都会改变woff的情况下,实现爬取的关键所在了。

font.saveXML('to.xml')就是将TTFont打开的woff转换为xml的形式,在xml中我们可以直接找到字体的相关数据,比如一个字符的笔画信息等。

来看一个字体xml文件的重要内容。完整内容参考:to.xml

....

...

...

...

...

GlyphOrder 这个标签中就是这个字体xml包含的字符种类了,glyph00000和x这两个不用考虑。

glyf 这个标签中是这些字体的具体坐标画法,一个TTGlyph对应一个字体,而其中contour标签的坐标数据,就是唯一确定这个字体是什么的最好的确定方法。

所以可以得出结论,不管每次请求的woff怎么变,它里面的字符的contour标签内的坐标画法是不会改变的。

既然如此,我们只需要一个模板,在这个模板中,我们先手动解码一个充当模板的woff。

如何制作这样一个模板呢?

我们先来找一个woff和woff生成的xml,woff可以用字体查看器High-Logic FontCreator打开,或者使用这个网页 http://fontstore.baidu.com/static/editor/index.html 。效果如下。

之后我们将模板xml里面的glyf中TTGlyph标签的name属性与打开的woff对应比较,得到这个数值列表(我这里woff和xml用的不是同一个,所以不要用这个比较!!!)

之后我们就可以根据glyf中TTGlyph的顺序得到解码数值的顺序,之所以要一一对应,是为了方便之后用下标索引。

num = [8,6,2,1,4,3,0,9,5,7] #这个值是直接硬编码进去的。

data = []

# 此处以解析xml的方式得到这个模板xml里面contour标签的内容。

xmlfilepath_temp = os.path.abspath("temp.xml")

domobj_temp = xmldom.parse(xmlfilepath_temp)

elementobj_temp = domobj_temp.documentElement

subElementObj = elementobj_temp.getElementsByTagName("TTGlyph")

for i in range(len(subElementObj)):

rereobj = re.compile(r"name=\"(.*)\"")

find_list = rereobj.findall(str(subElementObj[i].toprettyxml()))

data.append(str(subElementObj[i].toprettyxml()).replace(find_list[0],'').replace("\n",''))

最后data里面是glyf中TTGlyph按顺序的内容,其中当然就是contour了,而它的下表与num中一一对应,也就是说,这时候给你一个contour的坐标内容,那就可以在data中查找它的对应下标,根据这个下标找到num中下标的元素,这个元素就是解码后的值了!!!

获得了模板,我们接下来就可以将请求这次页面时获得的woff转化为xml进行对应了。

font = TTFont("demo.woff")

font.saveXML('to.xml')

#本次请求下载的字体的contour

new_font = []

xmlfilepath_find = os.path.abspath("to.xml")

domobj_find = xmldom.parse(xmlfilepath_find)

elementobj_find = domobj_find.documentElement

tunicode = elementobj_find.getElementsByTagName("TTGlyph")

for i in range(len(tunicode)):

th = tunicode[i].toprettyxml()

report = re.compile(r"name=\"(.*)\"")

find_this = report.findall(th)

get_code = th.replace(find_this[0], '').replace("\n", '')

for j in range(len(data)):

if not cmp(get_code,data[j]):

new_font.append(num[j])

其中get_code就是这次页面时获得的字体数据的list元素之一了,通过循环遍历,最终得到了一个本次xml的对应数字的list : new_font 。

接下来获得一个编码与具体数字对应的font_list

font = TTFont("demo.woff")

font_list = font.getGlyphNames()

font_list.remove('glyph00000')

font_list.remove('x')

此时,有了new_font中的具体数字和font_list中的编码值就可以完全解码这个页面中因为woff编码反爬虫的评分了。

# 匹配

star_woff = re.findall(re.compile(r">(.*)

for i in star_woff:

getthis = i.upper()

for j in range(len(font_list)):

if not cmp(getthis,font_list[j].replace("uni","")):

print(new_font[j])

这样就会输出评分的整数部分和小数部分了。虽然这里只是输出了这两个数字,但是反爬虫评分,票房,人数等数据均可以使用前一步的new_font和font_list进行处理,就不再加以阐述了。

python调用woff_GitHub - zergtant/python-maoyan-spider: woff-xml解码 “猫眼网反爬虫机制” 的爬虫。...相关推荐

  1. python调用php命令行,python调用php函数 python怎样调用php文件中的函数详解

    前言 python调用php代码实现思路:php文件可通过在terminal中使用php命令行进行调用,因此可使用python开启子进程执行命令行代码.函数所需的参数可通过命令行传递. 测试环境 1. ...

  2. python调用shell命令-Python调用shell命令常用方法(4种)

    方法一.使用os模块的system方法:os.system(cmd),其返回值是shell指令运行后返回的状态码,int类型,0表示shell指令成功执行,256表示未找到,该方法适用于shell命令 ...

  3. python 调用linux命令-Python调用shell命令常用方法

    Python调用shell指令 方法一.使用os模块的system方法:os.system(cmd),其返回值是shell指令运行后返回的状态码,int类型,0表示shell指令成功执行,256表示未 ...

  4. python调用shell命令-python调用shell命令小结

    在写python脚本的时候,经常需要调用系统命令,常用的python调用系统命令的方法主要有subprocess.call和os.popen.默认情况下subprocess.call的方法结果是返回值 ...

  5. python脚本中执行另一个脚本_如何用python调用另一个python脚本?

    如果想要将已经设置好的内容,在转移到另一个位置要怎么做呢?小编能写到的方法有,照抄,复制,以及转移使用.在我们日常办公上是非常好理解的,就是ctr v,但是如果想在编程上,将某一位置拿去到别的项目上使 ...

  6. python调用lib_基于python调用libvirt API

    基于python调用libvirt API 1.程序代码 #!/usr/bin/python import libvirt import sys def createConnection(): con ...

  7. 如何实现Python调用C代码--python与C之间如何通信(swig)

    转载: https://www.zhihu.com/question/23003213 1. C代码如何调用Python 1.1 test #include <Python.h> int ...

  8. python 无法调用turtle_新人求助,关于python 调用turtle《python简单turtle教程》

    新人求助,关于python 调用turtle 什么呀 turtle是python的简单的绘块,以下是一个例子from turtle import * def yin(radius, color1, c ...

  9. python调用百度翻译-Python 调用百度翻译API

    由于实习公司这边做的是日文app,有时要看看用户反馈,对于我这种五十音图都没记住的人,表示百度翻译确实还可以.但不想每次都复制粘贴啊,google被墙也是挺蛋疼的事,所以用python结合baidu ...

最新文章

  1. php 多人游戏_「谁会是下一个王者农药」云服务器如何搭建游戏服务器?
  2. 监控系统 Prometheus 和 Zabbix 对比
  3. You are using pip version 8.1.1, however version 20.1.1 is available
  4. 满足条件的两个数或多个数
  5. 查看dll文件被哪些软件调用的命令
  6. 安卓开发1-初步了解使用
  7. Jquery Datatable 数据填充报错:requested unknown parameter ‘XXX‘ for row xx, column xx 解决方法
  8. datagrid底部显示水平滚动_看完《惊奇队长》等彩蛋,我想到了一个制作PPT滚动字幕的方法...
  9. 基于JavaScript的在线语音识别库Julius
  10. [转]设计模式六大原则[1]:单一职责原则
  11. android底部导航栏网络请求有冲突,Android 自定义底部导航栏 CustomizeTabLayout(支持访问网络图片、本地图片)...
  12. TDSQL 在微众银行的大规模实践之路
  13. Nginx用为缓存服务器
  14. HTTP权威指南学习笔记:连接管理
  15. python百度ai实现身份证识别_python利用百度AI实现文字识别功能
  16. android 描点抠图源码,一款功能强大的AI驱动一键安卓抠图软件,人物商品图章签名logo...
  17. LENET-5卷积神经网络的深度学习技术
  18. 知识图谱属性融合_知识图谱融合_本体概念层的融合方法与技术
  19. scala reduce和Fold
  20. 阿里云服务器安装nodejs

热门文章

  1. qq邮箱如何在win10邮箱连接到服务器,Win10系统自带Mail应用添加QQ邮箱的方法
  2. Mac下文件Non-ISO extended-ASCII编码问题
  3. 威力曲面sw2020_威力曲面Power Surfacing
  4. 社工攻击@斯拉夫字母
  5. 互联网常见通用的运营数据指标
  6. 网络入侵检测系统之Suricata(七)--DDOS流量检测模型
  7. 红米k40关闭广告方法分享(图文)
  8. wpf拖拽图片,滚轮放大缩小
  9. View 事件分发机制
  10. 前端生成二维码 微信小程序