經過了前面的努力,我們成功獲取到了數據,並且學會了保存,但是只是用網頁展示出來,是不是有一些不夠美觀呢?
所以本節的內容是:數據的可視化。拿到了數據卻不能使其簡單易懂並且足夠突出,那就是不是好的數據工程師。
效果圖:

本節需要做的准備: 安裝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]