import json
import requests
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s: %(message)s'
)
INDEX_URL = 'https://spa1.scrape.center/api/movie/?limit={limit}&offset={offset}'
def scrape_api(url):
logging.info('scraping %s...',url)
try:
response = requests.get(url)
if response.status_code == 200:
return response.json()
logging.error('get invalid status code %s while scraping %s',response.status_code,url)
except requests.RequestException:
logging.error('error occurred while scraping %s',url,exc_info=True)
#爬取列表的方法
LIMIT = 10
def scrape_index(page):
url = INDEX_URL.format(limit=LIMIT,offset=LIMIT*(page-1))
return scrape_api(url)
#详情页的爬取方法
DETAIL_URL = 'https://spa1.scrape.center/api/movie/{id}'
def scrape_detail(id):
url = DETAIL_URL.format(id = id)
return scrape_api(url)
#定义总的调用方法
TOTAL_PAGE = 10
def main():
for page in range(1,TOTAL_PAGE + 1):
index_data = scrape_index(page)
with open('chen.json','w',encoding='utf-8') as f:
f.write(json.dumps(index_data))
for item in index_data.get('results'):
id = item.get('id')
detail_data = scrape_detail(id)
logging.info('detail data %s',detail_data)
if __name__=='__main__':
main()
index_data.get('results')详解:
1. 先理解 index_data 是什么
在你的代码中,index_data = scrape_index(page) 这行代码的作用是调用 scrape_index 函数爬取某一页的电影列表数据,而 scrape_index 最终会通过 scrape_api 函数返回接口的 JSON 解析结果(字典类型)。
这个接口返回的 JSON 数据结构大概是这样的(示例):
json
{
"count": 100,
"results": [
{"id": 1, "name": "肖申克的救赎", "score": "9.7"},
{"id": 2, "name": "霸王别姬", "score": "9.6"},
...
]
}
简单说:index_data 是一个包含 count(总数量)和 results(当前页电影列表)的字典。
2. index_data.get('results') 详解
这行代码是字典的 get 方法的典型应用,拆解来看:
(1)基础语法
字典.get(key, 默认值)
- 作用:从字典中获取
key对应的 value;如果key不存在,返回默认值(默认值不写则返回None)。 - 对比直接取值
字典[key]:- 直接取值:如果
key不存在,会抛出KeyError异常,导致程序崩溃; get方法:如果key不存在,返回None,程序不会崩溃,更安全。
- 直接取值:如果
(2)在你的代码中的具体作用
for item in index_data.get('results'):
- 第一步:
index_data.get('results')从index_data字典中获取results对应的 value(也就是当前页的电影列表,是一个列表); - 第二步:
for item in ...遍历这个列表,逐个取出每部电影的信息(item是一个字典,包含id、name等字段); - 第三步:通过
id = item.get('id')获取电影 ID,再调用scrape_detail(id)爬取详情页。
(3)为什么不用 index_data['results']?
假设接口返回的数据格式异常(比如没有 results 字段):
-
用
index_data['results']:会直接抛出KeyError: 'results',程序中断; -
用
index_data.get('results'):会返回None,此时for item in None会抛出TypeError,但你可以通过优化代码避免崩溃(比如加判断):results = index_data.get('results') if results: # 确保results是非空列表 for item in results: id = item.get('id') detail_data = scrape_detail(id) logging.info('detail data %s', detail_data) else: logging.warning('no results found in page %s', page)
3. 实际执行示例
假设 index_data 的数据是:
index_data = {
"count": 100,
"results": [
{"id": 1, "name": "肖申克的救赎"},
{"id": 2, "name": "霸王别姬"}
]
}
index_data.get('results')返回:[{"id": 1, "name": "肖申克的救赎"}, {"id": 2, "name": "霸王别姬"}];- 遍历后,
item依次是{"id": 1, ...}和{"id": 2, ...}; - 最终取出
id=1和id=2,分别爬取详情页。
总结
index_data.get('results')的核心是安全地从接口返回的字典中获取电影列表数据,避免因字段缺失导致程序崩溃;get方法是爬虫开发中处理接口数据的常用技巧(接口返回格式可能异常),比直接取值更健壮;- 遍历
results列表的目的是获取每部电影的id,为爬取详情页提供必要的参数。