用Python爬蟲爬了貓眼TOP100電影后,我發現了……

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

通常來說,實現一個爬蟲分三個步驟:

1 獲取網頁

爬蟲就是爬取網頁上的內容,首先獲取網頁內容,比如文本、圖片、視頻等,這些信息都包裹在網頁的 HTML 源代碼中,爬蟲程序先請求獲取網頁的源代碼,接下來在源代碼中提取我們想要的信息。

2 提取信息

從雜亂的網頁源代碼中,提取出整潔有序的信息是爬蟲中最重要的一步。通常需提取的信息是包裹在一層又一層的網頁源代碼節點中的,有多種方法可以來提取出這些信息,最通用萬能的方法是採用「正則表達式」提取,使用它的好處在於不用去分析源代碼中繁複錯雜的節點信息,直接使用正則表達式語法去提取,簡單直接。不過正則表達式語法寫起來比較複雜,也容易出錯,效率不高,所以一般不把它當作首選方法。

Python 中有一些專門提取網頁信息的庫,比如 Beautiful Soup 、PyQuery 、lxml 等。這些庫可以利用 CSS 選擇器或者 XPath 來提取信息,比寫正則表達式簡單許多。藉助一些插件,信息提取更容易,速度更快。

記得關注小編後私信【學習】領取Python學習教程哦。

3 存儲數據

信息提取好可保存下來以便後續使用,Python 中可選擇多種數據保存形式,

比如 CSV 、txt,也可以保存到數據庫,如 MySQL 、MongoDB 等。


瞭解實現爬蟲的基本步驟後,我們上手一個實戰項目來加深理解,這個項目是用多種方法爬取並分析「貓眼 TOP 100 電影」。

項目知識點:

Requests 請求庫用法正則表達式用法lxml+XPath 用法Beatutiful Soup+CSS 選擇器用法Beatutiful Soup+Find_all 用法

1. 流程分析

這是要爬取的網頁:http://maoyan.com/board/4?offset=0


用Python爬蟲爬了貓眼TOP100電影后,我發現了……

該網頁上有 100 電影的電影名稱、演員名、評分、上映時間等信息,需要爬取下來,然後存儲到本地 CSV 文件。


用Python爬蟲爬了貓眼TOP100電影后,我發現了……

接著,對這些數據做簡單地分析,分析內容包括這幾方面:

  • 哪部電影評分最高?
  • 哪位演員作品數量最多?
  • 哪個國家/地區上榜電影數量最多?
  • 哪一年上榜電影數量最多?

2. 網頁抓取

先來分析下 URL 規律,下拉頁面到底部,點擊第 2 頁,網址變成:

http://maoyan.com/board/4?offset=10

offset 表示偏移,10 代表一個頁面的電影偏移數量,可以推斷出 url 的變化規律,即:第一頁電影是從 0-10,第二頁電影是從 11-20。要獲取全部 100 部電影,只需要構造出 10 個 url,然後用 Python 請求庫請求網頁,從返回的響應中提取出所需內容就可以了。

常用的 Python 請求庫有 urllib 和 Requests,相比 urllib,Requests 更強大好用,所以我們直用 Requests 方法來請求網頁。

2.1. Requests 請求網頁

先定義一個函數 get_one_page() ,傳入 url 參數來請求第一頁內容。

def get_one_page(url):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36'}

# 不加 headers 爬不了
response = requests.get(url, headers=headers)
if response.status_code == 200:
return response.text

接下來在 main()函數中設置 url。

def main():
url = 'http://maoyan.com/board/4?offset=0'
html = get_one_page(url)
print(html)
if __name__ == '__main__':
main()

運行程序,首頁源代碼就爬取下來了:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

接下來就需要從 HTML 源代碼中提取出所需內容,我們前述所說的四種方法來解析提取,下面一一介紹。

2.2. 正則表達式提取

正則表達式從字面上難以理解,下面這串看起來亂七八糟的符號就是正則表達式。

'

.*?board-index.*?>(\d+).*?class="lazy" data-original="(.*?)".*?name">(.*?).*?'

它是一種強大的字符串處理工具,之所以叫正則表達式,是因為它能別正則字符串。什麼意思呢,就是說:“ 如果你給我的字符串符合規則,就返回它;如果字符串不符合規則,就忽略它”。Requests 請求網頁返回 HTML是一堆字符串,使用它處理後便可提取出想要的內容。

常見的正則表達式語法有這些:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

下面,就來提取所需信息。右鍵網頁-檢查-Network 選項,選中左邊第一個文件然後定位到電影信息的相應位置,如下圖:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

可以看到每部電影的相關信息都在dd這個節點之中,就可以從該節點運用正則提取。

第 1 個要提取的內容是電影排名,是數字。

它位於 class="board-index"的i節點內。不需要提取的內容用'.*?'替代,需要提取的數字排名用()括起來,()裡面的數字表示為(\d+)。正則表達式可以寫為:

'
.*?board-index.*?>(\d+)'

第 2 個需要提取的是封面圖片網址,URL 位於 img 節點的'src'屬性中,正則表達式可寫為:

'class="lazy" data-original="(.*?)".*?'

第 1 和第 2 個正則之間的代碼是不需要的,用'.*?'替代,所以這兩部分合起來寫就是:

'
.*?board-index.*?>(\d+).*?class="lazy" data-original="(.*?)"

同理,可以依次用正則寫下主演、上映時間和評分等內容,完整的正則表達式如下:

'

.*?board-index.*?>(\d+).*?class="lazy" data-original="(.*?)".*?name">(.*?).*?star">(.*?).*?releasetime">(.*?)(.*?).*?fraction">(.*?).*?
'

正則表達式寫好以後,可以定義一個頁面解析提取方法:parse_one_page(),用來提取內容:

def parse_one_page(html):
pattern = re.compile(
'
.*?board-index.*?>(\d+).*?class="lazy" data-original="(.*?)".*?name">(.*?).*?star">(.*?).*?releasetime">(.*?)(.*?).*?fraction">(.*?).*?
', re.S)
# re.S 表示匹配任意字符,如果不加,則無法匹配換行符

items = re.findall(pattern, html)
# print(items)
for item in items:
yield {
'index': item[0],
'thumb': get_thumb(item[1]), # 定義 get_thumb()方法進一步處理網址
'name': item[2],
'star': item[3].strip()[3:],
# 'time': item[4].strip()[5:],
# 用兩個方法分別提取 time 裡的日期和地區
'time': get_release_time(item[4].strip()[5:]),
'area': get_release_area(item[4].strip()[5:]),
'score': item[5].strip() + item[6].strip()
# 評分 score 由整數+小數兩部分組成
}

tips:

re.S:匹配任意字符,如果不加則無法匹配換行符;

yield:使用 yield 的好處是作為生成器,可以遍歷迭代,並且將數據整理形成字典,輸出結果美觀。

.strip():用於去掉字符串中的空格。

為了便於提取內容,這裡又定義了 3 個方法:get_thumb()、get_release_time()和 get_release_area():

# 獲取封面大圖
def get_thumb(url):
pattern = re.compile(r'(.*?)@.*?')
thumb = re.search(pattern, url)
return thumb.group(1)
# http://p0.meituan.net/movie/5420be40e3b755ffe04779b9b199e935256906.jpg@160w_220h_1e_1c
# 去掉@160w_220h_1e_1c 就是大圖
# 提取上映時間函數

def get_release_time(data):
pattern = re.compile(r'(.*?)(\(|$)')
items = re.search(pattern, data)
if items is None:
return '未知'
return items.group(1) # 返回匹配到的第一個括號(.*?)中結果即時間
# 提取國家/地區函數
def get_release_area(data):
pattern = re.compile(r'.*\((.*)\)')
# $表示匹配一行字符串的結尾,這裡就是(.*?);\(|$,表示匹配字符串含有(,或者只有(.*?)
items = re.search(pattern, data)
if items is None:
return '未知'
return items.group(1)

tips:

'r':正則前面加上'r' 是為了告訴編譯器這個 string 是個 raw string,不要轉意'\'。當一個字符串使用了正則表達式後,最好在前面加上'r';

'|' ':正則表示或,'表示匹配一行字符串的結尾;

.group(1):意思是返回 search 匹配的第一個括號中的結果,即(.*?),gropup()則返回所有結果 2013-12-18(,group(1)返回'('。

接下來,修改 main()函數來輸出爬取的內容:

def main():
url = 'http://maoyan.com/board/4?offset=0'
html = get_one_page(url)
for item in parse_one_page(html):
print(item)
if __name__ == '__main__':

main()

tips:

if __ name__ == '_ main_': 當.py 文件被直接運行時,if __ name__ == '_ main_'之下的代碼塊將被運行;當.py 文件以模塊形式被導入時,if __ name__ == '_ main_'之下的代碼塊不被運行。

參考:https://blog.csdn.net/yjk13703623757/article/details/77918633。

最後運行程序,就能提取出第一頁我們需要的全部信息:

{'index': '1', 'thumb': 'http://p1.meituan.net/movie/20803f59291c47e1e116c11963ce019e68711.jpg', 'name': '霸王別姬', 'star': '張國榮,張豐毅,鞏俐', 'time': '1993-01-01', 'area': '中國香港', 'score': '9.6'}
{'index': '2', 'thumb': 'http://p0.meituan.net/movie/54617769d96807e4d81804284ffe2a27239007.jpg', 'name': '羅馬假日', 'star': '格利高裡·派克,奧黛麗·赫本,埃迪·艾伯特', 'time': '1953-09-02', 'area': '美國', 'score': '9.1'}
{'index': '3', 'thumb': 'http://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg', 'name': '肖申克的救贖', 'star': '蒂姆·羅賓斯,摩根·弗里曼,鮑勃·岡頓', 'time': '1994-10-14', 'area': '美國', 'score': '9.5'}
{'index': '4', 'thumb': 'http://p0.meituan.net/movie/e55ec5d18ccc83ba7db68caae54f165f95924.jpg', 'name': '這個殺手不太冷', 'star': '讓·雷諾,加里·奧德曼,娜塔莉·波特曼', 'time': '1994-09-14', 'area': '法國', 'score': '9.5'}
{'index': '5', 'thumb': 'http://p1.meituan.net/movie/f5a924f362f050881f2b8f82e852747c118515.jpg', 'name': '教父', 'star': '馬龍·白蘭度,阿爾·帕西諾,詹姆斯·肯恩', 'time': '1972-03-24', 'area': '美國', 'score': '9.3'}
...
}
[Finished in 1.9s]

以上是第 1 種提取方法,如果還不習慣正則表達式這種複雜的語法,可以試試下面的第二種方法。

2.3. lxml 結合 XPath 提取

該方法需要用到 lxml 這款解析利器,同時利用 XPath 語法的路徑選擇表達式,高效提取網頁內容。lxml 包為第三方包,需要自行安裝。

XPath,全稱 XML Path Language,即 XML 路徑語言,是一門在XML文檔中查找信息的語言,同樣適用於 HTML 文檔的搜索。是一個爬蟲信息抽取利器。

xpath 常用規則如下:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

下面,我們利用 lxml 和 XPath 來提取信息。






2018-08-18已更新


榜單規則:將貓眼電影庫中的經典影片,按照評分和評分人數從高到低綜合排序取前 100 名,每天上午 10 點更新。相關數據來源於“貓眼電影庫”。




1






主演:張國榮,張豐毅,鞏俐



上映時間:1993-01-01(中國香港)



9.6







根據截取的部分 html 網頁,先來提取第 1 個電影排名信息,有兩種方法。

第一種是直接複製。

右鍵-Copy-Copy Xpath,得到 XPath 路徑為://\*[@id="app"]/div/div/div[1]/dl/dd[1]/i,為了能夠提取到頁面所有的排名信息,需進一步修改為:/\*[@id="app"]/div/div/div[1]/dl/dd/i/text(),如果想要再精簡一點,可以省去中間部分絕對路徑'/'然後用相對路徑'//'代替,最後進一步修改為://\*[@id="app"]//div//dd/i/text()。

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

第二種:觀察網頁結構自己寫。

注意到id = app的 div 節點,因為在整個網頁結構 id 是唯一的不會有第二個相同的,所有可以將該 div 節點作為 xpath 語法的起點,然後往下觀察分別是 3 級 div 節點,可以省略寫為://div,再往下分別是是兩個並列的p節點、dl節點、dd節點和最後的i節點文本。中間可以隨意省略,只要保證該路徑能夠選擇到唯一的文本值'1'即可,例如省去 p 和 dl 節點,只保留後面的節點。這樣,完整路徑可以為:*//\*[@id="app"]//div//dd/i/text(),和上式一樣。

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

根據上述思路,可以寫下其他內容的 XPath 路徑。觀察到路徑的前一部分://\*[@id="app"]//div//dd都是一樣的,從後面才開始不同,因此為了能夠精簡代碼,將前部分路徑賦值為一個變量 items,最終提取的代碼如下:

# 2 用 lxml 結合 xpath 提取內容
from lxml import etree
def parse_one_page2(html):
parse = etree.HTML(html)
items = parse.xpath('//*[@id="app"]//div//dd')
# 完整的是//*[@id="app"]/div/div/div[1]/dl/dd
# print(type(items))
# *代表匹配所有節點,@表示屬性
# 第一個電影是 dd[1],要提取頁面所有電影則去掉[1]
# xpath://*[@id="app"]/div/div/div[1]/dl/dd[1]
for item in items:
yield{
'index': item.xpath('./i/text()')[0],
#./i/text()前面的點表示從 items 節點開始
#/text()提取文本
'thumb': get_thumb(str(item.xpath('./a/img[2]/@src')[0].strip())),
# 'thumb': 要在 network 中定位,在 elements 裡會寫成@src 而不是@data-src,從而會報 list index out of range 錯誤。
'name': item.xpath('./a/@title')[0],
'star': item.xpath('.//p[@class = "star"]/text()')[0].strip(),
'time': get_release_time(item.xpath(
'.//p[@class = "releasetime"]/text()')[0].strip()[5:]),
'area': get_release_area(item.xpath(
'.//p[@class = "releasetime"]/text()')[0].strip()[5:]),
'score' : item.xpath('.//p[@class = "score"]/i[1]/text()')[0] + \
item.xpath('.//p[@class = "score"]/i[2]/text()')[0]
}

tips:

[0]:XPath 後面添加了[0]是因為返回的是隻有 1 個字符串的 list,添加[0]是將 list 提取為字符串,使其簡潔;

Network:要在最原始的 Network 選項卡中定位,而不是 Elements 中,不然提取不到相關內容;

p[@class = "star"]/text():提取 class 屬性為"star"的 p 節點的文本值;

img[2]/@src':提取 img 節點的 src 屬性值,屬性值後面無需添加'/text()'

運行程序,就可成功地提取出所需內容,結果和第一種方法一樣。

如果不太習慣 XPath 語法,可以試試下面的第三種方法。

記得關注小編後私信【學習】領取Python學習教程哦。

2.4. Beautiful Soup + CSS 選擇器

Beautiful Soup 同 lxml 一樣,是一個非常強大的 Python 解析庫,可以從 HTML 或 XML 文件中提取效率非常高,常用的語法如下:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

更多用法可參考下面的教程:

https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/

不過 Beautiful Soup 通常結合 CSS 選擇器一起使用,形成 soup.select 方法,提取信息更簡單。CSS 選擇器選是一種模式,用於選擇需要添加樣式的元素,使用它的語法同樣能夠快速定位到所需節點,然後提取相應內容。

CSS 選擇器常用的規則 :

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

更多用法可參考下面的教程:

http://www.w3school.com.cn/cssref/css_selectors.asp

下面就利用這種方式來提取:

# 3 用 beautifulsoup + css 選擇器提取
def parse_one_page3(html):
soup = BeautifulSoup(html, 'lxml')
items = range(10)
for item in items:
yield{
'index': soup.select('dd i.board-index')[item].string,
# iclass 節點完整地為'board-index board-index-1',寫 board-index 即可
'thumb': get_thumb(soup.select('a > img.board-img')[item]["src"]),
# 表示 a 節點下面的 class = board-img 的 img 節點,注意瀏覽器 eelement 裡面是 src 節點,而 network 裡面是 src 節點,要用這個才能正確返回值
'name': soup.select('.name a')[item].string,
'star': soup.select('.star')[item].string.strip()[3:],
'time': get_release_time(soup.select('.releasetime')[item].string.strip()[5:]),
'area': get_release_area(soup.select('.releasetime')[item].string.strip()[5:]),
'score': soup.select('.integer')[item].string + soup.select('.fraction')[item].string

運行上述程序,結果同同前述方法一樣。

2.5. Beautiful Soup + find_all 函數提取

Beautifulsoup 除了和 CSS 選擇器搭配,還可以直接用它自帶的 find_all 函數進行提取。

find_all,顧名思義,就是查詢所有符合條件的元素,可以給它傳入一些屬性或文本來得到符合條件的元素,功能十分強大,API 接口如下:

find_all(name , attrs , recursive , text , **kwargs)

常用的語法規則有這幾點

soup.find_all(name='ul'): 查找所有ul節點,ul 節點內還可以嵌套;

li.string 和 li.get_text():都是獲取li節點的文本,但推薦使用後者;

soup.find_all(attrs={'id': 'list-1'})):傳入 attrs 參數,參數的類型是字典類型,表示查詢 idlist-1 的節點;

常用的屬性比如 id、class 等,可以省略 attrs 採用更簡潔的形式,例如:

soup.find_all(id='list-1')

soup.find_all(class_='element')

用這種方法提取內容,可以這樣寫:

def parse_one_page4(html):
soup = BeautifulSoup(html,'lxml')
items = range(10)
for item in items:
yield{
'index': soup.find_all(class_='board-index')[item].string,
'thumb': soup.find_all(class_ = 'board-img')[item].attrs['src'],
# 用.get('src')獲取圖片 src 鏈接,或者用 attrs['src']
'name': soup.find_all(name = 'p',attrs = {'class' : 'name'})[item].string,
'star': soup.find_all(name = 'p',attrs = {'class':'star'})[item].string.strip()[3:],

'time': get_release_time(soup.find_all(class_ ='releasetime')[item].string.strip()[5:]),
'area': get_release_time(soup.find_all(class_ ='releasetime')[item].string.strip()[5:]),
'score':soup.find_all(name = 'i',attrs = {'class':'integer'})[item].string.strip() + soup.find_all(name = 'i',attrs = {'class':'fraction'})[item].string.strip()
}

提取結果仍然和前述方法一樣。

以上,我們用了四種不同方法來解析提取信息,通過對比可以加深對每種方法的理解,接下來就要保存提取的內容。

3. 數據存儲

上面輸出的結果是字典格式,可利用 csv 包的 DictWriter 函數將字典格式數據存儲到 csv 文件中。

# 數據存儲到 csv
def write_to_file3(item):
with open('貓眼 top100.csv', 'a', encoding='utf_8_sig',newline='') as f:
# 'a'為追加模式(添加)
# utf_8_sig 格式導出 csv 不亂碼
fieldnames = ['index', 'thumb', 'name', 'star', 'time', 'area', 'score']
w = csv.DictWriter(f,fieldnames = fieldnames)
# w.writeheader()
w.writerow(item)

然後修改一下 main()方法:

def main():
url = 'http://maoyan.com/board/4?offset=0'
html = get_one_page(url)
for item in parse_one_page(html):
# print(item)
write_to_csv(item)
if __name__ == '__main__':
main()

結果如下圖: 再把封面的圖片下載下來:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

def download_thumb(name, url,num):
try:
response = requests.get(url)
with open('封面圖/' + name + '.jpg', 'wb') as f:
f.write(response.content)
print('第%s 部電影封面下載完畢' %num)
print('------')
except RequestException as e:
print(e)
pass
# 不能是 w,否則會報錯,因為圖片是二進制數據所以要用 wb

這樣我們就完成了第一頁信息爬取和存儲。一共有十頁信息,下面我們構造一個簡單

這樣我們就完成了第一頁信息爬取和存儲。一共有十頁信息,下面我們構造一個簡單的循環,就可以爬取全部頁數信息。

4. 分頁爬取

剩下 9 頁共 90 部電影的數據可以給網址傳入一個 offset 參數,然後遍歷 URL 重複執行上面的過程即可,代碼修改如下:

def main(offset):
url = 'http://maoyan.com/board/4?offset=' + str(offset)
html = get_one_page(url)
for item in parse_one_page(html):
write_to_csv(item)
if __name__ == '__main__':
for i in range(10):
main(offset = i*10)

這樣我們就爬取了全部電影信息,結果如下:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……


用Python爬蟲爬了貓眼TOP100電影后,我發現了……

5. 數據分析

俗話說“文不如表,表不如圖”。下面爬取的數據做簡單的數據可視化分析。

5.1. 評分最高的十部電影

先來看一看評分最高的十部電影是哪些,代碼編寫如下:

import pandas as pd
import matplotlib.pyplot as plt
import pylab as pl #用於修改 x 軸座標
plt.style.use('ggplot') #默認繪圖風格很難看,替換為好看的 ggplot 風格
fig = plt.figure(figsize=(8,5)) #設置圖片大小
colors1 = '#6D6D6D' #設置圖表 title、text 標註的顏色
columns = ['index', 'thumb', 'name', 'star', 'time', 'area', 'score'] #設置表頭
df = pd.read_csv('maoyan_top100.csv',encoding = "utf-8",header = None,names =columns,index_col = 'index') #打開表格
# index_col = 'index' 將索引設為 index
df_score = df.sort_values('score',ascending = False) #按得分降序排列
name1 = df_score.name[:10] #x 軸座標
score1 = df_score.score[:10] #y 軸座標
plt.bar(range(10),score1,tick_label = name1) #繪製條形圖,用 range()能搞保持 x 軸正確順序
plt.ylim ((9,9.8)) #設置縱座標軸範圍
plt.title('電影評分最高 top10',color = colors1) #標題
plt.xlabel('電影名稱') #x 軸標題
plt.ylabel('評分') #y 軸標題
# 為每個條形圖添加數值標籤
for x,y in enumerate(list(score1)):
plt.text(x,y+0.01,'%s' %round(y,1),ha = 'center',color = colors1)
pl.xticks(rotation=270) #x 軸名稱太長髮生重疊,旋轉為縱向顯示
plt.tight_layout() #自動控制空白邊緣,以全部顯示 x 軸名稱
# plt.savefig('電影評分最高 top10.png') #保存圖片
plt.show()

結果如下圖:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

可以看到,排名最高的分別是兩部國產片《霸王別姬》和《大話西遊》,其他還包括《肖申克的救贖》、《教父》等。

5.2. 各國電影數量對比

來了解一下這 100 部電影都是來自哪些國家,代碼編寫如下:

area_count = df.groupby(by = 'area').area.count().sort_values(ascending = False)
# 繪圖方法 1
area_count.plot.bar(color = '#4652B1') #設置為藍紫色

pl.xticks(rotation=0) #x 軸名稱太長重疊,旋轉為縱向
# 繪圖方法 2
# plt.bar(range(11),area_count.values,tick_label = area_count.index)
for x,y in enumerate(list(area_count.values)):
plt.text(x,y+0.5,'%s' %round(y,1),ha = 'center',color = colors1)
plt.title('各國/地區電影數量排名',color = colors1)
plt.xlabel('國家/地區')
plt.ylabel('數量(部)')
plt.show()
# plt.savefig('各國(地區)電影數量排名.png')

結果如下圖:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

可以看到,除去網站自身沒有顯示國家的電影以外,上榜電影被 10 個國家/地區"承包"了。其中,美國以 30 部電影的絕對優勢佔據第 1 名,其次是 8 部的日本,7 部的韓國。香港有 5 部,而內地一部都沒有。

5.3. 電影大年

這些電影拍攝的年份時間跨度很大,統計一下各年的電影數量,看看是否存在"電影大年"。

# 從日期中提取年份
df['year'] = df['time'].map(lambda x:x.split('/')[0])
# print(df.info())
# print(df.head())
# 統計各年上映的電影數量
grouped_year = df.groupby('year')
grouped_year_amount = grouped_year.year.count()
top_year = grouped_year_amount.sort_values(ascending = False)
# 繪圖
top_year.plot(kind = 'bar',color = 'orangered') #顏色設置為橙紅色
for x,y in enumerate(list(top_year.values)):
plt.text(x,y+0.1,'%s' %round(y,1),ha = 'center',color = colors1)
plt.title('電影數量年份排名',color = colors1)
plt.xlabel('年份(年)')
plt.ylabel('數量(部)')
plt.tight_layout()
# plt.savefig('電影數量年份排名.png')
plt.show()

結果如下圖:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

可以看到,100 部電影來自 37 個年份。其中 2011 年上榜電影數量最多,達到 9 部;其次是 2010 年的 7 部。網上盛傳的傳" 1994 電影史奇蹟年" 僅排名第 6,貓眼榜單的權威性有待考量。

另外,上世紀三四十年代也有電影上榜,那會兒還是黑白電影,反映了電影的口碑好壞跟外在技術沒有絕對的關係,質量才是王道。

5.4. 電影作品最多的演員

最後,看看前 100 部電影中哪些演員的作品數量最多。

#表中的演員位於同一列,用逗號分割符隔開。需進行分割然後全部提取到 list 中
starlist = []
star_total = df.star
for i in df.star.str.replace(' ','').str.split(','):
starlist.extend(i)
# print(starlist)
# print(len(starlist))
# set 去除重複的演員名
starall = set(starlist)
# print(starall)
# print(len(starall))
starall2 = {}
for i in starall:
if starlist.count(i)>1:
# 篩選出電影數量超過 1 部的演員
starall2[i] = starlist.count(i)
starall2 = sorted(starall2.items(),key = lambda starlist:starlist[1] ,reverse = True)

starall2 = dict(starall2[:10]) #將元組轉為字典格式
# 繪圖
x_star = list(starall2.keys()) #x 軸座標
y_star = list(starall2.values()) #y 軸座標
plt.bar(range(10),y_star,tick_label = x_star)
pl.xticks(rotation = 270)
for x,y in enumerate(y_star):
plt.text(x,y+0.1,'%s' %round(y,1),ha = 'center',color = colors1)
plt.title('演員電影作品數量排名',color = colors1)
plt.xlabel('演員')
plt.ylabel('數量(部)')
plt.tight_layout()
plt.show()
# plt.savefig('演員電影作品數量排名.png')

結果如下圖:

用Python爬蟲爬了貓眼TOP100電影后,我發現了……

張國榮排在了第一位,覺得意外麼?其次是梁朝偉和周星馳,再之後是布拉德·皮特。仔細數一下,前十名影星中,香港影星佔了 6 位,這份榜單真是偏愛港星。

對張國榮以七部影片的巨大優勢佔據第一感到好奇,來看看是哪七部電影。

df['star1'] = df['star'].map(lambda x:x.split(',')[0]) #提取 1 號演員
df['star2'] = df['star'].map(lambda x:x.split(',')[1]) #提取 2 號演員
star_most = df[(df.star1 == '張國榮') | (df.star2 == '張國榮')][['star','name']].reset_index('index')
# |表示兩個條件或查詢,之後重置索引
print(star_most)

可以看到包括排名第一的《霸王別姬》、第 17 名的《春光乍洩》、第 27 名的《射鵰英雄傳之東成西就》等。這些電影你都看過麼。

index star name
0 1 張國榮,張豐毅,鞏俐 霸王別姬
1 17 張國榮,梁朝偉,張震 春光乍洩
2 27 張國榮,梁朝偉,張學友 射鵰英雄傳之東成西就
3 37 張國榮,梁朝偉,劉嘉玲 東邪西毒
4 70 張國榮,王祖賢,午馬 倩女幽魂
5 99 張國榮,張曼玉,劉德華 阿飛正傳
6 100 狄龍,張國榮,周潤發 英雄本色

以上,我們使用了多種方法爬取並分析了貓眼 TOP 100 電影,初步瞭解了爬蟲的基本技法。

記得關注小編後私信【學習】領取Python學習教程哦。

用Python爬蟲爬了貓眼TOP100電影后,我發現了……


分享到:


相關文章: