用漂亮的圖表展示爬取到的數據


經過了前面的努力,我們成功獲取到了數據,並且學會了保存,但是只是用網頁展示出來,是不是有一些不夠美觀呢?

所以本節的內容是:數據的可視化。拿到了數據卻不能使其簡單易懂並且足夠突出,那就是不是好的數據工程師。

效果圖:


 
部分效果圖

本節需要做的准備: 安裝pyecharts這個Python的圖表庫,在之前我們安裝了requests、lxml、bs4。所以只需要再在cmd里面 pip3 install pyecharts 就OK啦,如果失敗,請仔細閱讀教程:爬蟲入門教程⑥—安裝爬蟲常用工具包

 

  • pyecharts簡介

這是百度echarts圖表庫,使用Python接口進行生成圖表的一個庫,非常炫酷。在之前繪圖基本上是用的【Matplotlib】這個庫,這個庫功能非常強大,但是缺點也比較明顯,api調用比較復雜,新手上手很慢也很難。於是在去年,陳鍵冬大佬推出了一個簡單易用的繪圖庫 pyecharts

我當時懷着試一試的心情使用了一下,哇,超好用的,對新手超友好的,代碼和圖都寫出來了,非常詳細,同時配置項也非常清晰。一口氣畫5個圖都超快超簡單的~!

  • 確定可視化的目標

這是很重要的一步,先確認哪些數據值得拿來可視化,然后再去編寫代碼。一部電影的信息有:名字、上映日期、地區、類型、關注者數量。最明顯的當然是關注者數量排行榜(柱狀圖),除此之外我還想了幾個:
上映電影類型占比(餅圖)
上映地區占比(餅圖)
上映日期柱狀圖

  • 采集所有電影信息

先上之前的代碼:

import requests from bs4 import BeautifulSoup # 從bs4引入BeautifulSoup #請求網頁 url = "https://movie.douban.com/cinema/later/chengdu/" response = requests.get(url) soup = BeautifulSoup(response.content.decode('utf-8'), 'lxml') all_movies = soup.find('div', id="showing-soon") # 先找到最大的div for each_movie in all_movies.find_all('div', class_="item"): # 從最大的div里面找到影片的div # print(each_movie) # 輸出每個影片div的內容 all_a_tag = each_movie.find_all('a') all_li_tag = each_movie.find_all('li') movie_name = all_a_tag[1].text moive_href = all_a_tag[1]['href'] movie_date = all_li_tag[0].text movie_type = all_li_tag[1].text movie_area = all_li_tag[2].text movie_lovers = all_li_tag[3].text print('名字:{},鏈接:{},日期:{},類型:{},地區:{}, 關注者:{}'.format( movie_name, moive_href, movie_date, movie_type, movie_area, movie_lovers)) 

這是數據的基礎信息,我們先全部拿到,然后放進一個list,方便后續的比較分析處理。同時我們在代碼頂部,從pyecharts引入Page(在一張圖顯示多個圖表)、Pie(餅圖)、Bar(柱狀圖)。

# 可視化爬取結果
import requests
from bs4 import BeautifulSoup # 從bs4引入BeautifulSoup
from pyecharts.charts import Bar # 引入繪圖需要的模塊

from pyecharts.charts import Page # 引入繪圖需要的模塊
from pyecharts.charts import Pie # 引入繪圖需要的模塊

 


#請求網頁
url = "https://movie.douban.com/cinema/later/chengdu/"
response = requests.get(url)

soup = BeautifulSoup(response.content.decode('utf-8'), 'lxml')

all_movies = soup.find('div', id="showing-soon") # 先找到最大的div

# 先把所有的數據存到這個list里面
all_movies_info = []
for each_movie in all_movies.find_all('div', class_="item"): # 從最大的div里面找到影片的div
# print(each_movie) # 輸出每個影片div的內容
all_a_tag = each_movie.find_all('a')
all_li_tag = each_movie.find_all('li')
movie_name = all_a_tag[1].text
moive_href = all_a_tag[1]['href']
movie_date = all_li_tag[0].text
movie_type = all_li_tag[1].text
movie_area = all_li_tag[2].text
movie_lovers = all_li_tag[3].text.replace('人想看', '') # 去掉除了數字之外的字
# 把電影數據添加到list
all_movies_info.append({'name': movie_name, 'date': movie_date, 'type': movie_type,
'area': movie_area, 'lovers': movie_lovers})
# print('名字:{},日期:{},類型:{},地區:{}, 關注者:{}'.format(
# movie_name, movie_date, movie_type, movie_area, movie_lovers))
print(all_movies_info) # 輸出一下檢查數據是否傳遞成功

 

  • 繪制關注者排行榜

處理邏輯:首先把所有的電影以關注者數量排個序,然后從所有電影里面以獲取到電影的名字和電影的關注者數量,最后添加到柱狀圖里。
sorted函數,第一個參數接受一個可以遍歷的對象,key參數接受一個匿名函數,用以指定以遍歷對象內的哪個元素作為排序的依據
以下代碼添加到上一個示例代碼后面即可。

# 繪制關注者排行榜圖 # i['name'] for i in all_movies_info 這個是Python的快捷方式, # 這一句的作用是從all_movies_info這個list里面依次取出每個元素, # 並且取出這個元素的 name 屬性 sort_by_lovers = sorted(all_movies_info, key=lambda x: int(x['lovers'])) all_names = [i['name'] for i in sort_by_lovers] all_lovers = [i['lovers'] for i in sort_by_lovers] lovers_rank_bar = Bar('電影關注者排行榜') # 初始化圖表,給個名字 # all_names是所有電影名,作為X軸, all_lovers是關注者的數量,作為Y軸。二者數據一一對應。 # is_convert=True設置x、y軸對調,。is_label_show=True 顯示y軸值。 label_pos='right' Y軸值顯示在右邊 lovers_rank_bar.add('', all_names, all_lovers, is_convert=True, is_label_show=True, label_pos='right') lovers_rank_bar # jupyter下直接顯示圖表在輸出框內 

運行截圖:


 
電影關注者排行榜
  • 繪制電影類型占比圖

我們先從所有電影里獲取所有的電影類型(一個電影可能有多個類型,比如動畫 / 奇幻 / 冒險,就需要先分割成3個);然后通過代碼統計這些類型的數量,最后繪制成餅圖。代碼同樣添加到之前的代碼之后就OK。

# 繪制電影類型占比圖 all_types = [i['type'] for i in all_movies_info] type_count = {} for each_types in all_types: # 把 愛情 / 奇幻 這種分成[愛情, 奇幻] type_list = each_types.split(' / ') for e_type in type_list: if e_type not in type_count: type_count[e_type] = 1 else: type_count[e_type] += 1 # print(type_count) # 檢測是否數據歸類成功 type_pie = Pie('上映類型占比', title_top=20) # 因為類型過多影響標題,所以標題向下移20px # 直接取出統計的類型名和數量並強制轉換為list。 type_pie.add('', list(type_count.keys()), list(type_count.values()), is_label_show=True) type_pie # jupyter下直接顯示 

效果圖:


 
上映類型比例圖

 

  • 繪制上映日期圖

類似於上一個步驟,我們同樣拿到所有的上映日期並做一個數量統計再添加到條形圖就OK了。代碼同樣也是添加到上面的代碼之后就OK了。

# 繪制電影上映日期柱狀圖 all_dates = [i['date'] for i in all_movies_info] dates_count = {} for date in all_dates: if date not in dates_count: dates_count[date] = 1 else: dates_count[date] += 1 # print(dates_count) # 輸出驗證數據是否正確 dates_bar = Bar('上映日期占比') dates_bar.add('',list(dates_count.keys()), list(dates_count.values()), is_label_show=True) dates_bar # jupyter下直接顯示 

效果圖:


 
上映日期條形圖

完整代碼

要把所有的圖表都添加到一起一次性輸出,那么就需要使用Page這個類,把圖表加進去,這些圖表就會按照添加順序,挨個展示。完整代碼如下:
等下,遇到了問題,運行報錯了(獲取上映日期代碼報錯list out of range:也就是我們要第四個元素,但是它只有3個元素,所以超過了range),發現是過了12點,豆瓣更新了2部電影,這兩部電影,沒有上映日期~!所以更改了一點代碼以增強兼容性。爬蟲就是這樣,網頁結構變化了,代碼就要修改。所以這個工作還是可以做得比較久的。

# 可視化爬取結果 import requests from bs4 import BeautifulSoup # 從bs4引入BeautifulSoup from pyecharts import Page, Pie, Bar #請求網頁 url = "https://movie.douban.com/cinema/later/chengdu/" response = requests.get(url) soup = BeautifulSoup(response.content.decode('utf-8'), 'lxml') all_movies = soup.find('div', id="showing-soon") # 先找到最大的div all_movies_info = [] for each_movie in all_movies.find_all('div', class_="item"): # 從最大的div里面找到影片的div # print(each_movie) # 輸出每個影片div的內容 all_a_tag = each_movie.find_all('a') all_li_tag = each_movie.find_all('li') movie_name = all_a_tag[1].text moive_href = all_a_tag[1]['href'] # 運行報錯 index out of range:是因為有電影沒顯示日期 if len(all_li_tag) == 4: movie_date = all_li_tag[0].text movie_type = all_li_tag[1].text movie_area = all_li_tag[2].text movie_lovers = all_li_tag[3].text.replace('人想看', '') else: # 網站結構改變,跟着改變代碼 movie_date = "未知" movie_type = all_li_tag[0].text movie_area = all_li_tag[1].text movie_lovers = all_li_tag[2].text.replace('人想看', '') all_movies_info.append({'name': movie_name, 'date': movie_date, 'type': movie_type, 'area': movie_area, 'lovers': movie_lovers}) # print('名字:{},日期:{},類型:{},地區:{}, 關注者:{}'.format( # movie_name, movie_date, movie_type, movie_area, movie_lovers)) # print(all_movies_info) # 輸出一下檢查數據是否傳遞成功 page = Page() # 同一個網頁顯示多個圖 # 繪制關注者排行榜圖 # i['name'] for i in all_movies_info 這個是Python的快捷方式 # 這一句的作用是從all_movies_info這個list里面依次取出每個元素, # 並且取出這個元素的 name 屬性 sort_by_lovers = sorted(all_movies_info, key=lambda x: int(x['lovers'])) all_names = [i['name'] for i in sort_by_lovers] all_lovers = [i['lovers'] for i in sort_by_lovers] lovers_rank_bar = Bar('電影關注者排行榜') lovers_rank_bar.add('', all_names, all_lovers, is_convert=True, is_label_show=True, label_pos='right') page.add(lovers_rank_bar) # lovers_rank_bar # 繪制電影類型占比圖 all_types = [i['type'] for i in all_movies_info] type_count = {} for each_types in all_types: # 把 愛情 / 奇幻 這種分成[愛情, 奇幻] type_list = each_types.split(' / ') for e_type in type_list: if e_type not in type_count: type_count[e_type] = 1 else: type_count[e_type] += 1 # print(type_count) # 檢測是否數據歸類成功 type_pie = Pie('上映類型占比', title_top=20) type_pie.add('', list(type_count.keys()), list(type_count.values()), is_label_show=True) # type_pie page.add(type_pie) # 繪制電影上映日期柱狀圖 all_dates = [i['date'] for i in all_movies_info] dates_count = {} for date in all_dates: if date not in dates_count: dates_count[date] = 1 else: dates_count[date] += 1 # print(dates_count) # 輸出驗證數據是否正確 dates_bar = Bar('上映日期占比') dates_bar.add('',list(dates_count.keys()), list(dates_count.values()), is_label_show=True) # dates_bar page.add(dates_bar) page # jupyter下自動顯示 
簡單的分析
  • 關注者排行榜圖里,大雄的金銀島,6.1上映,關注人數4700,當之無愧的最火最期待的電影,畢竟是這么多快到中年的年輕人小時候很喜歡的動漫,並且也幾乎從來沒讓人失望過。
  • 上映電影類型圖里,最多的是劇情類,不過這個標簽比較平常,所以略過。剩下最多的就是冒險和動漫了,這個也和最近的日子有關系,畢竟明天就兒童節了,所以大部分電影和兒童、少年沾邊了。
  • 上映日期也表明了,大部分電影在6.1和6.8上映。6.1兒童節,大家容易理解,6.8呢?6.8是高考結束的那天啊~!!!廣大高三學子終於解放了~!!!解放了肯定就要看看電影啊~作為一個即將畢業的老人,提前恭祝廣大學子高考金榜題名!

后記

爬蟲入門教程就到此為止了,非常高興能夠和大家一起分享知識。一起學習Python爬蟲,把這門實用又有趣的技術,通過簡單的代碼,向各位展示出來。希望各位能從這個小小的爬蟲教程中,獲取到一點編程的樂趣,也了解一下為什么Life is short, I use Python是Python的slogan。
所以我真的太喜歡Python了。本着分享技術的精神,向各位從爬蟲的概念,基礎知識,編碼,數據提取,數據可視化,簡單數據分析 向大家介紹了Python爬蟲方面的簡單知識。如果這幾篇文章能夠讓你對代碼,對爬蟲,對Python產生一點積極的作用,那我會覺得非常開心!

Python的禪宗三字經——蒂姆•彼得斯
優美勝於丑陋,
明了勝於晦澀,
簡潔勝於復雜,
復雜勝於凌亂,
間隔勝於緊湊,
可讀性很重要,
即便假借特例的實用性之名,也不可違背這些規則,
不要包容所有錯誤,除非你確定需要這樣做,
當存在多種可能,不要嘗試去猜測 ,
而是盡量找一種,最好是唯一一種明顯的解決方案,
雖然這並不容易,因為你不是 Python 之父。
做也許好過不做,但不假思索就動手還不如不做,
如果你無法向人描述你的方案,那肯定不是一個好方案;
反之亦然,命名空間是一種絕妙的理念,我們應當多加利用

是的,在Python任何版本,代碼里面輸入import this,就會出現Python的格言。意在勸告人們寫Python要遵循的規則,也就是寫代碼要pythonic~!

In [1]: import this """ The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those! """ 

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM