当前位置: 首页 > 编程日记 > 正文

如何利用 C# + Python 破解猫眼电影的反爬虫机制?

在 如何利用 C# 爬取「猫眼电影:最受期待榜」及对应影片信息! 这篇图文中可以看到猫眼电影对“本月新增想看人数” 和 “总想看人数”进行了字符集加密。

字体编码

在 如何利用 C# 爬取「猫眼电影:国内票房榜」及对应影片信息! 这篇图文中也可以看到猫眼电影对“实时票房” 和 “总票房”进行了字符集加密。

字体编码

破解这种利用字符集加密的反爬虫机制,需要建立映射关系表,找到每个字符对应的真实数字即可。怎么做呢?

我们 首先 需要把对应的字符集下载到本地。

stonefont类

然后,把该字符集转换成XML文件。由于 Python 中有 TTFont 指令可以直接使用,于是把转换的功能用 Python 来写并用 pyinstaller 指令打包成 EXE 文件,通过 C# 语言进行调用即可。

imports sys
from fontTools.ttLib import TTFontif __name__ =='__main__'font1 = TTFont(str(sys.argv[1]))font1.saveXML(str(sys.argv[2]))

打包main.py文件的代码:

pyinstaller -F main.py

生成的 XML 文件如下:

图形信息

接着,建立映射关系表,把TTGlyph namecountour和真实的数据对应起来。这个不能自动化只能把网页上的数字与源代码中的字符对应,在通过源代码中的字符与这个XML中的 TTGlyph name对应。

映射关系

最后,可以通过加载这份映射表来破解猫眼电影的反爬虫机制。即我先在内存中加载这份映射表,每个字体的图形名称TTGlyph name在刷新后是变化的,但图形信息countour是不会变化的,所以可以先通过图形名称找到图形信息,在通过这份映射表找到对应的真实数字。


以上详细的介绍了破解猫眼电影反爬虫机制的方法,下面我们来写具体的代码。

1. 构造字体图形的结构 FontGlyph

public class FontGlyph
{/// <summary>/// 图形名称/// </summary>public string Name { get; set; }/// <summary>/// 图形数据/// </summary>public string Glyph { get; set; }/// <summary>/// 图形值/// </summary>public int Value { get; set; } = -1;
}

2. 获取字体 WOFF 文件的存储地址

private static string GetWoffUrl(string str)
{int end = str.IndexOf(@"') format('woff')", StringComparison.Ordinal);int start = str.LastIndexOf("//vfile.meituan.net", StringComparison.Ordinal);string url = str.Substring(start, end - start);return "http:" + url;
}

3. 下载字体 WOFF 文件到本地

private static string Download(string url)
{int index = url.LastIndexOf("/", StringComparison.Ordinal);string fileName = @".\font\" + url.Substring(index + 1);HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;if (request == null)return string.Empty;HttpWebResponse response = request.GetResponse() as HttpWebResponse;if (response == null)return string.Empty;Stream reponseStream = response.GetResponseStream();if (reponseStream == null)return string.Empty;Stream stream = new FileStream(fileName, FileMode.Create);byte[] bArr = new byte[1024];int size = reponseStream.Read(bArr, 0, bArr.Length);while (size > 0){stream.Write(bArr, 0, size);size = reponseStream.Read(bArr, 0, bArr.Length);}stream.Close();reponseStream.Close();return fileName;
}

4. 转换字体 WOFF 文件为XML文件

private static string TransXml(string fileName)
{string xml = @".\font\" + Path.GetFileNameWithoutExtension(fileName) + ".xml";Process p = new Process();p.StartInfo.FileName = @".\font\main.exe";p.StartInfo.UseShellExecute = false;p.StartInfo.RedirectStandardOutput = true;p.StartInfo.RedirectStandardInput = true;p.StartInfo.CreateNoWindow = true;p.StartInfo.Arguments = fileName + " " + xml;p.Start();p.WaitForExit();p.Close();return xml;
}

5. 根据 XML 文件获得字体图形文件列表 List<FontGlyph>

private static List<FontGlyph> GetXmlGlyf(string path)
{List<FontGlyph> result = new List<FontGlyph>();XmlDocument xmldoc = new XmlDocument();XmlReaderSettings settings = new XmlReaderSettings();settings.IgnoreComments = true;XmlReader reader = XmlReader.Create(path, settings);xmldoc.Load(reader);if (xmldoc.DocumentElement == null)return result;XmlNodeList nodeList = xmldoc.DocumentElement.ChildNodes;foreach (XmlNode node in nodeList){if (node.Name == "glyf"){XmlNodeList lst = node.ChildNodes;foreach (XmlNode n in lst){XmlElement xe = n as XmlElement;if (xe != null){if (string.IsNullOrEmpty(xe.InnerXml) == false){FontGlyph item = new FontGlyph();item.Name = xe.GetAttribute("name");item.Glyph = xe.InnerXml;item.Value = -1;result.Add(item);}}}}}return result;
}

6. 建立映射关系

private static int GetValue(string name)
{string[] str = new string[]{"uniF756", "uniED75", "uniF8F8", "uniF81A", "uniEE70", "uniECA0","uniEC6F", "uniE93B", "uniE9D3","uniF8B5"};for (int i = 0; i < str.Length; i++){if (str[i] == name)return i;}return -1;
}private static List<FontGlyph> GetFontGlyphList(string fileName)
{List<FontGlyph> lst = GetXmlGlyf(fileName);for (int i = 0, len = lst.Count; i < len; i++){lst[i].Value = GetValue(lst[i].Name);}return lst;
}

7. 解密算法

private static string Decrypt(string str, List<FontGlyph> lstModel, List<FontGlyph> lstCur)
{string result = string.Empty;string[] ss = str.Split(new char[] {'.'});string[] ss1 = ss[0].Split(new char[] {';'}); //处理整数部分for (int i = 0; i < ss1.Length; i++){if (string.IsNullOrEmpty(ss1[i]) == false){int d = GetIndex(ss1[i], lstCur);int v = GetValue(lstCur[d].Glyph, lstModel);result += v.ToString();}}if (ss.Length != 1) //处理小数部分{result += ".";string[] ss2 = ss[1].Split(new char[] {';'});for (int i = 0; i < ss2.Length; i++){if (string.IsNullOrEmpty(ss2[i]) == false){int d = GetIndex(ss2[i], lstCur);int v = GetValue(lstCur[d].Glyph, lstModel);result += v.ToString();}}}return result;
}private static int GetIndex(string str, List<FontGlyph> lstCur)
{for (int i = 0, len = lstCur.Count; i < len; i++){if (lstCur[i].Name.Contains(str.Substring(3).ToUpper()))return i;}return -1;
}private static int GetValue(string str, List<FontGlyph> lstModel)
{for (int i = 0, len = lstModel.Count; i < len; i++){if (lstModel[i].Glyph == str){return lstModel[i].Value;}}return -1;
}

8. 获取「猫眼电影:国内票房榜 及对应影片信息」修改后的代码

public static List<Film> GetFilmsTicket()
{List<Film> result = new List<Film>();string url = "https://maoyan.com/board/1"; //国内票房榜IHtmlDocument doc = GetHtmlDocument(url);if (doc == null)return result;List<FontGlyph> lstModel = GetFontGlyphList(@".\font\base.xml");List<IHtmlElement> woffStr = doc.Find("style").ToList();string tempUrl = GetWoffUrl(woffStr[0].InnerHtml());string fileNameWoff = Download(tempUrl);string fileNameXml = TransXml(fileNameWoff);List<FontGlyph> lstNew = GetXmlGlyf(fileNameXml);List<IHtmlElement> lists = doc.Find("dd").ToList();for (int i = 0; i < lists.Count; i++){List<IHtmlElement> infor = lists[i].Find("p").ToList();Film item = new Film();item.Num = i + 1; //排名string dw, ticket;List<IHtmlElement> s;if (infor.Count < 5){item.Time = infor[1].InnerHtml().Trim().Remove(0, 5); //上映时间dw = infor[2].InnerHtml().Trim();dw = dw.Remove(0, dw.Length - 1); //实时票房单位s = infor[2].Find(".stonefont").ToList();ticket = s[0].InnerHtml().Trim(); //加密的实时票房item.BoxInfo = Decrypt(ticket, lstModel, lstNew) + dw; //实时票房dw = infor[3].InnerHtml().Trim();dw = dw.Remove(0, dw.Length - 1); //总票房单位s = infor[3].Find(".stonefont").ToList();ticket = s[0].InnerHtml().Trim(); //加密的总票房item.SumBoxInfo = Decrypt(ticket, lstModel, lstNew) + dw; //总票房}else{item.Actor = infor[1].InnerHtml().Trim().Remove(0, 3); //演员item.Time = infor[2].InnerHtml().Trim().Remove(0, 5); //上映时间dw = infor[3].InnerHtml().Trim();dw = dw.Remove(0, dw.Length - 1); //实时票房单位s = infor[3].Find(".stonefont").ToList();ticket = s[0].InnerHtml().Trim(); //加密的实时票房item.BoxInfo = Decrypt(ticket, lstModel, lstNew) + dw; //实时票房dw = infor[4].InnerHtml().Trim();dw = dw.Remove(0, dw.Length - 1); //总票房单位s = infor[4].Find(".stonefont").ToList();ticket = s[0].InnerHtml().Trim(); //加密的总票房item.SumBoxInfo = Decrypt(ticket, lstModel, lstNew) + dw; //总票房}IHtmlElement a = infor[0].Find("a").ToList()[0]; //获取影片urlitem.MovieName = a.InnerHtml().Trim(); //名称url = "https://maoyan.com" + a.Attribute("href").AttributeValue;IHtmlDocument temp = GetHtmlDocument(url);List<IHtmlElement> t = temp.Find("li.ellipsis").ToList();item.Type = t[0].InnerHtml(); //类型List<IHtmlElement> b = temp.Find(".dra").ToList();item.Introduction = b[0].InnerHtml(); //介绍result.Add(item);}return result;
}

9. 获取「猫眼电影:最受期待榜及对应影片信息」修改后的代码

public static List<Film> GetFilmsExpect(int offset)
{List<Film> result = new List<Film>();string url = "https://maoyan.com/board/6"; //最受期待榜IHtmlDocument doc = GetHtmlDocument(url, offset);if (doc == null)return result;List<FontGlyph> lstModel = GetFontGlyphList(@".\font\base.xml");List<IHtmlElement> woffStr = doc.Find("style").ToList();string tempUrl = GetWoffUrl(woffStr[0].InnerHtml());string fileNameWoff = Download(tempUrl);string fileNameXml = TransXml(fileNameWoff);List<FontGlyph> lstNew = GetXmlGlyf(fileNameXml);List<IHtmlElement> lists = doc.Find("dd").ToList();for (int i = 0; i < lists.Count; i++){List<IHtmlElement> infor = lists[i].Find("p").ToList();Film item = new Film();item.Num = i + 1; //排名item.Actor = infor[1].InnerHtml().Trim().Remove(0, 3); //演员item.Time = infor[2].InnerHtml().Trim().Remove(0, 5); //上映时间string dw = infor[3].InnerHtml().Trim();dw = dw.Remove(0, dw.Length - 1); //单位List<IHtmlElement> p = infor[3].Find(".stonefont").ToList();string people = p[0].InnerHtml().Trim(); //加密的新增想看人数item.NewWatcher = Decrypt(people, lstModel, lstNew) + dw; //解密的新增想看人数dw = infor[4].InnerHtml().Trim();dw = dw.Remove(0, dw.Length - 1); //单位p = infor[4].Find(".stonefont").ToList();people = p[0].InnerHtml().Trim(); //加密的总想看人数item.TotalWatcher = Decrypt(people, lstModel, lstNew) + dw; //解密的总想看人数IHtmlElement a = infor[0].Find("a").ToList()[0]; //获取影片urlitem.MovieName = a.InnerHtml().Trim(); //名称url = "https://maoyan.com" + a.Attribute("href").AttributeValue;IHtmlDocument temp = GetHtmlDocument(url);List<IHtmlElement> t = temp.Find("li.ellipsis").ToList();item.Type = t[0].InnerHtml(); //类型List<IHtmlElement> b = temp.Find(".dra").ToList();item.Introduction = b[0].InnerHtml(); //介绍result.Add(item);}return result;
}

10. 输出结果

猫眼电影:国内票房榜 及对应影片信息

结果1

猫眼电影:最受期待榜及对应影片信息

结果2


到此为止,有关如何破解猫眼电影的反爬虫机制就全部介绍完了,破解这种反爬虫机制相对来说比较复杂。如果网站通过用户请求的 Headers 进行反爬虫或者通过限制同一IP短时间内多次访问同一页面进行反爬虫,破解起来就相对容易很多,只要请求时加入相应的 Headers 信息或者利用代理IP绕过就好。今天就到这里吧,See You!


相关图文:

  • 如何利用 C# 爬取 One 持有者返利数据!
  • 如何利用 C# 爬取Gate.io交易所的公告!
  • 如何利用 C# 爬取BigOne交易所的公告!
  • 如何利用 C# 爬取 ONE 的交易数据?
  • 如何利用 C# 实现 K 最邻近算法?
  • 如何利用 C# 实现 K-D Tree 结构?
  • 如何利用 C# + KDTree 实现 K 最邻近算法?
  • 如何利用 C# 对神经网络模型进行抽象?
  • 如何利用 C# 实现神经网络的感知器模型?
  • 如何利用 C# 实现 Delta 学习规则?
  • 如何利用 C# 爬取「京东 - 计算机与互联网图书销量榜」!
  • 如何利用 C# 爬取「当当 - 计算机与互联网图书销量榜」!
  • 如何利用 C# 爬取「互动出版网 - 计算机图书销量榜」!
  • 如何利用 C# 爬取「中国图书网 - 计算机与互联网图书销量榜」!
  • 如何利用 C# 爬取带 Token 验证的网站数据?

相关文章:

ZooKeeper学习笔记1-----------安装启动

ZooKeeper是一套协作服务&#xff0c;主要用来构建分布式架构的应用&#xff0c;通过ZooKeeper我们可以安全的处理分布式应用下的局部故障问题。我们知道ZooKeeper就是Hadoop中的分布式协作服务组件。下面我们进入ZooKeeper的安装部署。 安装Zookeeper https://zookeeper.apach…

软件测试培训完就业方向怎么选择

软件测试技术在近几年的发展前景是非常好的&#xff0c;越来越多的人都想要学习软件测试技术&#xff0c;报班是大多数人的选择&#xff0c;但是大家对于“软件测试培训完就业方向怎么选择”这个问题比较迷茫&#xff0c;我们来看看下面的详细介绍。 软件测试培训完就业方向怎么…

LeetCode实战:合并两个有序链表

题目英文&#xff1a; Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. Example: Input: 1->2->4, 1->3->4 Output: 1->1->2->3->4->4 题目中…

Apache反向代理设置【转载】

编译Apache时要进行的设置./configure --enable-mods-shared"all proxy"1>修改 httpd.conf 文件中&#xff1a;LoadModule proxy_module modules/mod_proxy.soLoadModule proxy_connect_module modules/mod_proxy_connect.soLoadModule proxy_http_module modules…

Suricata的输出

不多说&#xff0c;直接上干货&#xff01; 见官网 https://suricata.readthedocs.io/en/latest/output/index.html 总的来说&#xff0c;Suricata采集下来的数据输出分为&#xff1a;EVE 、 Lua Output 、 Syslog Alerting Compatibility 、 Custom http logging 、 Custo…

快速提高你的UI设计水平的一些小技巧

UI设计师这个岗位在最近几年的缺口是比较大的&#xff0c;很多企业都在招UI设计人员&#xff0c;想要学习UI设计或者提升UI设计技术的同学&#xff0c;可以看看小编分享的以下内容&#xff0c;善用这些UI设计小技巧&#xff0c;快速提高你的设计水平! 快速提高你的UI设计水平的…

hibernate join fetch

那天去了达内&#xff0c;试听了2个小时的课&#xff0c;刚好讲的他们的当当网项目&#xff0c;讲hibernate表关系映射这段来了&#xff0c;不过也够呛&#xff0c;投影仪看的眼睛点都不舒服&#xff0c;当时讲的也没认真听&#xff0c;听了个大概&#xff0c;就记住那个老师一…

Java IO 字节流与字符流 (三)

概述 IO流用来处理设备之间的数据传输 Java对数据的操作时通过流的方式 Java用于操作流的对象都在IO包中 流按操作的数据分为&#xff1a;字节流和字符流 流按流向不同分为&#xff1a;输入流和输出流 IO流常用基类 字节流的抽象基类 InputStream&#xff0c;OuputStream 字符流…

LeetCode实战:两两交换链表中的节点

题目英文 Given a linked list, swap every two adjacent nodes and return its head. You may not modify the values in the list’s nodes, only nodes itself may be changed. Example: Given 1->2->3->4, you should return the list as 2->1->4->3.…

在UI设计中如何正确使用颜色

在我们进行UI设计时&#xff0c;颜色往往是我们表达理念重要的一点&#xff0c;但也是我们常常会忽视的一点。颜色其实如同语言一样&#xff0c;我们可以通过颜色的变化组合&#xff0c;来表达不同的情绪。 正确使用颜色不单能让我们吸引到客户&#xff0c;也能更好地表达我们的…

如何用Python做Web开发?——Django环境配置

用Python做Web开发&#xff0c;Django框架是个非常好的起点。如何从零开始&#xff0c;配置好Django开发环境呢&#xff1f;本文带你一步步无痛上手。 概念 最近有个词儿很流行&#xff0c;叫做“全栈”(full stack)。各大IT培训机构几乎都在宣传这一概念。告诉你只需要交1XXXX…

LeetCode实战:旋转链表

题目英文 Given a linked list, rotate the list to the right by k places, where k is non-negative. Example 1: Input: 1->2->3->4->5->NULL, k 2 Output: 4->5->1->2->3->NULL Explanation: rotate 1 steps to the right: 5->1->2…

blog地址:

blog地址: blog地址: http://blog.csdn.net/q107770540posted on 2010-11-19 08:36 Tim_ 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/q107770540/archive/2010/11/19/1881399.html

Spring MVC框架有哪些优点

Spring MVC是Spring提供的一个实现了Web MVC设计模式的轻量级Web框架。它与Struts2框架一样&#xff0c;都属于MVC框架&#xff0c;但其使用和性能等方面比Struts2更加优异。 Spring MVC具有如下特点&#xff1a; 是Spring框架的一部分&#xff0c;可以方便的利用Spring所提供的…

MVC+Ninject+三层架构+代码生成 -- 总结(四、數據層)

1.數據層使用了SqlSugar 庫類 。 數據層使用了SqlSugar 庫類 &#xff0c;有興趣的 可以學習 http://www.codeisbug.com/Doc/8/1133&#xff0c;個人覺得比EF 簡單&#xff0c;容易上手&#xff0c;推薦1。 數據層使用代碼生成&#xff0c;所以考慮得比較多。 1.GetAllList()-…

台湾前十大科技公司拼不过三星(往后一点三星都不要买啦!)

台湾前十大科技公司拼不过三星,往后一点三星都不要买啦!本来还可以买它的内存和液晶,不过现在是一点都不能买了,再买就真反了他了! 三星像糖果也像毒药&#xff0c;让台湾LED类股1年涨3倍&#xff0c;但也让鸿海市值一夜之间消失350亿元(新台币&#xff0c;下同)。从来没有一刻…

技术图文:如何利用 C# 向 Access 数据库插入大量数据?

背景 通常我们在做数据分析与处理之前&#xff0c;需要把从网站爬取的数据或者从 甲方 系统中导出的数据存入到自己的数据库中。如果数据量小&#xff0c;直接利用 SQL的 Insert 语句逐条插入就好。可是数据量上万条之后&#xff0c;再利用这样的方法就会奇慢无比&#xff0c;…

Web前端面试自我介绍对话技巧注意事项

大家在学会了web前端技术后&#xff0c;当然是要准备找一个适合自己的web前端工作了&#xff0c;那么面试环节是必不可少的&#xff0c;有一个良好的自我介绍表述&#xff0c;在HR心中也能加分不少&#xff0c;接下来小编就为大家介绍一下Web前端面试自我介绍对话技巧注意事项。…

Android使用ListView控件问题

Android使用ListView控件问题&#xff1a; The application has stopped unexpectedly, please try again。 开发环境&#xff1a;android 1.6 最低兼容 4.0 报错代码如下&#xff1a; main.xml 代码 1 <?xml version"1.0" encoding"utf-8"?>2 <…

技术图文:如何实现 DataTable 与模型类 List 的相互转换?

通常情况下&#xff0c;我们在做工程项目的时候&#xff0c;需要把待处理的数据存储在数据库中。 通过 SQL 的 Select 语句很容易把查询的结果以 DataTable 的方式得到&#xff0c;但在对 DateTable 中的数据进行进一步的检索时远远没有模型类 List<T> 方便。 所以&…

SQL server 基本语句

SQL server数据库基本语句一、实验要求&#xff1a;1、 查询student表中所有学生的信息select * from student如图所示2、查询student表中“姓名”“所在班级”和“成绩”列内容select 姓名&#xff0c;所在班级&#xff0c;成绩 from student如图所示3、查询student表…

Python中if条件判断语句怎么用?

俗话说“不积跬步无以至千里”。学习了Python的基本语法后&#xff0c;接下来我们学习Python常的if条件判断语句。 if语句是最简单的条件判断语句&#xff0c;它可以控制程序的执行流程&#xff0c;其使用格式如下: if判断条件: 满足条件时要做的事情1… 满足条件时要做的事情2…

Arcmap技巧总结

Arcmap技巧总结 1. 要素的剪切与延伸 实用工具 TASK 任务栏 Extend/Trim feature 剪切所得内容与你画线的方向有关。 2. 自动捕捉跟踪工具 点击Editor工具栏中Snapping来打开Snapping Environment对话框 捕捉设置中有3个选项&#xff0c; vertex edge end 分…

Spring Web MVC(一)

概述Spring Web MVC框架的特点五大核心组件编程步骤 五大核心组件DispatcherServlet前端控制器WebApplicationContext中特殊的bean处理过程 HandlerMapping 处理映射Spring中最常用的两个处理器映射BeanNameUrlHandlerMappingSimpleUrlHandlerMapping拦截器HandlerInterceptor概…

技术图文:如何利用BigOne的API制作自动化交易系统 -- 身份验证

背景 最近&#xff0c;自己在技术精进方向上有所犹豫&#xff0c;是往"网络渗透"的方向走呢&#xff1f;还是往"量化交易"的方向走&#xff1f; 如果选择精进“网络渗透”&#xff0c;就需要学习各种Web渗透技术、客户端渗透技术、移动环境渗透技术、社会…

零基础学习java软件开发攻略

Java是主流开发语言&#xff0c;应用普遍。Spring Boot是Java开发时常用框架&#xff0c;有非常丰富的组件和易用的功能。实际开发工作中涉及到的知识点比较多&#xff0c;将它们分门别类&#xff0c;专题攻关&#xff0c;由点到面&#xff0c;学习效率非常高。 软件开发系统学…

Linux--档案/目录 权限及修改

首先所有权限对于三类用户分别设定&#xff1a; User(所有者) / Group(组群) / Others(其他)。 权限也是有三种&#xff1a;Read / Write / eXecute&#xff0c;这三种权限对于文档和目录有不同的意义。 1. 对于文档&#xff1a; Read&#xff1a;可以查看文档的内容 Write&…

sklearn:Python语言开发的通用机器学习库

引言&#xff1a;深入理解机器学习并全然看懂sklearn文档&#xff0c;须要较深厚的理论基础。可是。要将sklearn应用于实际的项目中&#xff0c;仅仅须要对机器学习理论有一个主要的掌握&#xff0c;就能够直接调用其API来完毕各种机器学习问题。本文选自《全栈数据之门》。将向…

资料分享:送你一本《BigONE Developer API V2》电子书!

背景 昨天&#xff0c;我推送了一篇技术图文《如何利用 BigOne 的 API 制作自动化交易系统 – 身份验证》&#xff0c;里面提到了 BigONE Developer API V2。为了方便自己也方便他人&#xff0c;所以把这份文档整理成 PDF。如果大家对封装 BigONE 提供的 API 感兴趣可以下载这…

Web前端培训面试攻略

学会web前端技术之后&#xff0c;接下来就是要找到一份合适的工作&#xff0c;今天小编要跟大家分享的文章是关于web前端面试攻略&#xff0c;做好这些可以给面试环节加分&#xff0c;找到合适的工作几率会更高&#xff0c;希望本篇文章能够对大家有所帮助。 ​  Web前端培训…