爬虫实战1.3.5 页面解析-抓取猫眼电影排行(Xpath解析)

之前我们介绍了几种爬虫常见的页面解析方式,今天我们就来看一下这些方式在实际情况下的用法,以后在抓取数据的时候可以选择合适自己的那种。

本文我们用“ 提取猫眼电影TOP100的电影名称、时间、评分、图片等信息“ 为例

1. 准备工作

首先准备环境,再次说一下我的环境:win7、Anconda3
本次需要的包是:requests、lxml、bs4

2. 请求页面

现在开始正式请求页面,获取页面信息:
页面地址:猫眼电影排行
看下图,我们需要的信息均可在这里提取出来:

页面信息

将页面拖到最下面,可以看到翻页信息,这块我们之后再看。
下面开始撸码。

3. 代码

1.发送请求, 获取页面信息,顺便带上代码结构,下面只写相关的方法了:

import re
import requests
from lxml import etree
from bs4 import BeautifulSoup

class TopMovieSpider(object):
    def __init__(self):
        self._start_url = "https://maoyan.com/board/4"
        self._headers = {
            'Connection': 'keep-alive',
            'X-Requested-With': 'XMLHttpRequest',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36',
        }

    def get_response(self):
        response = requests.get(self._start_url, headers=self._headers)
        if response.status_code == 200:
            return response.content.decode('utf-8')
        return None

    def run(self):
        # 1.发出请求,获取页面信息
        req_result = self.get_response()
        print(req_result)

if __name__ == '__main__':
    tm_spider = TopMovieSpider()
    tm_spider.run()

看下我们所需要的信息在哪:


页面信息

注意:在这个地方提醒一下,我们在google中查看页面信息的时候,不要去看Elements下的页面信息,要去Network下找到相应的请求看Response返回的,下面会举例说明。

2. Xpath获取信息

因为作者比较习惯使用Xpath,所以首先使用Xpath详解信息获取的整个过程:
通过页面源码我们可以看到电影排行信息在classboard-wrapperdl标签中,在dl标签下有若干dd标签,每个dd标签下包含了一部电影的信息,每个dd标签下的结构都是相同的:
在这里我们做个对比:Element下的页面跟Network
下相应请求的Response返回的页面信息:可以发现两者在一些信息都有不同,如果以Element为准提取的话,会获取不到你所需要的信息,大家可以尝试一下。

Element下的页面的名称跟图片

Response返回的页面中名称跟图片

dd标签下共有三个标签,在这可以很明显的看到a标签的title属性就是电影的名称,展开a标签就能发现,下面的img标签就是电影的图片,a标签上面有个i标签,里面的内容是排名,所以我们可以这样写:

    def xpath_parse(self, req_result):
        """
        Xpath解析页面
        :param req_result:
        :return:
        """
        html = etree.HTML(req_result)
        # 排名
        movie_index_list = html.xpath('//i[contains(@class, "board-index")]/text()')

        # 电影名称: 我们可以根据 a 标签的class来确定,同样获取 a 标签中的 title 属性,就为电影名称
        movie_name = html.xpath('//a[@class="image-link"]/@title')
        print(movie_name)

        # 电影图片: 我们这里不难发现,a 标签中的第二个 img 标签的 data-src 属性就是图片的地址, 可以用该图片的 class 属性来确定
        movie_picture = html.xpath('//img[@class="board-img"]/@data-src')
        print(movie_picture)

看下输出结果:

['霸王别姬', '肖申克的救赎', '罗马假日', '这个杀手不太冷', '泰坦尼克号', '唐伯虎点秋香', '乱世佳人', '魂断蓝桥', '辛德勒的名单', '天空之城']
['https://p0.meituan.net/movie/ce4da3e03e655b5b88ed31b5cd7896cf62472.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/283292171619cdfd5b240c8fd093f1eb255670.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/289f98ceaa8a0ae737d3dc01cd05ab052213631.jpg@160w_220h_1e_1c', 'https://p1.meituan.net/movie/6bea9af4524dfbd0b668eaa7e187c3df767253.jpg@160w_220h_1e_1c', 'https://p1.meituan.net/movie/b607fba7513e7f15eab170aac1e1400d878112.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/da64660f82b98cdc1b8a3804e69609e041108.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/223c3e186db3ab4ea3bb14508c709400427933.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/58782fa5439c25d764713f711ebecd1e201941.jpg@160w_220h_1e_1c', 'https://p0.meituan.net/movie/b0d986a8bf89278afbb19f6abaef70f31206570.jpg@160w_220h_1e_1c', 'https://p1.meituan.net/movie/ba1ed511668402605ed369350ab779d6319397.jpg@160w_220h_1e_1c']

下一步我们再看一下剩余的信息:主演、上映时间跟评分


剩余信息

跟名称一样的分析方式,这里就不过多赘述,看代码:

        # 电影主演: 我们可以根据 class 为 star 的 p 标签来确定,提取出来后做个简单的整理:去除空格
        movie_star_list = html.xpath('//p[@class="star"]/text()')
        movie_star_list = [movie_star.strip() for movie_star in movie_star_list]
        print(movie_star_list)

        # 上映时间:我们可以根据 class 为 releasetime 的 p 标签来确定, 有些还带着上映地区
        show_time_list = html.xpath('//p[@class="releasetime"]/text()')
        print(show_time_list)

        # 电影评分:评分在页面上是有两部分组成的:小数,整数; 整数部分可以通过 class 为 integer 的 i 标签确定, 小数部分可以通过class为fraction的i标签确定,提取出来后做个简单的整理:相加
        movie_grade_integer_list = html.xpath('//i[@class="integer"]/text()')
        movie_grade_decimals_list = html.xpath('//i[@class="fraction"]/text()')
        movie_grade_list = [movie_grade_integer_list[i] + movie_grade_decimals_list[i] for i in range(len(movie_grade_integer_list))]
        print(movie_grade_list)

看下输出结果:

['主演:张国荣,张丰毅,巩俐', '主演:蒂姆·罗宾斯,摩根·弗里曼,鲍勃·冈顿', '主演:格利高里·派克,奥黛丽·赫本,埃迪·艾伯特', '主演:让·雷诺,加里·奥德曼,娜塔莉·波特曼', '主演:莱昂纳多·迪卡普里奥,凯特·温丝莱特,比利·赞恩', '主演:周星驰,巩俐,郑佩佩', '主演:费雯·丽,克拉克·盖博,奥利维娅·德哈维兰', '主演:费雯·丽,罗伯特·泰勒,露塞尔·沃特森', '主演:连姆·尼森,拉尔夫·费因斯,本·金斯利', '主演:寺田农,鹫尾真知子,龟山助清']
['上映时间:1993-07-26', '上映时间:1994-09-10(加拿大)', '上映时间:1953-09-02(美国)', '上映时间:1994-09-14(法国)', '上映时间:1998-04-03', '上映时间:1993-07-01(中国香港)', '上映时间:1939-12-15(美国)', '上映时间:1940-05-17(美国)', '上映时间:1993-12-15(美国)', '上映时间:1992-05-01']
['9.5', '9.5', '9.1', '9.5', '9.5', '9.1', '9.1', '9.2', '9.2', '9.0']

到这里,我们第一页所有的上榜电影都已经获取到了,接下来我们来提取剩余的电影信息:
首先分析页面地址,从图中看到我们只能拿到一部分页面地址,中间位置的地址都被隐藏了,所以我们只能走别的路了,根据可见的地址,我们可以找到对应的规律:


分页地址信息

我们从这很容易就能看出他的规律:第n页,offset的值是10 * (n -1),总共就10页,我们可以加个循环:

    for i in range(10):
        print('=' * 30 + f'第{i + 1}页')
        movie_info_list = tm_spider.run(i * 10)
        for movie_info in movie_info_list:
            print(movie_info)
        # 加个强制睡眠,以防反爬
        time.sleep(10)

下面贴上完整代码,如有可以优化的地方欢迎大家指导:

import re
import requests
from lxml import etree
from bs4 import BeautifulSoup
import time

class TopMovieSpider(object):
    def __init__(self):
        self._start_url = "https://maoyan.com/board/4"
        self._headers = {
            'Connection': 'keep-alive',
            'X-Requested-With': 'XMLHttpRequest',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36',
        }

    def get_response(self, offert_set):
        response = requests.get(f'{self._start_url}?offset={offert_set}', headers=self._headers)
        if response.status_code == 200:
            return response.content.decode('utf-8')
        return None

    def run(self, offert_set):
        # 1.发出请求,获取页面信息
        req_result = self.get_response(offert_set)

        # 2.解析页面,获取信息
        ## (1)、Xpath解析
        movie_info_list = self.xpath_parse(req_result)
        yield movie_info_list

    def xpath_parse(self, req_result):
        """
        Xpath解析页面
        :param req_result:
        :return:
        """
        movie_info_list = []
        html = etree.HTML(req_result)
        # 排名
        movie_index_list = html.xpath('//i[contains(@class, "board-index")]/text()')

        # 电影名称: 我们可以根据 a 标签的class来确定,同样获取 a 标签中的 title 属性,就为电影名称
        movie_name_list = html.xpath('//a[@class="image-link"]/@title')

        # 电影图片: 我们这里不难发现,a 标签中的第二个 img 标签的 data-src 属性就是图片的地址, 可以用该图片的 class 属性来确定
        movie_picture_list = html.xpath('//img[@class="board-img"]/@data-src')

        # 电影主演: 我们可以根据 class 为 star 的 p 标签来确定,提取出来后做个简单的整理:去除空格
        movie_star_list = html.xpath('//p[@class="star"]/text()')
        movie_star_list = [movie_star.strip() for movie_star in movie_star_list]

        # 上映时间:我们可以根据 class 为 releasetime 的 p 标签来确定, 有些还带着上映地区
        show_time_list = html.xpath('//p[@class="releasetime"]/text()')

        # 电影评分:评分在页面上是有两部分组成的:小数,整数; 整数部分可以通过 class 为 integer 的 i 标签确定, 小数部分可以通过class为fraction的i标签确定,提取出来后做个简单的整理:相加
        movie_grade_integer_list = html.xpath('//i[@class="integer"]/text()')
        movie_grade_decimals_list = html.xpath('//i[@class="fraction"]/text()')
        movie_grade_list = [movie_grade_integer_list[i] + movie_grade_decimals_list[i] for i in range(len(movie_grade_integer_list))]
        for i in range(len(movie_index_list)):
            movie_info_dict = dict()
            movie_info_dict['movie_index'] = movie_index_list[i]
            movie_info_dict['movie_name'] = movie_name_list[i]
            movie_info_dict['movie_picture'] = movie_picture_list[i]
            movie_info_dict['movie_star'] = movie_star_list[i]
            movie_info_dict['show_time'] = show_time_list[i]
            movie_info_dict['movie_grade'] = movie_grade_list[i]
            movie_info_list.append(movie_info_dict)
        return movie_info_list

if __name__ == '__main__':
    tm_spider = TopMovieSpider()
    for i in range(10):
        print('=' * 30 + f'第{i + 1}页')
        movie_info_list = tm_spider.run(i * 10)
        for movie_info in movie_info_list:
            print(movie_info)
        time.sleep(10)

结果的话就贴个图吧:


结果

至于最后的保存,大家就可以随意了,我在这里就不赘述了。

3. 结语

这篇主要通过一个简单的数据采集来介绍的爬虫的基本流程,还有Xpath的简单用法,但也用的不是很多,详细的用法还需要大家自己去慢慢摸索了。下一篇会介绍一下其他几种解析的用法。

你可能感兴趣的:(爬虫实战1.3.5 页面解析-抓取猫眼电影排行(Xpath解析))