Python數據可視化:2018年電影分析

2021-02-13 Python中文社區

法納斯特,Python愛好者,喜歡爬蟲,數據分析以及可視化。

雙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  電影類型分布

劇情電影永遠引人深思。感覺今年的電影好多跟錢有關,比如「我不是藥神」「西虹市首富」「一齣好戲」「頭號玩家」,貧窮限制了大傢伙們。

關注數據科學俱樂部公眾號後回復電影即可獲取全部源碼。

相關焦點

  • Python的數據可視化:對比7種工具包
    Python 的scientific stack(一個介紹Python科學計算包的網站)已經完全成熟,並且有各種各樣用例的庫,包括機器學習(連結:machine learning),數據分析(連結:data analysis)。數據可視化是探索數據和清晰的解釋結果很重要的一部分,但是Python在過去卻相對於其他工具比如R落後一點。
  • Python數據分析:股票數據分析案例
    步驟:準備數據可視化數據、審查數據處理數據根據ACF、PACF定階擬合ARIMA模型預測準備數據    # 指定股票分析開始日期    start_date = datetime.datetime(2009, 1, 1)    # 指定股票分析截止日期    end_date = datetime.datetime(2019, 4, 1)    # 股票代碼    stock_code = '600519.SS'    # 滬市貴州茅臺
  • Pajek:關係網絡分析和可視化工具
    近日做社交媒體用戶行為分析,需要展示用戶關係的結果。發現Pajek已經到5.0版了,幾年前版本還很低。
  • Python 網絡爬蟲實戰:爬取並下載《電影天堂》3千多部動作片電影
    你想嘛,早上上班前跑一下爬蟲,晚上回家以後已經有幾十部最新大片在你硬碟裡等著你啦,累了一天躺床上看看電影,這種感覺是不是很爽啊。而且正因為這個爬蟲比較簡單,所以我會寫的稍微細一點,爭取讓 python 小白們也能儘可能看懂,並且能夠在這個爬蟲的基礎上修改,得到爬取這個網站其他板塊或者其他電影網站的爬蟲。
  • Python學習:mac電腦安裝python教程
    與python2.7 共存2 下載安裝包進入官方安裝包下載頁面,https://www.python.org/downloads/mac-osx/找到合適的安裝包,基本上mac電腦都是64位的系統,因此選擇64位的安裝包進行下載
  • Python爬蟲實戰:爬取天氣數據的實例詳解
    在本篇文章裡小編給大家整理的是一篇關於python爬取天氣數據的實例詳解內容,有興趣的朋友們學習下。
  • 大數據:最適合學英語的20部迪士尼電影
    今天這篇文章,不僅僅講的是電影。Frank用大數據分析電影學英語這件事兒, 值得說說。首先,他的綜合技能,代表了我們未來培養孩子的方向,或者說,未來的人才的素質模型。表面上看是四個基本技能:數學、閱讀、編程、外語。底層看是一個綜合的研究技能,包括提出問題,跨學科整合資源,分析研究並得出結論。
  • 新年微課:實戰學習網絡輿情可視化工具
    而隨著大數據時代的到來,網絡輿論在數據體量、複雜性和產生速度等方面發生巨大變化。以往的網絡輿情的內容樣本分析已無法準確的描繪熱點事件中網絡輿論的發展之勢了。而可視化工具的出現則很好的彌補了這一缺陷。它不僅可以抓取輿論數據,並繪製出網絡輿論的傳播軌跡圖,了解網絡事件的傳播發展過程。
  • 詞彙星空:如何構建一個炫酷的 Word2Vec 可視化
    本文由劉晶翻譯自 github原項目地址:https://github.com/anvaka/word2vec-graph1.數據集1.1GloVe 數據集用於該可視化的數據集來自GloVe,包含60億詞條,40萬單詞,每個單詞由一個300維向量表示。
  • Python詞雲:Windows安裝Wordcloud報錯解決辦法
    首先,先看清楚你的python版本,以及搞清楚你的python是基於32位系統還是64位系統。具體操作方法:1、 在左下角搜索windows搜索框裡輸入cmd,打開命令行窗口;2、 輸入python;3、 這裡可以看到python的版本是3.8.2,基於32位系統。
  • 360瀏覽器大數據分析 2017春運或將一票難求
    」和「春運大數據可視化地圖系統」,由於今年春運比上年提前11天,加上12306網站車票預售期縮短為30天,再加上春運期間可能出現的「拉尼娜」天氣事件,《報告》預測,2017春運或將導致『史上最難搶票年』的出現。
  • 數據分析與可視化示例一:pandas和plotly快速拼湊《某地19年耕地質量調查評價報告》
    /usr/bin/env python# -*- coding:utf-8 -*-# # Author: LiaoChenchen# Created on: 2020/11/9 16:45# Reference:"""Description: 對耕地質量等級點位表進行基本分析 統計最值、標準差、變異係數等Usage
  • Python數據可視化:平凡的世界
  • 乾貨分享:據說這是史上最全的大數據分析工具
    |沙龍精選自大數據人,原文來源於網絡百度ECharts:http://echarts.baidu.com/Cytoscape:http://www.cytoscape.org/圖表秀:http://www.tubiaoxiu.com/數據觀:http://shujuguan.cn/
  • 爆文精選:大數據文摘2016年1季度TOP10
    (2)解密幸福婚姻:心理學家+40年研究+3000對情侶數據簡介:心理學家高特曼夫婦通過超過40年的臨床實踐,12                                            (4)【租房數據分析】2016年在北京如何租到好房子?
  • 刷屏的北京霧霾,2018 年北上廣深空氣品質分析
    網站沒有反爬,所以直接抓取信息就好了。又是重操舊業,我的PPT水平還是很水呢~/ 02 / 數據獲取獲取代碼如下所示。即可獲取全部可視化源碼及相關文件。以前天天去下載PPT大神的大作,然後觀摩,可惜的是PPT水平還是那麼菜~01  AQI全年走勢圖
  • Python可視化:Seaborn庫熱力圖使用進階
    前言在日常工作中,經常可以見到各種各種精美的熱力圖,熱力圖的應用非常廣泛
  • V-RAY: 建築可視化 3D 渲染軟體
    8 分鐘,4K規格的 3D 立體電影。Tomorrow © Gensler電影大片:TOMORROWAB 呈現了 GENSLER 的美國第一高塔的概念場景受其影視特效背景的影響,瑞典可視化公司 Tomorrow 戴上了一副未來眼鏡,看到了平行宇宙的景象