scrapy抓取豆瓣电影相关数据

Posted pythoner6833

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了scrapy抓取豆瓣电影相关数据相关的知识,希望对你有一定的参考价值。

1. 任务分析及说明

目标网站:https://movie.douban.com/tag/#/

抓取豆瓣电影上,中国大陆地区,相关电影数据约1000条;数据包括:电影名称、导演、主演、评分、电影类型、语言、上映时间、短评top20等数据;

1.1 Fiddler抓包要点分析:

请求均为GET请求;拼接后的URL为是https://movie.douban.com/j/new_search_subjects?sort=U&range=0,10&tags=电影&start=0

其中,range表示评分区间(0,10表示筛选评分在0-10之间的电影);

tags表示分类类别(电影?剧集?);

第一次请求默认返回20部电影相关信息,start=0;点击加载更多start=20,即每次点击一次加载更多,start增加20;

返回数据为json格式,数据包括电影名称、导演、电影详情的URL等信息;

从json数据中提取电影详情页的URL,访问并抓取详情信息;

抓取电影短评时,只抓取了最前面的20条,并利用//拼接成一个字符串,数据保存为excel形式。

2. 代码逻辑

2.1  项目创建

利用scrapy的基本命令创建项目、爬虫等,在此不细说,直接上命令。

scrapy startproject DoubanMovie  # 创建项目

cd DoubanMovie # 进入项目目录

scrapy genspider douban douban.movie.com # 创建爬虫

2.2 明确抓取字段

scrapy爬虫的套路都相似,创建项目后首先明确爬取字段;其次,编写爬虫逻辑;然后,编写数据保存逻辑;最后,做一些修修补补的工作,例如添加请求头啊,注册通道呀等等。

来到items.py文件中,明确要抓取的字段。

# -*- coding: utf-8 -*-
import scrapy

class DoubanmoviesItem(scrapy.Item):

    # 电影名称
    filmtitle = scrapy.Field()
    # 电影评分
    moviemark = scrapy.Field()
    # 导演名称
    moviedirt = scrapy.Field()
    # 电影主演
    movierole = scrapy.Field()
    # 电影类型
    movietype = scrapy.Field()
    # 制片地区
    moviearea = scrapy.Field()
    # 语言类型
    movielang = scrapy.Field()
    # 上映时间
    moviedate = scrapy.Field()
    # 剧情简介
    moviesyno = scrapy.Field()
    # 电影短评
    moviecoms = scrapy.Field()
    # # 电影影评
    # movierews = scrapy.Field()

2.3 爬虫逻辑

明确抓取字段后,开始到spiders文件夹下的douban.py中编写爬虫逻辑。豆瓣电影返回的数据为json格式,对json格式的数据进行解析,从中提取到电影详情页的url,访问并从中提取详细信息。

# -*- coding: utf-8 -*-
import re
import json
import scrapy

from DoubanMovies.items import DoubanmoviesItem

class DoubanSpider(scrapy.Spider):
    name = douban
    allowed_domains = [movie.douban.com]
    # start_urls = [‘http://movie.douban.com/‘]

    start = 0

    # 指定参数
    formdata = {
        sort: U,
        range: 0, 10,
        tags: 电影,
        start: 0,
        countries: 中国大陆  # 这里只抓取中国大陆地区,其他地区可做相应修改
    }

    base_url = https://movie.douban.com/j/new_search_subjects

    def start_requests(self):

        # 构造初始请求url
        url = self.base_url + ? + sort={}&range={}&tags={}&start={}&countries={}.format(
            self.formdata[sort], self.formdata[range], self.formdata[tags],
            self.formdata[start], self.formdata[countries]
        )

        # 发起请求
        yield scrapy.Request(
            url=url,
            callback=self.parse,
            meta={formdata: self.formdata}
        )


    def parse(self, response):
        """
        豆瓣默认返回json格式的数据
        :param response:
        :return:
        """
        formdata = response.meta[formdata]

        # 将json格式的数据转化为字典
        data_list = json.loads(response.body.decode())[data]

        # 数据解析
        for data in data_list:

            # 从json数据中解析基本信息
            item = DoubanmoviesItem()
            item[filmtitle] = data[title]
            item[moviemark] = data[rate]
            item[moviedirt] =  .join(data[directors])
            item[movierole] =  .join(data[casts])

            # 拿到详情页链接,获取影评等信息
            detail_url = data[url]
            yield scrapy.Request(
                url=detail_url,
                callback=self.parse_detail,
                meta={item: item, formdata: formdata}  # 传入item到parse_detail,继续解析数据
            )

        if not self.start == 1000:  # 抓取1020条数据
            self.start += 20
            formdata = self.formdata
            formdata[start] = str(self.start)

            url = self.base_url + ? + sort={}&range={}&tags={}&start={}&countries={}.format(
            formdata[sort], formdata[range], formdata[tags],
            formdata[start], formdata[countries])

            yield scrapy.Request(
                url=url,
                callback=self.parse,
                meta={formdata: formdata}
            )

    def parse_detail(self, response):
        """
        从详情页解析其他信息
        :param response:
        :return:
        """
        formdata = response.meta[formdata]
        item = response.meta[item]

        item[movietype] = /.join(response.xpath("//div[@id=‘info‘]/span[@property=‘v:genre‘]/text()").extract())
        item[moviearea] = formdata[countries]
        item[movielang] = ‘‘.join(re.findall(<span class="pl">语言:</span>(.*?)<br/>, response.body.decode()))
        item[moviedate] = /.join(response.xpath("//div[@id=‘info‘]/span[@property=‘v:initialReleaseDate‘]/text()").extract())
        item[moviesyno] = response.xpath("//div[@id=‘link-report‘]/span[1]/text()").extract_first().strip()

        # 新页面解析电影短评
        coms_url = response.xpath("//div[@id=‘comments-section‘]/div[1]/h2/span/a/@href").extract_first()
        yield scrapy.Request(
            url=coms_url,
            callback=self.parse_coms,  # 在parse_coms中提取电影短评,这里只提取前20 
            meta={item: item}
        )

    def parse_coms(self, response):
        """
        解析电影短评top20,将20条短评以//拼接成一个字符串
        :param response:
        :return:
        """
        item = response.meta[item]
        
        # 提取短评top20
        coms_list = response.xpath("//div[@id=‘comments‘]/div[@class=‘comment-item‘]/div[@class=‘comment‘]/p/span/text()").extract()
        item[moviecoms] = //.join(coms_list)

        yield item

 

2.4 数据保存

编写完爬虫逻辑后,来到pipelines.py文件中编写保存数据逻辑。这里将数据保存为excel格式。

# -*- coding: utf-8 -*-
from openpyxl import Workbook

class DoubanmoviesPipeline(object):

    def __init__(self):

        # 创建excel表格保存数据
        self.workbook = Workbook()
        self.booksheet = self.workbook.active
        self.booksheet.append([电影名称, 评分, 导演,
                               主演, 电影类型, 制片地区,
                               语言类型, 上映时间, 剧情简介,
                               短评(top20)])

    def process_item(self, item, spider):

        DATA = [
            item[filmtitle], item[moviemark], item[moviedirt],
            item[movierole], item[movietype], item[moviearea],
            item[movielang], item[moviedate], item[moviesyno],
            item[moviecoms]]
        self.booksheet.append(DATA)
        self.workbook.save(./results.xls)

        return item

2.5 其他

1. 通道注册,包括下载中间件,pipelines等的注册,还有不遵循爬虫协议

2. 延时处理,在settings.py文件中添加

DOWNLOAD_DELAY = 5  # 每个请求延迟5秒

3. 添加请求头

在下载中间件(middlewares.py)中给每个请求添加请求头

# -*- coding: utf-8 -*-
from DoubanMovies.settings import USER_AGENTS as ua
import random

class DoubanmoviesDownloaderMiddleware(object):

    def process_request(self, request, spider):
        """
                给每一个请求随机分配一个代理
                :param request:
                :param spider:
                :return:
                """
        user_agent = random.choice(ua)
        request.headers[User-Agent] = user_agent

4. 将运行命令写在main.py文件中

from scrapy import cmdline

cmdline.execute(scrapy crawl douban.split())

3. 完整代码

参见:https://github.com/zInPython/DoubanMovie

以上是关于scrapy抓取豆瓣电影相关数据的主要内容,如果未能解决你的问题,请参考以下文章

03_使用scrapy框架爬取豆瓣电影TOP250

1-1 用Python抓取豆瓣及IMDB上的电影信息

Python爬虫编程思想(87):项目实战--抓取豆瓣电影排行榜

Python爬虫编程思想(87):项目实战--抓取豆瓣电影排行榜

Scrapy爬取豆瓣电影并存入MySQL数据库

python怎么抓取豆瓣电影url