阅读文本大概需要 18 分钟。

双11已经过去,双12即将来临,离2018年的结束也就2个月不到,还记得年初立下的flag吗?

完成了多少?相信很多人和我一样,抱头痛哭...

本次利用猫眼电影,实现对2018年的电影大数据进行分析。

/ 01 / 网页分析


01  标签



通过点击猫眼电影已经归类好的标签,得到网址信息。


02  索引页



打开开发人员工具,获取索引页里电影的链接以及评分信息。

索引页一共有30多页,但是有电影评分的只有10页。

本次只对有电影评分的数据进行获取。


03  详情页


对详情页的信息进行获取。

主要是名称,类型,国家,时长,上映时间,评分,评分人数,累计票房。

/ 02 / 反爬破解

通过开发人员工具发现,猫眼针对评分,评分人数,累计票房的数据,施加了文字反爬。

通过查看网页源码,发现只要刷新页面,三处文字编码就会改变,无法直接匹配信息。

所以需要下载文字文件,对其进行双匹配。

from fontTools.ttLib import TTFont

#font = TTFont('base.woff')
#font.saveXML('base.xml')
font = TTFont('maoyan.woff')
font.saveXML('maoyan.xml')

将woff格式转换为xml格式,以便在Pycharm中查看详细信息。

利用下面这个网站,打开woff文件。

url: http://fontstore.baidu.com/static/editor/index.html

可以得到下面数字部分信息(上下两块)。

在Pycharm中查看xml格式文件(左右两块),你就会发现有对应信息。

通过上图你就可以将数字6对上号了,其他数字一样的。

def get_numbers(u):
    """
    对猫眼的文字反爬进行破解
    """
    cmp = re.compile(",\n           url\('(//.*.woff)'\) format\('woff'\)")
    rst = cmp.findall(u)
    ttf = requests.get("http:" + rst[0], stream=True)
    with open("maoyan.woff", "wb") as pdf:
        for chunk in ttf.iter_content(chunk_size=1024):
            if chunk:
                pdf.write(chunk)
    base_font = TTFont('base.woff')
    maoyanFont = TTFont('maoyan.woff')
    maoyan_unicode_list = maoyanFont['cmap'].tables[0].ttFont.getGlyphOrder()
    maoyan_num_list = []
    base_num_list = ['.', '3', '0', '8', '9', '4', '1', '5', '2', '7', '6']
    base_unicode_list = ['x', 'uniF561', 'uniE6E1', 'uniF125', 'uniF83F', 'uniE9E2', 'uniEEA6', 'uniEEC2', 'uniED38', 'uniE538', 'uniF8E7']
    for i in range(1, 12):
        maoyan_glyph = maoyanFont['glyf'][maoyan_unicode_list[i]]
        for j in range(11):
            base_glyph = base_font['glyf'][base_unicode_list[j]]
            if maoyan_glyph == base_glyph:
                maoyan_num_list.append(base_num_list[j])
                break
    maoyan_unicode_list[1] = 'uni0078'
    utf8List = [eval(r"'\u" + uni[3:] + "'").encode("utf-8") for uni in maoyan_unicode_list[1:]]
    utf8last = []
    for i in range(len(utf8List)):
        utf8List[i] = str(utf8List[i], encoding='utf-8')
        utf8last.append(utf8List[i])
    return (maoyan_num_list ,utf8last)

/ 03 / 数据获取

01  构造请求头

head = """
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding:gzip, deflate, br
Accept-Language:zh-CN,zh;q=0.8
Cache-Control:max-age=0
Connection:keep-alive
Host:maoyan.com
Upgrade-Insecure-Requests:1
Content-Type:application/x-www-form-urlencoded; charset=UTF-8
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.86 Safari/537.36
"""

def str_to_dict(header):
    """
    构造请求头,可以在不同函数里构造不同的请求头
    """
    header_dict = {}
    header = header.split('\n')
    for h in header:
        h = h.strip()
        if h:
            k, v = h.split(':', 1)
            header_dict[k] = v.strip()
    return header_dict

因为索引页和详情页请求头不一样,这里为了简便,构造了一个函数。

02  获取电影详情页链接

def get_url():
    """
    获取电影详情页链接
    """
    for i in range(0, 300, 30):
        time.sleep(10)
        url = 'http://maoyan.com/films?showType=3&yearId=13&sortId=3&offset=' + str(i)
        host = """Referer:http://maoyan.com/films?showType=3&yearId=13&sortId=3&offset=0
        """
        header = head + host
        headers = str_to_dict(header)
        response = requests.get(url=url, headers=headers)
        html = response.text
        soup = BeautifulSoup(html, 'html.parser')
        data_1 = soup.find_all('div', {'class': 'channel-detail movie-item-title'})
        data_2 = soup.find_all('div', {'class': 'channel-detail channel-detail-orange'})
        num = 0
        for item in data_1:
            num += 1
            time.sleep(10)
            url_1 = item.select('a')[0]['href']
            if data_2[num-1].get_text() != '暂无评分':
                url = 'http://maoyan.com' + url_1
                for message in get_message(url):
                    print(message)
                    to_mysql(message)
                print(url)
                print('---------------^^^Film_Message^^^-----------------')
            else:
                print('The Work Is Done')
                break

03  获取电影详情页信息

def get_message(url):
    """
    获取电影详情页里的信息
    """
    time.sleep(10)
    data = {}
    host = """refer: http://maoyan.com/news
    """
    header = head + host
    headers = str_to_dict(header)
    response = requests.get(url=url, headers=headers)
    u = response.text
    # 破解猫眼文字反爬
    (mao_num_list, utf8last) = get_numbers(u)
    # 获取电影信息
    soup = BeautifulSoup(u, "html.parser")
    mw = soup.find_all('span', {'class': 'stonefont'})
    score = soup.find_all('span', {'class': 'score-num'})
    unit = soup.find_all('span', {'class': 'unit'})
    ell = soup.find_all('li', {'class': 'ellipsis'})
    name = soup.find_all('h3', {'class': 'name'})
    # 返回电影信息
    data["name"] = name[0].get_text()
    data["type"] = ell[0].get_text()
    data["country"] = ell[1].get_text().split('/')[0].strip().replace('\n', '')
    data["length"] = ell[1].get_text().split('/')[1].strip().replace('\n', '')
    data["released"] = ell[2].get_text()[:10]
    # 因为会出现没有票房的电影,所以这里需要判断
    if unit:
        bom = ['分', score[0].get_text().replace('.', '').replace('万', ''), unit[0].get_text()]
        for i in range(len(mw)):
            moviewish = mw[i].get_text().encode('utf-8')
            moviewish = str(moviewish, encoding='utf-8')
            # 通过比对获取反爬文字信息
            for j in range(len(utf8last)):
                moviewish = moviewish.replace(utf8last[j], maoyan_num_list[j])
            if i == 0:
                data["score"] = moviewish + bom[i]
            elif i == 1:
                if '万' in moviewish:
                    data["people"] = int(float(moviewish.replace('万', '')) * 10000)
                else:
                    data["people"] = int(float(moviewish))
            else:
                if '万' == bom[i]:
                    data["box_office"] = int(float(moviewish) * 10000)
                else:
                    data["box_office"] = int(float(moviewish) * 100000000)
    else:
        bom = ['分', score[0].get_text().replace('.', '').replace('万', ''), 0]
        for i in range(len(mw)):
            moviewish = mw[i].get_text().encode('utf-8')
            moviewish = str(moviewish, encoding='utf-8')
            for j in range(len(utf8last)):
                moviewish = moviewish.replace(utf8last[j], maoyan_num_list[j])
            if i == 0:
                data["score"] = moviewish + bom[i]
            else:
                if '万' in moviewish:
                    data["people"] = int(float(moviewish.replace('万', '')) * 10000)
                else:
                    data["people"] = int(float(moviewish))
        data["box_office"] = bom[2]
    yield data

/ 04 / 数据存储

01  创建数据库及表格

db = pymysql.connect(host='127.0.0.1', user='root', password='774110919', port=3306)
cursor = db.cursor()
cursor.execute("CREATE DATABASE maoyan DEFAULT CHARACTER SET utf8mb4")
db.close()

db = pymysql.connect(host='127.0.0.1', user='root', password='774110919', port=3306, db='maoyan')
cursor = db.cursor()
sql = 'CREATE TABLE IF NOT EXISTS films (name VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, country VARCHAR(255) NOT NULL, length VARCHAR(255) NOT NULL, released VARCHAR(255) NOT NULL, score VARCHAR(255) NOT NULL, people INT NOT NULL, box_office BIGINT NOT NULL, PRIMARY KEY (name))'
cursor.execute(sql)
db.close()

其中票房收入数据类型为BIGINT(19位数),最大为18446744073709551615。

INT(10位数),最大为2147483647,达不到36亿(3600000000)。

02  数据存储

def to_mysql(data):
    """
    信息写入mysql
    """
    table = 'films'
    keys = ', '.join(data.keys())
    values = ', '.join(['%s'] * len(data))
    db = pymysql.connect(host='localhost', user='root', password='774110919', port=3306, db='maoyan')
    cursor = db.cursor()
    sql = 'INSERT INTO {table}({keys}) VALUES ({values})'.format(table=table, keys=keys, values=values)
    try:
        if cursor.execute(sql, tuple(data.values())):
            print("Successful")
            db.commit()
    except:
        print('Failed')
        db.rollback()
    db.close()

最后成功存储数据

/ 05 / 数据可视化


可视化源码就不放了,公众号回复电影即可获得。


01  电影票房TOP10


还剩一个多月,不知道榜单上会不会有新成员。最近「毒液」很火,蛮有希望。

02  电影评分TOP10

这里就得吐槽一下pyecharts,坐标转换后,坐标值名称太长就会被遮挡,还需改进呢~

03  电影人气TOP10


茫茫人海之中,相信一定也有大家的身影,我也是其中的一员!!!

04  每月电影上映数量


每月上映数好像没什么大差距,7月最少,难道是因为天气热?

05  每月电影票房


这里就看出春节档电影的威力了,金三银四、金九银十,各行各业的规律,电影行业也不例外。

上一张图我们知道7月份电影上新最少,票房反而是第二。

这里看了下数据,发现有「我不是药神」「西虹市首富」「邪不压正」「摩天营救」「狄仁杰之四大天王」几部大剧撑着。

06  各国家电影数量TOP10


原来中国电影这么高产的,可是豆瓣 TOP250 里又有多少中国电影呢?深思!!!

07  中外票房对比


2017 年的年度票房是 560 亿,估计今年快要突破了。据说今年全年票房有望突破 600 亿。

08  电影名利双收TOP10


计算公式是,把某部电影的评分在所有电影评分中的排名与这部电影的票房在所有票房中的排名加起来,再除以电影总数。

除了「侏罗纪世界2」「无双」「捉妖记2」,我都看过啦!

09  电影叫座不叫好TOP10


计算公式是,把某部电影的票房排名减去某部电影的评分排名加起来,再除以电影总数。

可能是猫眼的用户比较仁慈吧,与豆瓣相比,普遍评分都比较高。我个人都不太敢相信这个结果。

不过有一个还是挺准的,「爱情公寓」。

10  电影类型分布

剧情电影永远引人深思。感觉今年的电影好多跟钱有关,比如「我不是药神」「西虹市首富」「一出好戏」「头号玩家」,贫穷限制了大家伙们。

公众号回复电影。即可获取全部源码。

现在微信改版了

好多人跟痴海说

看不到痴海了

其实只要把痴海置顶就可以了

只需要 5 秒钟

痴海教你置顶

推荐阅读:

2018 年最受欢迎的电影,你都看过哪些?相关推荐

  1. 这6部韩国电影你都看过吗?

    1.<下女> 在看整部片的过程中,压抑.愤怒,还带点恐惧感.有钱了就会改变已有的格局,随后各种各样的问题也会接踵而来,但守得住人性的底线,才会无所畏惧.惊悚的氛围比较像希区柯克,单一场景的 ...

  2. 2018 年最受欢迎的电影,你都看过哪些?爬猫眼电影

    阅读文本大概需要 18 分钟 ^_^ 双11已经过去,双12即将来临,离2018年的结束也就2个月不到,还记得年初立下的flag吗? 完成了多少?相信很多人和我一样,抱头痛哭... 本次利用猫眼电影, ...

  3. 2018年最受欢迎 Linux 发行版都有哪些?

    Linux发行版在过去的日子里,不断为大家带来改变,对于那些希望迁移到开源平台的人来说,选择什么平台是最大的困扰,如果你去 Distrowatch找一下,那么多的发行版可能会令你眼花缭乱,而且排名也十 ...

  4. 有哪些好的刷题网站?2018年最受欢迎的编程挑战网站

    本文转自 https://blog.csdn.net/UzV80PX5V412NE/article/details/78653695 2018年最受欢迎的编程挑战网站 1.TopCoder 2.Cod ...

  5. 盘点2018上半年最受欢迎的前端开发!

    2017 是一个前端 Web 开发年. 像 React 和 Angular 这样的框架,继续在社区中享有大规模的支持,但是,新的候选者 Vue ,人气也很旺.Webpack 依旧是构建的首选工具,NP ...

  6. 最受中国人喜欢的电影,你看过几个?(豆瓣top250分析,附资源)

    豆瓣作为一个电影评论的网站,标榜着文艺与小清新,上面的评价还是比较符合大众的对影片的真实评价. 今天小编就以豆瓣评分top250作为统计标准,对这250部电影到底说了点啥,给大家展示一下. 所有资源均 ...

  7. ACL 2018最佳论文公布!计算语言学最前沿研究都在这里了

    国际计算语言学协会 (ACL,The Association for Computational Linguistics),是世界上影响力最大.最具活力的国际学术组织之一,其会员遍布世界各地.ACL ...

  8. 电影解说都是怎么配音的?电影解说配音实战教程

    现在短视频已经离不开大家的生活了,我相信只要一提到短视频,大家首先就想到的是抖音的电影解说和一些有趣的视频配音,之所以这些视频深受大家喜欢,不可或缺的是因为他们高超的剪辑水评,以及高质量的配音水评. ...

  9. 网吧看电影你们都用什么IT网站看网吧电影会员免费免VIP的那种

    今天来写的是网吧看电影你们都用什么IT网站看网吧电影会员免费免VIP的那种,有没有呢,一直找着. 谁可以告诉我在网吧怎样弄声音外放,得看机器本身带不带外置扬声器,如果没有的话,是外放不了的, 现在网吧 ...

最新文章

  1. 自动驾驶解决方案架构
  2. [j2me]类似于OperaMini二级菜单界面演练[1]
  3. 火蚁机器人_适度偷懒提高整体效率:火蚁工作方式启发机器人群组协作
  4. mysql+keepalived必须要lvs吗_MySQL 双主热备 + LVS + Keepalived 高可用操作记录
  5. 三个表格居中纵向html,前端技巧集:图与表三步垂直居中
  6. Git:Rebase和Merge之间的区别,看完这篇文章你就懂了!
  7. 2.页面布局示例笔记
  8. mysql递归查询所有上下节点_非递归打印二叉树的所有路径,保存父节点和孩子节点到底有啥差别...
  9. python https 协议_Python中连接HTTPS网站如何强制使用TLSv1协议
  10. Linux异步管道多线程速率测试
  11. [转]Oracle分页之三:利用PagerView来实现无刷新GridView
  12. mysql脚本之家_详细讲述MySQL中的子查询操作 (来自脚本之家)
  13. AndroidDeveloper Weekly No.1
  14. PHP Yii开源框架入门学习(二)修改Yii网站访问路径
  15. 网站建设中常见的21个漏洞及预防方法
  16. Vue2.0源码解析 - 知其然知其所以然之keep-alive原理分析(二)
  17. linux删除大量过期文件,linux删除大量文件的6种方法
  18. linux中的sh、dash、bash的区别
  19. 隔离变压器不触电原因
  20. 什么是逻辑卷管理器lvm?lvm设备的管理

热门文章

  1. MSP430 5xx/6xx系列 低频振荡器VLO编程实例(源码+电路)
  2. 《Learning Scrapy》(中文版)第7章 配置和管理
  3. 国内第二波信息化wave:国家智能电网标准出台-《智能电网技术标准体系规划》...
  4. 【小毛驴的絮叨】英语帝国建立记
  5. 知识图谱构建之数据集分析
  6. 扩展Redis的JSON处理模块,非常强调性能的RedisJson!速学
  7. C++中1e9(初始化、无穷大)解析
  8. android代码修改默认输入法,Android 4.3 源码下如何修改默认输入法
  9. 测试人耳听力频率的软件,超火的听力测试,测测你的耳朵可以听到多少赫兹?...
  10. 正则表达式 常用工具类