本文共 6401 字,大约阅读时间需要 21 分钟。
温馨提示:
爬虫玩得好,监狱进得早。数据玩得溜,牢饭吃个够。
《刑法》第 285 条,非法获取计算机信息系统数据罪。 违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金;情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。
正文:
豆瓣电影排行榜,这个网站,是Ajax动态加载数据的网站,这样的网站有两个特点:【1】 右键 -> 查看网页源码中没有具体数据【2】 滚动鼠标滑轮或者其他动作时加载,或者页面局部刷新
比如:腾讯招聘、小米应用商店、京东等等都是这样的网站类型
那对于这种网站的话,我们拼接URL地址、查看URL规律、正则和xpath都是没有意义的了,那只能是F12抓包找 我们进入到豆瓣电影网站,找到排行榜点进去:我们看这个,数据显示的是数字的,这个是不是就是对应上面的什么剧情类总数、我没有看过的、可在线播放的数量啊
这个就是了,我们看到这里面有什么国家、上映时间、电影名字和主演什么的,这个就是响应的JSON数据
对于GET请求数据这么多,我们看下面的这个东西 Query String Parameters,这个就是查询参数的意思,这个查看参数就是上面URL地址 ? 后面的东西,就是给你格式化输出了下,然你好看一点
https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action=&start=0&limit=20type=11&interval_id=100%3A90&action=&start=0&limit=20
所以我们到现在的话,就可以发现一个问题了,就是页面是
那我们分析Query String Parameters里的数据规律
那我们在找一个数据包看看变化的规律,这个没变的还是没变,变了的还是那一个,这样看的话,这个start,下一次变得话就是60了,所以我们找到了规律就是:0、20、40、60…:
https://movie.douban.com/j/chart/top_list?type=11&interval_id=100%3A90&action=&start=0&limit=20
那我们复制到浏览器看一下是什么样的,这就是那个JSON数据,我们在页面中更好看点,因为我们之前安装的这个插件JSONView,如果不装这个的话,我们打开这个网址的时候可能是乱的,但是数据是对的,就是看着比较乱
这里丢个链接,就是我们安装的步骤,可以安装一下,按照我里面说的走就可以安装
html = requests.get(url=url,headers={ }).josn()
那这个html列表里面呢的字典就是我们要拿的json,我们提里面的字典,就是列表里面套了20个字典,每个字典都是这样的一个数据:
那我们要是提取字典里面的数据就得这样写代码:
for one_film in html: item = { } # 电影的排名 item['rank'] = one_film['rank']
那这是一页的,我要是想获其他也的数据怎么搞,其实之前我们呢已经分析出来了,就是那个start,这个就是控制网页页数的东西,所以我们也发现了URL地址的数据,只需要改start,就行了
接下来我们正式写代码: 导入模块import requestsimport json # 简单的话我们直接.json 但是我们最后做成全站,一定涉及到静态和动态的所以要导入json模块from fake_useragent import UserAgentimport timeimport randomimport re
定义功能函数,减少重复代码
我测试了一下,网站没有检查Cookie,所以不用定义
class DoubanSpider: def __init__(self): # json数据URL地址,type就是电影类型,start是页数,把这两个定义为{} self.url = 'https://movie.douban.com/j/chart/top_list?type={}&interval_id=100%3A90&action=&start={}&limit=20'
请求功能函数,需要多次发送请求
def get_html(self, url): headers = { 'User-Agent':UserAgent().random} # 不要写.json,因为这个数据是有动态和静态的,要是写.json的话,只能动态用,不能静态用了,而text静态和动态都可以用 html = requests.get(url=url, headers=headers).text return html
解析的功能函数,提取出数据了就要解析
def parse_html(self, url): html = self.get_html(url=url) # 动态解析数据.loads # html: [{},{},...,{}] html = json.loads(html) for one_film_dict in html: item = { } # 排名 item['rank'] = one_film_dict['rank'] # 电影名称 item['name'] = one_film_dict['title'] # 评分 item['score'] = one_film_dict['score'] # 国家 item['regions'] = onefilm_dict['regions'] # 电影类型 item['types'] = onefilm_dict['types'] # 主演 item['actors'] = onefilm_dict['actors'] print(item)
接下来我们写电影数量的代码,因为我们不能每次每次爬取页数的时候都去网页里面看看吧,这也不太合理,所以我们就定义一个变量来作为要爬取的电影数量,那先来我们去网页里看一下电影页数,就是这个:
所以接下来我们还是抓包吧,其实上面有找到完了,我们也提了一下,现在我在给他弄下来
就是这个复制URL地址,注意这个地址跟之前的地址是不一样的,因为要是一样的话就返回电影的数据了,我们放到地址栏里回车看一下
这样的话,我们也获取到了电影页数的数据了,所以我们还得用到它的这个URL地址,接着写代码:
def get_total(self, user_type): # 获取电影总数 # 把type设置为{},因为这样我们可以获取全排行站的类型 total_url = 'https://movie.douban.com/j/chart/top_list_count?type={}&interval_id=100%3A90'.format(user_type) # json格式 total_html = json.loads(self.get_html(total_url))
到现在有一个问题,我先要看各种类型的电影,比如:喜剧、恐怖、剧情等等,那我的 type 是不是要定义一下啊,就是弄一个字典存放起来:
# 比如{ '剧情':'11','喜剧':'24',...}
如果想这样的话,我们就是要获取每个电影类型的数值了,那我们只能是在这个页面获取
那我们就要发请求了,注意: 要向我们提取类型的地址发请求, https://movie.douban.com/chart
因为,别的地址只能找到一个类型,这个是所有的类型的,所以要发向这个地址发请求,再说,别的地址你发请求,要么没有,要么只有一个,那我们写正则提那个就没有意义了吧正则解析提取数据
regex = '
此时获取的type是这样的:
r_list: [('剧情','11'),('喜剧':'24'),....]
我们存的是字典,直接遍历出来存入字典:
# 定义空字典film_type_dict = { }for r in r_list: # 取出列表里的数据 film_type_dict[r[0]] = r[1]
最后我们从字典中吧所有的key提取出来,当作爬取电影类的提示,我们就直接遍历就好了;
menu = ''for key in film_type_dict: # | 分隔作用 menu += key + '|'print(menu)
最后我们拼接地址就好了:
# 获取到type的keyuser_type = film_type_dict[choice]# total: 电影总数total = self.get_total(user_type)for start in range(0, total, 20): page_url = self.url.format(user_type, start) self.parse_html(url=page_url)
最后奉上全部代码:
import requestsimport jsonfrom fake_useragent import UserAgentimport timeimport randomimport reclass DoubanSpider: def __init__(self): self.url = 'https://movie.douban.com/j/chart/top_list?type={}&interval_id=100%3A90&action=&start={}&limit=20' def get_html(self, url): """请求功能函数""" headers = { 'User-Agent':UserAgent().random} html = requests.get(url=url, headers=headers).text return html def parse_html(self, url): html = self.get_html(url=url) # html: [{},{},...,{}] html = json.loads(html) for one_film_dict in html: item = { } item['rank'] = one_film_dict['rank'] item['name'] = one_film_dict['title'] item['score'] = one_film_dict['score'] print(item) def get_total(self, user_type): """获取电影总数""" total_url = 'https://movie.douban.com/j/chart/top_list_count?type={}&interval_id=100%3A90'.format(user_type) total_html = self.get_html(total_url) total_html = json.loads(total_html) return total_html['total'] def get_film_type_dict(self): """获取所有类别的大字典""" # 获取主页响应内容 url = 'https://movie.douban.com/chart' html = self.get_html(url) # 正则解析提取数据 regex = '
转载地址:http://gmpuk.baihongyu.com/