爬虫第二式:猫眼电影前100排行榜

hello hello,小伙伴们你们好,今天我就正式进入爬虫稍微高级一点的阶段了,哈哈哈哈上一篇才是入门了,本章就进阶了,所以没学好入门的小伙伴们先去我的上一篇文章看懂看明白啊,丢个小链接:

温馨提示:
    

好的,接下来我们继续进阶之路   爬虫第二式   
大家看到了,本篇的标题是爬取猫眼电影前100排行榜,在这之前我想了想,我觉得有必要温习一下上一篇的技术,所以,我们先来做个案例,把上一篇的技术点都组合起来用一下,再开始我们相当相当相当正规的猫眼电影前100排行榜,如果不想看就直接翻到下面,直接看本章的正式内容吧~~

  • 百度贴吧数据抓取
需求:
	1、输入贴吧名称: 张一山吧
	2、输入起始页: 1
	3、输入终止页: 2
	4、保存到本地文件:张一山吧_第1.html、张一山吧_第2.html
实现总步骤:
	【1】查看所抓数据在响应内容中是否存在
    右键 - 查看网页源码 - 搜索关键字
    
	【2】查找并分析URL地址规律
	    第1: http://tieba.baidu.com/f?kw=???&pn=02: http://tieba.baidu.com/f?kw=???&pn=50
	    第n页: pn=(n-1)*503】发请求获取响应内容
	
	【4】保存到本地文件

第一步:

在这里插入图片描述
我们看途中有个这样的字样:哪位大神帮忙找找呀
我们直接进鼠标右键单击查看查看网页源码
在这里插入图片描述
我们 Ctrl+f 搜索字样,看到是有的,那就可以,为什么这样做呢?
额。。。。。好像上一篇没有说。。。。。在这里说下吧,因为有些网站的内容是动态加载出来的,不是直接响应出来的,这也是一种反爬机制,后面我们会讲怎么突破这样的,但是记住了,以后在爬去页面的时候

先检查源代码中是否有关键字这样的内容,如果有就是普通网站,没有就是反爬比较好的,这一点很重要,千万千万千万记住了!!!

第二步

  • 查找并分析URL地址规律
    在这里插入图片描述
    我们看这个:http://tieba.baidu.com/f?kw=张一山&pn=0
    我们看这个kw= 这个是哪个人的贴吧,这个必须有,然后规律呢,就是这个pn=0,这个是第一页,我们在点击下一页看:http://tieba.baidu.com/f?kw=张一山&pn=50
    在这里插入图片描述
    以此类推,我们就知道了,这个url地址的每个页数是:**0、 50、 100…等等,对应着第一、第二、第三页…**等等吧,我们发现了规律,就知道了URL地址怎么搞了
    以后的以后,我们就这样获取URL地址规律,哎呀我这多年的积累就这样毫无保留的奉献了出来,不看这个案例的真是亏了,太亏了哎

接着,也就是我们上面看到的,获取到了规律就像这样,对把:

1: http://tieba.baidu.com/f?kw=???&pn=02: http://tieba.baidu.com/f?kw=???&pn=50
    第n页: pn=(n-1)*50

第三步

  • 发请求获取响应内容
html = requests.get(url=url, headers=self.headers).content.decode('utf-8')

就是我们之前说过的,requests请求、和字符串拼接、还要掩藏请求头,不能让网站知道我们是爬虫等等吧,就下来我们分析完了就开始写代码吧

# 导入各种库
import requests #导入requests库,发送请求用
from urllib import parse  # urllib,这个是给URL地址中查询参数进行编码
import time  # 时间模块
import random  # 随机数模块

time、random模块的导入,我们下面再说
我们接着,用函数的方法,定义各个模块吧,不会函数的小朋友我没办法了,我没写过Python函数的文章,可以去看看别的

class TiebaSpider:
    def __init__(self):
        """定义常用变量"""
        self.url = 'http://tieba.baidu.com/f?kw={}&pn={}'
        self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}

我们定义一个类实例化常用变量,因为经常要用到嘛,所有定义类和函数就比较方便
就是这样,把要爬取的URL地址放上去,变量要用大括号代替,下面我们会给到参数,然后要掩盖你的请求头,作用就不多说了

接着我们定义请求功能函数

def get_html(self, url):
        """请求功能函数"""
        html = requests.get(url=url, headers=self.headers).content.decode('utf-8')

        return html

用到上面我们实例化的URL地址和请求头了,直接return出去
接着我们定义数据处理函数

    def save_html(self, filename, html):
        """数据处理函数"""
        with open(filename, 'w') as f:
            f.write(html)

获取到的内容我们保存下来,直接写入到文件里面,保存到本地
在接下来就是程序入口函数

def run(self):
        """程序入口函数"""
        name = input('请输入贴吧名:')
        start = int(input('请输入起始页:'))
        end = int(input('请输入终止页:'))
        # 编码
        params = parse.quote(name)
        # 拼接多页的URL地址
        for page in range(start, end + 1):
            pn = (page - 1) * 50
            page_url = self.url.format(params, pn)
            # 请求 + 解析 + 数据处理
            html = self.get_html(url=page_url)
            filename = '{}_第{}页.html'.format(name, page)
            self.save_html(filename, html)
            # 终端提示
            print('第%d页抓取完成' % page)
            # 控制数据抓取的频率
            time.sleep(random.randint(1, 2))

最后直接main一下:

if __name__ == '__main__':
    spider = TiebaSpider()
    spider.run()

最后奉上完整代码:

"""
    1、输入贴吧名称: 赵丽颖吧
    2、输入起始页: 1
    3、输入终止页: 2
    4、保存到本地文件:赵丽颖吧_第1页.html、赵丽颖吧_第2页.html
"""
import requests
from urllib import parse
import time
import random

class TiebaSpider:
    def __init__(self):
        """定义常用变量"""
        self.url = 'http://tieba.baidu.com/f?kw={}&pn={}'
        self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}

    def get_html(self, url):
        """请求功能函数"""
        html = requests.get(url=url, headers=self.headers).content.decode('utf-8')

        return html

    def parse_html(self):
        """解析功能函数"""
        pass

    def save_html(self, filename, html):
        """数据处理函数"""
        with open(filename, 'w') as f:
            f.write(html)

    def run(self):
        """程序入口函数"""
        name = input('请输入贴吧名:')
        start = int(input('请输入起始页:'))
        end = int(input('请输入终止页:'))
        # 编码
        params = parse.quote(name)
        # 拼接多页的URL地址
        for page in range(start, end + 1):
            pn = (page - 1) * 50
            page_url = self.url.format(params, pn)
            # 请求 + 解析 + 数据处理
            html = self.get_html(url=page_url)
            filename = '{}_第{}页.html'.format(name, page)
            self.save_html(filename, html)
            # 终端提示
            print('第%d页抓取完成' % page)
            # 控制数据抓取的频率
            time.sleep(random.randint(1, 2))

if __name__ == '__main__':
    spider = TiebaSpider()
    spider.run()

在这里插入图片描述
现在可以看到文件夹里有两个名字为张一山.html的网页了,可以打开看一下,但是还是像我们上一篇说的,可能显示不全的,这里我就不打开了

这个time、random模块导入的原因就是控制抓取量,因为有时候抓取太快了也会被认为是爬虫程序,所以我们随机生成时间段抓取

最后:终于到了我们的猫眼排行前100阶段了

首先我们介绍正则模块:

  • re模块使用流程
# 方法一 
	r_list=re.findall('正则表达式',html,re.S)
	
	# 方法二
	pattern = re.compile('正则表达式',re.S)
	r_list = pattern.findall(html)

首先了解正则,以及正则表达式元字符,请自行了解吧,我们就在这里介绍一下这两个东西

贪婪匹配和非贪婪匹配

  • 贪婪匹配(默认)
	1、在整个表达式匹配成功的前提下,尽可能多的匹配 * + ?
	2、表示方式:.* .+ .?
  • 非贪婪匹配
	1、在整个表达式匹配成功的前提下,尽可能少的匹配 * + ?
	2、表示方式:.*? .+? .??
  • 正则表达式分组作用
	在完整的模式中定义子模式,将每个圆括号中子模式匹配出来的结果提取出来

那我们看一下对于分组必须要知道的事情:

	1、在网页中,想要什么内容,就加()
	2、先按整体正则匹配,然后再提取分组()中的内容
	   如果有2个及以上分组(),则结果中以元组形式显示 [(),(),()]
	3、最终结果有3种情况
	   情况1[]
	   情况2['', '', '']  -- 正则中1个分组时
	   情况3[(), (), ()]  -- 正则中多个分组时

来个案例:

# 从如下html代码结构中完成如下内容信息的提取:
问题1[('Tiger',' Two...'),('Rabbit','Small..')]
问题2 :
	动物名称 :Tiger
	动物描述 :Two tigers two tigers run fast
    **********************************************
	动物名称 :Rabbit
	动物描述 :Small white rabbit white and white



页面的结构如下:
	<div class="animal">
	    <p class="name">
				<a title="Tiger"></a>
	    </p>
	    <p class="content">
				Two tigers two tigers run fast
	    </p>
	</div>
	
	<div class="animal">
	    <p class="name">
				<a title="Rabbit"></a>
	    </p>
	
	    <p class="content">
				Small white rabbit white and white
	    </p>
	</div>
  • 练习答案
import re

html = '''<div class="animal">
    <p class="name">
        <a title="Tiger"></a>
    </p>

    <p class="content">
        Two tigers two tigers run fast
    </p>
</div>

<div class="animal">
    <p class="name">
        <a title="Rabbit"></a>
    </p>

    <p class="content">
        Small white rabbit white and white
    </p>
</div>'''

# 这个就是把没用的删掉,留着必要的,还不能全删了,数据提取哪里就加(.*?),其他无关紧要的要是删的话,就删完了,加上.*?,但是要保留内容的标签,也就是这样的:class="animal"、title=""等等吧
p = re.compile('<div class="animal">.*?title="(.*?)".*?content">(.*?)</p>.*?</div>',re.S)
r_list = p.findall(html)

for rt in r_list:
    print('动物名称:',rt[0].strip())
    print('动物描述:',rt[1].strip())
    print('*' * 50)

在这里插入图片描述
这样就可以提取到了,好了,正则已学完,对于我们的爬虫技术,真的是如虎添翼
接下来就是猫眼电影爬取:

  • 爬虫需求
1】确定URL地址
    百度搜索 - 猫眼电影 - 榜单 - top100榜

【2】 爬取目标
    所有电影的 电影名称、主演、上映时间
   
【3】注意 - 程序写完之后未出数据解决思路
	1print(r_list) 发现是空列表
    2print(html) 确认响应内容是否正确(搜索关键字来确定)
    3、响应内容不对,跳转到了验证中心
    4、F12抓包,找到对应的Cookie和User-Agent,放到程序中的headers参数中再做尝试
    5、发现数据抓取成功

在这里插入图片描述
点到这里就可以了
第一步

  • 查看网页源码,确认数据来源
    响应内容中存在所需抓取数据 - 电影名称、主演、上映时间
    在这里插入图片描述
    可以看到是有的,不是动态加载的
    第二步
  • 翻页寻找URL地址规律
1页:https://maoyan.com/board/4?offset=02页:https://maoyan.com/board/4?offset=10

我们查到了URL地址规律,是0、 10、 20、 30… ,对应着 1、 2、 3、 4…
我们得到的结论就是

	第n页:offset=(n-1)*10

第三步

  • 编写正则表达式
    这里我给出来了,但是我这个正则表达式,今天可以用,可能明天就不能用了,应为这个得根据它怎么html页面改变而改变
<div class="movie-item-info">.*?title="(.*?)".*?class="star">(.*?)</p>.*?releasetime">(.*?)</p>

有想自己尝试编写的我也给出了源代码:

<div class="movie-item-info">
        <p class="name"><a href="/films/1200486" title="我不是药神" data-act="boarditem-click" data-val="{movieId:1200486}">我不是药神</a></p>
        <p class="star">
                主演:徐峥,周一围,王传君
        </p>
<p class="releasetime">上映时间:2018-07-05</p>    </div>
    <div class="movie-item-number score-num">
<p class="score"><i class="integer">9.</i><i class="fraction">6</i></p>        
    </div>

      </div>

可以自己尝试一下改改,这个html码就是所有电影的框架,一般来说不会有另类的改变,也就是说,写一次正则表达式,就是所有的可以用的就是这个:
在这里插入图片描述
就以这三个为例子吧,他们的正则表达式都是一样的,至少现在是一样的,以后改不改不敢说,所以,就写出一个电影的表达式,所有的100个电影都可用

第四步
开干吧兄弟,奥利给!!!

import requests
import re
import time
import random

class MaoyanSpider:
    def __init__(self):
        self.url = 'https://maoyan.com/board/4?offset={}'
        self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}

这一段就是导入模块和定义类和实例化对象,就是以后经常用的,封装起来

def get_html(self, url):
        html = requests.get(url=url, headers=self.headers).content.decode('utf-8')
        # 直接调用解析函数
        self.parse_html(html)

请求响应地址,这个’utf-8’,要看他的编码格式是什么就填什么,因为要是不填的话,可能爬取出来的数据,编码格式是乱码,切记切记!

def parse_html(self, html):
        regex = '<div class="movie-item-info">.*?title="(.*?)".*?class="star">(.*?)</p>.*?releasetime">(.*?)</p>'
        pattern = re.compile(regex, re.S)
        r_list = pattern.findall(html)
        # 直接调用数据处理函数
        self.save_html(r_list)

这就是我们的正则表达式调用

def save_html(self, r_list):
        for r in r_list:
            item = {}
            item['name'] = r[0].strip()
            item['star'] = r[1].strip()
            item['time'] = r[2].strip()
            print(item)

这个是抓取的东西就是上面说的电影名称、主演、上映时间,给他用字典整起来,还要按顺序取对应的数据,就是他爬出来的是一个列表,电影名称我们就要取第一个,主演取第二个,上映时间取第三个,还要去掉前后的空格和换行加上strip()函数

    def run(self):
        for offset in range(0, 91, 10):
            page_url = self.url.format(offset)
            self.get_html(url=page_url)
            # 控制频率
            time.sleep(random.randint(1, 3))

再run一下,最后调用main():

if __name__ == '__main__':
    spider = MaoyanSpider()
    spider.run()

ok,大功告成,直接运行:
在这里插入图片描述
奉上全部代码:

import requests
import re
import time
import random

class MaoyanSpider:
    def __init__(self):
        self.url = 'https://maoyan.com/board/4?offset={}'
        self.headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.163 Safari/535.1'}

    def get_html(self, url):
        html = requests.get(url=url, headers=self.headers).content.decode('utf-8')
        # 直接调用解析函数
        self.parse_html(html)

    def parse_html(self, html):
        regex = '<div class="movie-item-info">.*?title="(.*?)".*?class="star">(.*?)</p>.*?releasetime">(.*?)</p>'
        pattern = re.compile(regex, re.S)
        r_list = pattern.findall(html)
        # 直接调用数据处理函数
        self.save_html(r_list)

    def save_html(self, r_list):
        for r in r_list:
            item = {}
            item['name'] = r[0].strip()
            item['star'] = r[1].strip()
            item['time'] = r[2].strip()
            print(item)

    def run(self):
        for offset in range(0, 91, 10):
            page_url = self.url.format(offset)
            self.get_html(url=page_url)
            # 控制频率
            time.sleep(random.randint(1, 3))

if __name__ == '__main__':
    spider = MaoyanSpider()
    spider.run()
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨旭华 

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值