目标
- 理解json的概念
- 了解爬虫中json出现的位置
- 掌握json相关的方法
1. json可用于结构化数据的提取
由于把json数据转化为培养他虹内建数据类型很简单,所以爬虫中,如果我们能找到返回json数据的url,就会尽量使用这种url,而很多地方也都会返回json
2. 什么时json
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。适用于进行数据交互的场景,比如网站前台与后台之间的数据交互。
3. 哪里能找到返回的json的url
以豆瓣热映电影信息为例,寻找返回json的url地址。
这个例子中,电脑版热映信息存在html中,手机版存在json中。
3.1 如何确定数据在哪里
在url地址对应的响应中搜索关键词即可,搜索发现电脑版是存在html中的
注意:url地址对应的响应中,中文往往是被编码之后的内容,所以更推荐大家去搜索英文和数字;另外一个方法就是在perview
中搜索,其中的内容都是转码之后的。
3.2 切换手机版寻找json地址
我们通过抓包找到手机版json地址后,打开地址发现响应中包含的数据并不是我们想要的,为什么呢?
对比抓包的地址和现在地址的请求headers ,就发现是Referer
字段缺少的原因。
在上面这个地址中,我们发现响应中包含部分数据并不是我们想要的,如下:
;jsonp1({'count': 18, 'subject_collection'..."})
其中jsonp1
似乎很眼熟,在请求地址中包含一个参数callback=jsonp1
,正式因为这个参数的存在,才导致结果中有这部分数据,对应的解决办法是:直接删除callback=jsonp1
字段即可。在url地址中很多字段都是没用的,可大胆尝试。
4. json模块中的方法
json模块提供了四个功能:dumps、dump、loads、load,用于字符串 和 python数据类型间进行转换。
4.1 json.loads()
把Json格式字符串转换成Python数据类型
import json
json_str = '{"city": "北京", "name": "大猫"}'
print(type(json_str)) # <class 'str'>
ret = json.loads(json_str)
print(type(ret)) # <class 'dict'>
print(ret) # {'city': '北京', 'name': '大猫'}
4.2 json.dumps()
把python数据类型转化为json格式字符串
import json
import chardet
tupleStr = (1, 2, 3, 4)
dictStr = {"city": "北京", "name": "大猫"}
json.dumps(tupleStr)
# '[1, 2, 3, 4]'
# 注意:json.dumps() 处理中文时默认使用的ascii编码,会导致中文无法正常显示
ret = json.dumps(dictStr)
# {"city": "\u5317\u4eac", "name": "\u5927\u732b"}
# 记住:处理中文时,添加参数 ensure_ascii=False 来禁用ascii编码
ret1 = json.dumps(dictStr, ensure_ascii=False)
# {"city": "北京", "name": "大刘"}
4.3 其他两个方法不需要掌握
5. 爬取豆瓣热映电影信息
import requests
import json
from pprint import pprint
url = "https://m.douban.com/rexxar/api/v2/subject_collection/movie_showing/items?os=ios&for_mobile=1&start=0&count=18&loc_id=108288&_=0"
headers = {
"Referer": "https://m.douban.com/movie/nowintheater?loc_id=108288",
"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"
}
response = requests.get(url, headers=headers)
json_str = response.content.decode()
# json.loads # json字符串转化为python类型
ret = json.loads(json_str)
print(ret) # 美化打印数据类型 类似于检查中的Preview
print(type(ret))
# json.dumps # python类型转化为json字符串
with open("a.txt", "w", encoding="utf-8") as f: # "w"只能写入字符串
# ensure_ascii=False 来禁用ascii编码,输出中文; indent=2 折叠换行效果 格式化输出每下一级缩进2
f.write(json.dumps(ret, ensure_ascii=False, indent=2)) # 这里不推荐使用str()强制转换
6 爬取36ke首页新闻
import requests
# from parse import parse_url
import re
import json
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
}
url = "https://36kr.com/"
response = requests.get(url, headers=headers)
html_str = response.content.decode()
print(html_str)
ret = re.findall(r"<script>window.initialState=(.*?)</script>", html_str) # 不懂这里为何用findall
print(ret)
with open("36ke.json", "w", encoding="utf-8") as f:
f.write(json.dumps(ret, ensure_ascii=False))