网络采集途径之调用API获取豆瓣电影Top250
1.什么是API
2.API的作用
3.调用豆瓣API爬取电影Top250
4.解决问题
1.什么是API
API(Application Programming Interface应用程序编程接口) 是应用程序和开发人员之间的接口/通道,负责一个程序和其他软件的沟通。API本质上是一些预先定义好的函数,目的是提供应用程序以及开发人员基于某软件或硬件得以访问一组例程的能力。
例如:
- 函数是一个API。
函数已经把某些功能提前封装好,当别人要实现某些功能时,可以通过传入一些参数调用这个函数来很方便的实现这些功能。调用者并不需要知道这些函数内部具体是怎么实现的,只需要查看文档或者注释知道这个函数的入口参数/返回值/用来做什么。
对于用户来说 ,这些函数就是API,接API就是按照写函数的人规定的流程去调用这些函数。 - 银行柜台窗口是一个API。
对于一件待处理的业务,用户不需要自己去操作机器,只需要向柜台窗口按规定提交你的请求,然后柜员帮你完成业务后将结果返回给用户。相当于是用户调用了银行柜员这个API完成了功能。
2.API的作用
- 对于软件提供商来说,留出API,既能让别的应用程序来调用本软件,使软件才能发挥最大的价值,形成生态;也能不让别人看见代码,不泄露商业机密。
- 对于应用开发者来说,有了开放的API,就可以直接调用多家公司做好的功能来做自己的应用,不需要所有的事情都自己操刀,节省精力。
3.调用豆瓣API爬取电影Top250
3.1申请API Key
自己的应用使用豆瓣API之前一般需要申请API Key,豆瓣带API Key的例子为:http://api.douban.com/v2/user/1000001?apikey=XXX ,XXX为申请的API Key。
豆瓣目前已经关闭了个人API Key的申请:
不过豆瓣API说明里有一条
不需要授权公开API可以使用http,参数里面如果不包含API Key的话,限制单ip每小时150次,带的话每小时500次。
3.2 HTTP形式调用
API通常是以Http的形式提供,因此我在这里不申请API Key直接用Http。
- 豆瓣电影提供的接口:
GET /v2/movie/top250
- v2/ 表示版本
- "/"一般用来对资源层级的划分,如version2下的movie仓库下的前250部电影
- 调用API的形式:
http://api.douban.com/v2/movie/top250
- 调用列表参数:start--开始的位置,默认为0;count--一次获取的数目,默认为10。
- 请求方式:get
- 请求示例:
http://api.douban.com/v2/movie/top250?start=25&count=25
返回第26-50条信息。
第一次:尝试一次性抓取250条数据的标题
# 目标描述:
import requests
from time import sleep # 内置,使用sleep暂停,防止频率太高被封ip
url = 'http://api.douban.com/v2/movie/top250' # api接口
for start in range(0, 250, 250):
r = requests.get(url, params={'start': start, 'count': 250}) # api规定列表参数使用start和count
print ('processing %s' % r.url) # 打印当前页面url
res = r.json() # r是一个Response对象,res是一个字典,保存了响应网页的json数据
with open("D:app\\data.json",'ab') as f:
for movie in res['subjects']:
f.write(bytes(movie['title']+'\n',encoding='utf-8')) # 将电影名称写到data.json文件
sleep(0.1)
返回json的实例:
data.json
可以看到文件里只有100条数据。这是因为豆瓣设置了一次爬取的count最大为100,大于100的count会被置为100。
修改下面两行代码,设置一次只爬取50条,因此分5次爬取全部数据:
for start in range(0, 250, 50):
r = requests.get(url, params={'start': start, 'count': 50}) # api规定列表参数使用start和count
这样就能拿到250条数据了:
data.json
第二次:尝试获取电影的全部属性的数据,修改之前的代码:
import requests
from time import sleep # 内置,使用sleep暂停,防止频率太高被封ip
import json
# 写入json文件
def jsonFile(fileData):
file = open("d:app\json.json","ab")
file.write(fileData)
file.close()
url = 'http://api.douban.com/v2/movie/top250' # api接口
for start in range(0, 250, 50):
r = requests.get(url, params={'start': start, 'count': 50}) # api规定列表参数使用start和count
print ('processing %s' % r.url) # 打印当前页面url
res = r.json() # r是一个Response对象,res是一个字典,保存了响应网页的json数据
for movie in res['subjects']:
print (movie) # 将获取的json数据打印出来
# jsObj = json.dumps(movie)
# jsonFile(bytes(jsObj,encoding='utf-8')) 如何存到文件?
sleep(0.1)
查看数据,共有250条:
json.json
4.解决问题
问题1:报错 TypeError: a bytes-like object is required, not 'str'
image.png出现这个问题是因为f.write()
函数的参数类型必须是bytes
类型,而movie['title']
是str
类型。
解决办法:类型转换
f.write(bytes(movie['title']+'\n',encoding='utf-8'))
问题2:报错 TypeError: the JSON object must be str, bytes or bytearray, not 'dict'
这是在json数据解析的时候出现的错误,主要是没有搞清json.dumps()
和json.loads()
两个函数的参数类型和返回类型。
-
json.loads
take a string as input and returns a dictionary as output.(输入str,返回dict) -
json.dumps
take a dictionary as input and returns a string as output.(输入dict,返回str)
问题3:将dict对象写入json文件,但无法解析json格式
尝试了一下提取获取的response内容,然后存入json文件
res # res是dict类型
jsObj = json.dumps(res) # 转化为str类型
fileObject = open('json.json', 'ab')
fileObject.write(bytes(jsObj,encoding='utf-8'))
fileObject.close()
但是存进去之后json格式提取失败。目前已知上面这段代码是正确的,估计问题是res
数据的提取上。我之后再进行修改。