json
现在的网站服务器一般都是用json数据响应到客户端浏览器的,所以,我们发送请求后可以直接获取服务器响应回来的json数据,从而达到爬取数据的效果。
对于爬取出来的数据要进行数据提取,也就是提取出我们想要的数据。
数据分类
服务器响应回来的数据一般分为两种:
- 非结构化数据: html , 文本等 处理方法:正则表达式,xpath语法
- 结构化数据:json,xml等 处理方法:转换为python数据类型
json
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。适用于进行数据交互的场景,比如网站前台与后台之间的数据交互。
json格式
json对象
{"key":"value"}
json数组
[{"key":"val"},{"key":"val"}]
json类型与pytohn数据类型的转换
把json格式字符串转化为python字典类型很简单,所以爬虫中,如果我们能够找到返回json数据格式字符串的url,就会尽量使用这种url 如何找到返回json的url呢? 1、使用浏览器/抓包工具进行分析 wireshark(windows/linux),tcpdump(linux) 2、抓包手机app的软件
![](https://img.haomeiwen.com/i22697958/e56d1f70affc1c86.png)
json和python转换方法
1. json.loads()
把Json格式字符串解码转换成Python对象
2. json.dumps()
实现python类型转化为json字符串,返回一个str对象 把一个Python对象编码转换成Json字符串
3. json.dump()
将Python内置类型序列化为json对象后写入文件
4. json.load()
读取文件中json形式的字符串元素 转化成python类型
实例
import json
'''
dict与json的互转:
json.dumps(dict) : dict to json
json.loads(json) : json to dict
'''
dict_obj = {'name':'lizhao','age':'20'}
print(dict_obj,type(dict_obj)) #<class 'dict'> 字典
json_obj = json.dumps(dict_obj) #dict to json
print(json_obj,type(json_obj)) #<class 'str'> json字符串
dict_obj1 = json.loads(json_obj) #json to dict
print(dict_obj,type(dict_obj)) #<class 'dict'> 字典
'''
dict与json的文件操作
json.dump(dict) : 将dict转为json类型存入指定文件
json.load(文件名) : 读出json类型文件的数据,转为dict类型
'''
dictObj = {'name':'zhansan','age':'22'}
f = open('data.json','w',encoding='utf-8') #创建json类型的文件
json.dump(dictObj,f,ensure_ascii=False) #将dict转为json类型写入指定json文件
f.close()
t = open('data.json','r',encoding='utf-8')
jsonObj = json.load(t)
print(type(jsonObj),jsonObj) #<class 'dict'> {'name': 'zhansan', 'age': '22'}
data.json:
{"name": "zhansan", "age": "22"}
结果:
![](https://img.haomeiwen.com/i22697958/08c2536458607822.png)
爬取豆瓣电视信息
进入豆瓣的电影页面后。会发起多个ajax请求,每个ajax请求请求不同的内容,标签,电影信息,电视信息等。
请求电影信息的ajax请求,返回 json数据类型:
![](https://img.haomeiwen.com/i22697958/cde6ac4b809e662e.png)
爬取前50个电影信息:
代码:
import requests
import json
#请求url
xurl = 'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0'
#请求头
xheader ={
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'
}
resp = requests.get(url=xurl,headers=xheader)
resp_json_dict = resp.json()
print(resp_json_dict) #dict对象
#遍历输出
for item in resp_json_dict['subjects']:
print(item['title']+'---'+item['rate'])
#保存到文件
with open('douban.json', 'w', encoding='utf-8') as f:
# 将dict对象
json.dump(resp_json_dict['subjects'],f,ensure_ascii=False)
结果:
![](https://img.haomeiwen.com/i22697958/59db7f95a8429b61.png)
爬取都把所有的电影信息(url变换)
在上一步中我们爬取了豆瓣电影的电影信息,但是也只是爬取了第一页的50个数据,那么如果要爬取所有的数据怎么实现呢?
也就是在爬取完第一个url后,切换到下一页的url,再次发送请求,得到数据。
首先分析url:
https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0
通过观察:参数page_limit:每一页的电影数量,page_start:每页第一个的编号。
通过实验得到该网站最多有500个电影数据,也就是page_start最大值为450.
import requests
import json
import time
class Douban:
def __init__(self):
# 定义当前页码
self.start_page=0
# 定义当前请求url
self.url=f'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start={self.start_page}'
self.header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'}
def go(self):
movie_all_list = [] #定义存储所有电影的列表
for i in range(10): #循环多次发出请求
resp = requests.get(url=self.url,headers=self.header) #发送第一次请求
print(self.start_page)
# print(resp.json())
resp_list = resp.json()['subjects'] #获取每次请求的数据(直接获取列表)
# print(resp_list)
movie_all_list+=resp_list #存到总列表
time.sleep(1) #休眠一秒,防止察觉
self.start_page += 50 #修改start_page,切换到下一页电影页
#修改新的url
self.url=f'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start={self.start_page}'
#打印获取到的列表
print(movie_all_list)
print(type(movie_all_list))
print(len(movie_all_list))
#保存文件
with open('douban_all.json','w',encoding='utf-8') as f:
json.dump(movie_all_list,f,ensure_ascii=False)
if __name__ == '__main__':
douban = Douban()
douban.go()
结果:
![](https://img.haomeiwen.com/i22697958/072bf85ac8deafe0.png)
爬取电影名称以及每个电影的导演
爬取电影名称以及每个电影的导演,并保存到文件中。
代码:
import requests
import time
import re
class Movie:
def __init__(self,t,m,d):
self.title=t
self.moveurl=m
self.dor=d
def __str__(self):
return f'电影:{self.title},导演:{self.dor}'
class Douban:
def __init__(self):
# 定义当前页码
self.start_page=0
# 定义当前请求url
self.url=f'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start={self.start_page}'
self.header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36'}
# self.wfile = open('')
def download(self):
'''
在循环中发送第一次请求,休眠1秒
如果返来的数据不为空,那么获取数据,取出subjects的值
然后遍历该值,每次请求其中的url,并使用正则获取导演名
最后实例化Movie类
将movie对象转为字符串存入文件中
:return:
'''
while True:
resp=requests.get(url=self.url,headers=self.header)
time.sleep(0.5)
if resp:
pdata=resp.json()['subjects']
for it in pdata: #遍历每一个电影信息
p=requests.get(url=it['url'],headers=self.header) # 取出url在发起请求
t=re.findall('rel="v:directedBy">(.*?)</a>',p.text) #获取请求中的导演(使用正则匹配)
movie=Movie(it['title'],it['url'],t) #经三个数据实例化movie对象
print(movie)
#保存文件
with open('movie.txt','a',encoding='utf-8') as f:
f.write(str(movie))
f.write("\n")
self.start_page +=50
self.url = f'https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start={self.start_page}'
else:
break
if __name__ == '__main__':
dou=Douban()
dou.download()
结果:
![](https://img.haomeiwen.com/i22697958/bb9c71dabdfceda2.png)
这里没有加载完,因为数据量太大。
网友评论