背景
新近开始学习数据分析师课程,目前在数据获取阶段。这边记录下自己的课堂练习,也为后面复习留个底。
练习内容
如标题,利用维基百科标准的 url 格式,由电影标题生成对应的维基页面 url, 并批量访问下载电影海报。
已知条件:
通过 MediaWiki API 使用 wptools 访问维基百科页面数据,需要每部电影的维基百科页面标题,即网址中 en.wikipedia.org / wiki / 里最后一个斜杠之后的内容。测试中已经给出前 100 部电影的所有标题,我是直接拿来用的。
另外课程导师还贴心提示了下载代码技巧,避免走弯路:
import requests
from PIL import Image
from io import BytesIO
r = requests.get(url)
i = Image.open(BytesIO(r.content))
这样的做法好过用常规的文件打开、读取和写入方法(如下),这种有时候会破坏写入的文件。
import requests
r = requests.get(url)
with open(folder_name + '/' + filename, 'wb') as f:
f.write(r.content)
练习解决方案
# 导入必须的工具包
import pandas as pd
import wptools
import os
import requests
from PIL import Image
from io import BytesIO
# 定义电影标题列表,用来生成 url
title_list = [
'The_Wizard_of_Oz_(1939_film)',
'Citizen_Kane',
'The_Third_Man',
'Get_Out_(film)',
'Mad_Max:_Fury_Road'
]
# 准备好要用来存放下载图片的文件夹
folder_name = 'bestofrt_posters'
# 如果没有目录,创建目录
if not os.path.exists(folder_name):
os.makedirs(folder_name)
# 字典列表可以逐个创建文件,随后转化为一个 DataFrame
df_list = []
image_errors = {}
for title in title_list:
try:
# 这个单元格较慢,所以输出排行时计算剩余时间
ranking = title_list.index(title) + 1
print(ranking)
page = wptools.page(title, silent=True).get()
# 这里是你的代码 (三行)
images = page.data['image']
# 第一个图片通常是海报
first_image_url = images[0]['url']
r = requests.get(first_image_url)
# 下载电影海报图片
i = Image.open(BytesIO(r.content))
image_file_format = first_image_url.split('.')[-1]
i.save(folder_name + "/" + str(ranking) + "_" + title + '.' + image_file_format)
# 添加到字典列表中
df_list.append({'ranking': int(ranking),
'title': title,
'poster_url': first_image_url})
# 这不是抓住所有例外情况的最佳实践,但是适用于这一小段短小的程序脚本
except Exception as e:
print(str(ranking) + "_" + title + ": " + str(e))
image_errors[str(ranking) + "_" + title] = images
完成上面代码要求后,读取并运行下面三个单元格,解释输出结果。
for key in image_errors.keys():
print(key)
结果:
22_A_Hard_Day%27s_Night_(film)
64_Dr.Strangelove
72_Rosemary%27s_Baby(film)
83_Hell_or_High_Water_(film)
# 检查无法识别的图片,并逐个下载
for rank_title, images in image_errors.items():
if rank_title == '22_A_Hard_Day%27s_Night_(film)':
url = 'https://upload.wikimedia.org/wikipedia/en/4/47/A_Hard_Days_night_movieposter.jpg'
if rank_title == '64_Dr._Strangelove':
url = 'https://upload.wikimedia.org/wikipedia/en/e/e6/Dr._Strangelove_poster.jpg'
if rank_title == '72_Rosemary%27s_Baby_(film)':
url = 'https://upload.wikimedia.org/wikipedia/en/e/ef/Rosemarys_baby_poster.jpg'
if rank_title == '83_Hell_or_High_Water_(film)':
url = 'https://upload.wikimedia.org/wikipedia/en/8/8f/Hell_or_High_Water_film_poster.png'
title = rank_title[3:]
df_list.append({'ranking': int(title_list.index(title) + 1),
'title': title,
'poster_url': url})
r = requests.get(url)
# 下载电影海报图片
i = Image.open(BytesIO(r.content))
image_file_format = url.split('.')[-1]
i.save(folder_name + "/" + rank_title + '.' + image_file_format)
# 从字典列表中创建 DataFrame
df = pd.DataFrame(df_list, columns = ['ranking', 'title', 'poster_url'])
df = df.sort_values('ranking').reset_index(drop=True)
df
结果:
最后来一轮官方检查:
df_solution = pd.read_pickle('df_solution.pkl')
pd.testing.assert_frame_equal(df, df_solution)
然后我就得到了这么一个错误信息:
总结
本课程重点:
- try … except …异常处理简单案例
try:
# 执行代码,注意要写在缩进格式的代码块中
except Exception as e:
# 释放错误动作代码,同上,注意写在代码块区域中
- API 使用练习:
import wptools
# 获取页面信息
page = wptools.page(<your_key_word>, silent=True).get()
# 获取页面信息中的图像信息
images = page.data['image']
- JSON 结构。JSON 对象在 python 中被读取为 Dictionary 数据格式。
之前拿的 page 本身在 python 中式 wptools.page.WPToolsPage 对象,这个类型的对象不会被当成 Dictionary读取,每次要读就给我提示这个错误:
“如何将 WPToolsPage 转化为 JSON ”这一步我查了俩小时o(╥﹏╥)o
答案: page.data
没错,在 WPToolsPage 屁股后面加个 .data 然后 python 就能当做 JSON 读取了。
-
检验虽然未通过,但是我重新打印整个df自查的结果来看,获取结果至少是完整的。检验机制是用标准答案跟我的练习答案进行对比。然而标准答案失踪了╭(╯^╰)╮那我有什么办法……只好过一段时间再看下有没有更新吧。
-
存储。现在电影海报信息在df里面,不考虑共享,仅作为展示用,可以选择 flat file 方式存储。
df.to_csv('bestofrt_master.csv', index=False)