(4条消息) python3爬虫系列07之动态网页Json 数据,爬虫要怎么搞?
python3爬虫系列07之动态 Json 数据,要怎么搞?
1.前言
经过 python爬虫实战系列 中的 python3爬虫系列06之整体架构式:根据关键词爬取百度图片 相关学习,现在我们已经会一些基本的静态html页面的爬虫了。
接下来开始一些更复杂和实战例子;
在前面我们玩了好多静态的 HTML ,想必你应该知道怎么去爬这些数据了,但还有一些常见的动态数据,比如:商品的评论数据,实时的直播弹幕,各类影片的评分等等…
这些数据是会经常发生改变的,因此很多网站就会用到 Json 来传输这些数据
那么遇到 Json 我们应该怎么办呢?
首先要知道python怎么在json格式中获取到想要的数据:
python 的 json 模块有两个主要的函数:
将 python 对象转化为 json格式: json.dumps()
将json数据转化为python对象: json.loads()
具体使用操作可以参考:
python对json对象或json数组操作以及读写各类txt,csv,html,xls文件的工具类
2.动态网页requests+json爬虫:根据输入词爬取豆瓣热门影片
好了,不吹牛皮了,说半天不如实战。
环境:
- Python版本 :3.6
- 爬取网页模块:requests
- 分析网页模块:json
- 保存CSV文件
要知道 动态网页指的是网页的内容通过js动态加载出来的数据。那么分析一顿是免不了的啦。
2.1 网页分析
本次爬虫的目标是豆瓣电影和电视剧页面:
URL如下:
https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0
一打开这个页面我们可以看到,其下方有一个【加载更多】。。
这就是动态加载的,所以我们无法直接通过get方法获取网页内容。
所以,当我们点击加载更多时,可以通过开发者工具(浏览器里面按F12打开) Network选项中的XHR 来获取动态加载的js。
查看请求,然后haders里面有个url:
打开获取到的连接:
https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0
可以看到返回的是json数据:
观察可以发现,不同页的连接的规律,是page_limit 和 page_start,两个参数。也就是说,我们可以通过控制这两个参数来动态变化页面的内容,比如翻页。
这里我们就可以尝试构造一个连接,让它从第一个电影开始,并显示200个:
https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=200&page_start=0
打开验证就知道了,
电影的:
电视剧的也一样:
https://movie.douban.com/j/search_subjects?type=tv&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0
然后随便复制一下这个页面里面的一段json数据。
打开浏览器,在线解析一下这个json:
(你随便百度一下json在线解析就可以了)
通过这个json,我们假设需要的数据内容是:
- 评分rate
- 电影名称title
- 电影的豆瓣链接url
- 封面图片的地址cover
OK,分析完毕,就开始整代码了。
2.2 撸码环节
因为动态页面中,我们看到请求返回的是json数据,而且有了对应的URL地址,所以就不需要再使用什么beautifulsoup 解析器了。
直接将响应的json字符串,转为python的字典对象操作就好了。
热门电影的爬虫:
rowCount 是对应的条数。
# 热门电影
def douban_movie(rowCount):
url='https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit='+rowCount+'&page_start=0'
# 解决出现403拒绝访问
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/51.0.2704.63 Safari/537.36'}
# 使用request模块打开并获取网页内容
response = requests.get(url,headers = headers,verify=False,timeout=30)
print(response.text) # 报错:json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
# 解决:以后在使用json时,最好先输出一下参数,检查一下是否符合格式?
content = response.content
# json格式转为字典
result = json.loads(content)
print(content,result)
# 获取相关信息并存入列表的字典中
movie_list = []
mos = result['subjects']
for i in range (0,len(mos)):
mo = {}
mo['rate']=mos[i]['rate']
mo['cover']=mos[i]['cover']
mo['url']=mos[i]['url']
mo['title']=mos[i]['title']
movie_list.append(mo) # 列表存放字典
return movie_list
热门电视剧的爬虫:
rowCount 是对应的条数。
# 热门电视剧
def douban_tv(rowCount):
url='https://movie.douban.com/j/search_subjects?type=tv&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit='+rowCount+'&page_start=0'
print(url)
# 解决出现403拒绝访问
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/51.0.2704.63 Safari/537.36'}
# 使用request模块打开并获取网页内容
response = requests.get(url, headers=headers, verify=False, timeout=30) # 禁止重定向
content = response.text
print(content)
# 返回的是json,那么就直接解码转为字典。不需要解析器bs了
result = json.loads(content)
tvs = result['subjects']
tv_list = [] # 创建一个列表
for i in range (0,len(tvs)):
tv={} # 创建一个字典
tv['rate']=tvs[i]['rate'] # 评分
tv['title']=tvs[i]['title'] # 电影名称
tv['cover'] = tvs[i]['cover'] # 封面图片的地址
tv['url'] = tvs[i]['url'] # 电影的豆瓣链接
tv_list.append(tv) # 列表存放字典
return tv_list
其实是差不多的,甚至可以简化到一个函数去共用。
然后就是保存一下爬取的数据:
# 保存为csv文件
def output_csv(datalist):
print(type(datalist),len(datalist)) # <class 'list'> 100
import csv
# 准备好存储的csv文件
csv_file = open("douban_data.csv", 'w', newline='', encoding='utf-8-sig') # 解决中文乱码问题
writer = csv.writer(csv_file)
writer.writerow(['评分', '作品名称', '豆瓣链接','封面图片'])
for data in datalist:
writer.writerow([data['rate'], data['title'],data['url'],data['cover']])
csv_file.close()
最后呢调用传参:
if __name__=="__main__":
category = input('请输入爬取的类别代号(电视剧:0,电影:1):')
rowCount = input('请输入爬取的条数:')
if category=='0':
print('爬取电视剧中,请稍后...')
result = douban_tv(rowCount)
elif category=='1':
print('爬取电影中,请稍后...')
result = douban_movie(rowCount)
else:
print('输入错误,暂不支持,请重试...')
# 持久化保存
# for i in result:
# print(i)
output_csv(result)
print("爬虫完毕,文件已生成。快去查看吧")
整个源码:
#!/usr/bin/python3
#@Readme : 豆瓣热门电影/电视剧-不需登录的动态网页爬虫-ajax加载的
# 目标: https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0
# 返回的是json数据,那么就不需要解析器了。直接转字典就好了。
import requests
import json
# 热门电视剧
def douban_tv(rowCount):
url='https://movie.douban.com/j/search_subjects?type=tv&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit='+rowCount+'&page_start=0'
print(url)
# 解决出现403拒绝访问
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/51.0.2704.63 Safari/537.36'}
# 使用request模块打开并获取网页内容
response = requests.get(url, headers=headers, verify=False, timeout=30) # 禁止重定向
content = response.text
print(content)
# 返回的是json,那么就直接解码转为字典。不需要解析器bs了
result = json.loads(content)
tvs = result['subjects']
tv_list = [] # 创建一个列表
for i in range (0,len(tvs)):
tv={} # 创建一个字典
tv['rate']=tvs[i]['rate'] # 评分
tv['title']=tvs[i]['title'] # 电影名称
tv['cover'] = tvs[i]['cover'] # 封面图片的地址
tv['url'] = tvs[i]['url'] # 电影的豆瓣链接
tv_list.append(tv) # 列表存放字典
return tv_list
# 热门电影
def douban_movie(rowCount):
url='https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit='+rowCount+'&page_start=0'
# 解决出现403拒绝访问
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/51.0.2704.63 Safari/537.36'}
# 使用request模块打开并获取网页内容
response = requests.get(url,headers = headers,verify=False,timeout=30)
print(response.text) # 报错:json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
# 解决:以后在使用json时,最好先输出一下参数,检查一下是否符合格式?
content = response.content
# json格式转为字典
result = json.loads(content)
print(content,result)
# 获取相关信息并存入列表的字典中
movie_list = []
mos = result['subjects']
for i in range (0,len(mos)):
mo = {}
mo['rate']=mos[i]['rate']
mo['cover']=mos[i]['cover']
mo['url']=mos[i]['url']
mo['title']=mos[i]['title']
movie_list.append(mo) # 列表存放字典
return movie_list
# 保存为csv文件
def output_csv(datalist):
print(type(datalist),len(datalist)) # <class 'list'> 100
import csv
# 准备好存储的csv文件
csv_file = open("douban_data.csv", 'w', newline='', encoding='utf-8-sig') # 解决中文乱码问题
writer = csv.writer(csv_file)
writer.writerow(['评分', '作品名称', '豆瓣链接','封面图片'])
for data in datalist:
writer.writerow([data['rate'], data['title'],data['url'],data['cover']])
csv_file.close()
if __name__=="__main__":
category = input('请输入爬取的类别代号(电视剧:0,电影:1):')
rowCount = input('请输入爬取的条数:')
if category=='0':
print('爬取电视剧中,请稍后...')
result = douban_tv(rowCount)
elif category=='1':
print('爬取电影中,请稍后...')
result = douban_movie(rowCount)
else:
print('输入错误,暂不支持,请重试...')
# 持久化保存
# for i in result:
# print(i)
output_csv(result)
print("爬虫完毕,文件已生成。快去查看吧")
运行一下,爬取结果:
电视剧
电影
…东西是动态的,如果你想抓其他的类型,比如综艺啊,纪录片啊什么的,就是多加一个方法即可。
代码对应的介绍已经写在了注释中,不明白可以评论留言。