Scrapy框架的运用,获取豆瓣电影信息-02

第一节:豆瓣电影信息的爬取

1.分析源码

page页面:https://www.douban.com/doulist/3936288/

 关键源码截图:

外部div:

<div class="bd doulist-subject">
      
        <div class="doulist-video-items">
          <span class="title">播放全片</span>
            
            <a class="doulist-video-item" target="_blank" href="https://v.qq.com/x/cover/1o29ui77e85grdr.html?ptag=newdouban.movie"><span class="icon-circle"><img src="https://img1.doubanio.com/f/movie/f3c173002946c88386e659caef9842e97c19d273/pics/movie/video-qq.png" /></span> 腾讯视频</a>

            
            <a class="doulist-video-item" target="_blank" href="https://m.bilibili.com/bangumi/play/ss28274?bsource=doubanh5"><span class="icon-circle"><img src="https://img1.doubanio.com/f/movie/f536fe0ea1cbb0914658ae803125d078351f9047/pics/movie/video-bilibili.png" /></span> 哔哩哔哩</a>

            
            <a class="doulist-video-item" target="_blank" href="http://v.youku.com/v_show/id_XMjgwNDkwNzE2.html?tpa=dW5pb25faWQ9MzAwMDA4XzEwMDAwMl8wMl8wMQ&refer=esfhz_operation.xuka.xj_00003036_000000_FNZfau_19010900"><span class="icon-circle"><img src="https://img1.doubanio.com/f/movie/886b26a83d18bc60de4ee1daac38145f03c88792/pics/movie/video-youku.png" /></span> 优酷视频</a>

            <a href="javascript:;" class="more-video-item"><img src="https://img1.doubanio.com/f/sns/e2ebb96e1a69c9d9ab686fdf1fda829f43aa1116/pics/sns/ic_circle_more@2x.png" /> 更多</a>
            <div class="video-items-other">
                
                <a target="_blank" href="https://www.douban.com/link2/?url=http%3A%2F%2Fwww.iqiyi.com%2Fv_19rra0h3wg.html%3Fvfm%3Dm_331_dbdy%26fv%3D4904d94982104144a1548dd9040df241&subtype=9&type=online-video"><span class="icon-circle"><img src="https://img1.doubanio.com/f/movie/7c9e516e02c6fe445b6559c0dd2a705e8b17d1c9/pics/movie/video-iqiyi.png" /></span> 爱奇艺视频</a>
            </div>
        </div>

    

内部div: 

内部div:

<div class="source">
      来自:豆瓣电影
    </div>
    
    <div class="post">
      <a href="https://movie.douban.com/subject/1292052/" target="_blank">
        <img src="https://img3.doubanio.com/view/photo/s_ratio_poster/public/p480747492.webp"/>
      </a>
    </div>
    <div class="title">
      <a href="https://movie.douban.com/subject/1292052/" target="_blank">
          <img style="width: 16px; vertical-align: text-top;" src="https://img1.doubanio.com/f/sns/5741f726dfb46d89eb500ed038833582c9c9dcdb/pics/sns/doulist/ic_play_web@2x.png"/>
        肖申克的救赎 The Shawshank Redemption
      </a>
    </div>
    
      <div class="rating">
          <span class="allstar50"></span>
          <span class="rating_nums">9.7</span>
          <span>(2954899人评价)</span>
      </div>
    <div class="abstract">
      
          导演: 弗兰克·德拉邦特
            <br />
          主演: 蒂姆·罗宾斯 / 摩根·弗里曼 / 鲍勃·冈顿
            <br />
          类型: 犯罪 / 剧情
            <br />
          制片国家/地区: 美国
            <br />
          年份: 1994
    </div>
  </div>
  

2.通过命令创建spiders文件db.py

 3.Scrapy shell 的运用(交互式平台)

用来调试Scrapy 项目代码的 命令行工具。 启动的时候预定义了Scrapy的一些对象 启动后如下图所示 作用: 调试 调试 调试

启动Scrapy shell的命令语法格式如下: scrapy shell [option] [url|file] url 就是你想要爬取的网址 注意:分析本地文件是一定要带上路径,scrapy shell默认当作url

 

 获取page页面25条电影名字信息(以列表形式展示):response.xpath('//div[@class="title"]/a/text()')

 获取Selector对象数值:response.xpath('//div[@class="title"]/a/text()').extract()

 获取第一条电影名字信息(strip()为去除空格):response.xpath('//div[@class="title"]/a/text()').extract()[1].strip()

 数据的存储

 

items.py

 pipelines.py(存储管道)

 运行代码:

 运行结果:(这样写的话电影名字、主演、评分信息分开显示,没有写在一起)

 

 

 源代码:

import scrapy

from ..items import DoubanItem  # ..上上级
class DbSpider(scrapy.Spider):
    name = "db"
    # 域名可以在创建项目的时候自定义随便写,但是必须要有,不用的话在这里可以直接注释掉自己写想要的域名
    # allowed_domains = ["www.db233"]
    # start_urls = ["https://www.db233"]

    # allowed_domains = ["m.baidu.com"] # 域名
    allowed_domains = ["www.douban.com"]  # 域名
    # 这个网址通过交互式(scrapy shell +网址)爬不到数据
    # start_urls = ["https://m.baidu.com/sf?pd=topone_multi&top=%7B%22sfhs%22%3A1%7D&atn=index&word=%E8%B1%86%E7%93%A3%E7%94%B5%E5%BD%B1top250&lid=16638235655785603014&key=bd%2FbPtJ7umUkuPF3fz0H4wbbfR%2FIB8veb6rRjTDeeqEVS%2F1TIXYtLVMW25bRVfFa%2BdvPb0y98zHLTQOcnk8wmJEQqtz76fON2BcDkEuHIdg%3D&type=bpage"]
    # page页面的地址,开始请求
    start_urls =["https://www.douban.com/doulist/3936288/"]
    # 一次性拿到xpath数据不一定正确,所以可以通过交互式平台先进行测试
    # scrapy shell+网址
    def parse(self, response):
        # 获取电影信息(先在交互式平台测试好 通过scarpy shell) <以下是response 自带的xpath 要与交互式平台的xpath区分开,交互式安装了scrapy 就会有xpath
        # 通过extract()方法 从select()对象中获取需要的信息
        # 1、通过内部div获取电影名字

        film_name = response.xpath('//div[@class="title"]/a/text()').extract()  # 是个列表

        # 2、评分
        score=response.xpath('//div[@class="rating"]/span[2]/text()').extract()

        # 3、获取导演信息
        # response.xpath('//div[@class="abstract"]/text()')
        main_star = response.xpath('//div[@class="abstract"]/text()').extract()
        # 通过外部div获取电影名字
        # film_name=response.xpath('//div[@class="bd doulist-subject"]/div/div/div/div/a/text()').extract()  # 这样写为啥空值,待确认

        # film_name=response.xpath('//div/div/div/div[@class="title"]/a/text()').extract()[1].strip()
        # 输出电影信息: {'film_name': '肖申克的救赎 The Shawshank Redemption'}
        # films_list = response.xpath('//div[@class="bd doulist-subject"]')  # 共25个电影信息
        # print(len(films_list)) # 25
        # #
        # for node in films_list:
        #
        #     film_name = node.xpath('./div[@class="title"]/a/text()').extract()
        #     print('电影名字:',film_name)
        #     print('================================================')
        # 要交给管道存储,先在 items.py中定义字段名,然后在db.py文件中导入from ..items import DoubanItem
        # 然后使用DoubanItem
        item = DoubanItem()  # 创建对象
        item['film_name']=film_name # 这里就是一个赋值,item可以理解为一个安全的字典
        item['score']=score
        item['main_star']=main_star
        print('输出电影信息:',dict(item))  # 可以转换成真正的字典
        # 只要是返回值就是交个引擎的
        return item # 解析出的数据交给引擎,引擎会交给管道==》需要打开管道,在settings.py
        # ITEM_PIPELINES = {
        #     "douban.pipelines.DoubanPipeline": 300,
        # }
        # 数据交给管道,管道也要进行处理的pipelines.py
        # print('#######################################')
        # print('#######################################')
        # print('#######################################')
        # print(response.text) # 获取page页数据
        pass
'''
xpath抓取数据值有\r\n\t时,去掉的方法normalize-space()
'''

第二节:豆瓣电影信息的爬取(优化:实现将电影信息写在一起显示出来)  

 1.分析page页面源代码,先通过shell先测试一下

 外部div

 与内部div

 获取电影名字:

>> node_list=response.xpath('//div[@class="bd doulist-subject"]')
>>> len(node_list)
25
>>> node_xsk=node_list[0]
>>> node_xsk.xpath('./div[@class="title"]/a/text()').extract()
['\n          ', '\n        肖申克的救赎 The Shawshank Redemption\n      ']
>>> node_xsk.xpath('./div[@class="title"]/a/text()').extract()[1].strip()
'肖申克的救赎 The Shawshank Redemption'

发现电影名字输出不规则,有些名字前没有空格,无法统一使用xpath().extract[1].strip() 打印出字符串形式

 获取主演:

 node_xsk.xpath('./div[@class="abstract"]/text()').extract()
['\n      \n          导演: 弗兰克·德拉邦特\n            ', '\n          主演: 蒂姆·罗宾斯 / 摩根·弗里曼 / 鲍勃·冈顿
\n            ', '\n          类型: 犯罪 / 剧情\n            ', '\n          制片国家/地区: 美国\n            ', '\n
      年份: 1994\n    ']
>>> node_xsk.xpath('./div[@class="abstract"]/text()').extract()[1]
'\n          主演: 蒂姆·罗宾斯 / 摩根·弗里曼 / 鲍勃·冈顿\n            '
>>> node_xsk.xpath('./div[@class="abstract"]/text()').extract()[1].strip()
'主演: 蒂姆·罗宾斯 / 摩根·弗里曼 / 鲍勃·冈顿'

获取评分:

2.主要代码部分

与db.py不同的地方:因为是个for循环要不断的输出25条数据给到引擎,由引擎给到管道。

 

 运行结果:

 film2.text(电影名字输出不规则导致无法统一打印输出,待解决!!!)

 db2.py:

import scrapy

from ..items import DoubanItem  # ..上上级
import re
class DbSpider(scrapy.Spider):
    name = "db2"
    # 域名可以在创建项目的时候自定义随便写,但是必须要有,不用的话在这里可以直接注释掉自己写想要的域名
    # allowed_domains = ["www.db233"]
    # start_urls = ["https://www.db233"]

    # allowed_domains = ["m.baidu.com"] # 域名
    allowed_domains = ["www.douban.com"]  # 域名
    # 这个网址通过交互式(scrapy shell +网址)爬不到数据
    # start_urls = ["https://m.baidu.com/sf?pd=topone_multi&top=%7B%22sfhs%22%3A1%7D&atn=index&word=%E8%B1%86%E7%93%A3%E7%94%B5%E5%BD%B1top250&lid=16638235655785603014&key=bd%2FbPtJ7umUkuPF3fz0H4wbbfR%2FIB8veb6rRjTDeeqEVS%2F1TIXYtLVMW25bRVfFa%2BdvPb0y98zHLTQOcnk8wmJEQqtz76fON2BcDkEuHIdg%3D&type=bpage"]
    # page页面的地址
    start_urls =["https://www.douban.com/doulist/3936288/"]
    # 一次性拿到xpath数据不一定正确,所以可以通过交互式平台先进行测试,
    # scrapy shell+网址
    def parse(self, response):
        # 获取电影信息(先在交互式平台测试好 通过scarpy shell) <以下是response 自带的xpath 要与交互式平台的xpath区分开,交互式安装了scrapy 就会有xpath
        # 通过extract()方法 从select对象中获取需要的信息
        # film_name=response.xpath('//div[@class="title"]/a/text()').extract()  # 是个列表
        node_list = response.xpath('//div[@class="bd doulist-subject"]')  # 共25个电影信息
        for node in node_list:
            # 1.获取电影名字

            # film_name=node.xpath('./div[@class="title"]/a/text()').extract()
            # 按以下写会出现 list index out of range,因为存在有几个第一个不存在空格情况
            # film_name=node.xpath('./div[@class="title"]/a/text()').extract()[1].strip()
            # 2.获取评分
            # response.xpath('//div[@class="rating"]/span[2]')
            score = node.xpath('./div[@class="rating"]/span[2]/text()').extract()[0].strip()
            # >> > node_xsk.xpath('./div[@class="rating"]/span[2]/text()').extract()[0]
            # '9.7'
            # >> >
            # 3.获取主演
            #>>> node.xpath('./div[@class="abstract"]/text()').extract()[1].strip()
            '导演: 弗兰克·德拉邦特'
            # 第一种写法:
            main_star=node.xpath('./div[@class="abstract"]/text()').extract()[1].strip()
            # 第二种写法:
            # '''
            # import re
            # for node in node_list:
            #     main_star = node.xpath('./div[@class="abstract"]/text()').extract()
            #     star_name = re.findall("主演?:? ?(.*)",str(main_star))[1]
            #     star_name
            #
            #
            # '''
            # main_star = node.xpath('./div[@class="abstract"]/text()').extract()
            # if '主' in main_star:
            #     # 第一个?是演是0或者1个,第二个?是:是0或者1个,第三个?空格可以是0或者1个,(.*)匹配后面所有的意思
            #     # star_name=re.findall("主演?:? ?(.*)",str(main_star))
            #     star_name = re.findall("主演:? ?(.*)",str(main_star))[1]
            #
            # else:
            #     star_name='空'  # 如果没有主演的情况下

            # 注意:extract()跟extract_first()一样
            # 要交给管道存储,先在 items.py中定义字段名,然后在db.py文件中导入from ..items import DoubanItem
            # 然后使用DoubanItem
            item=DoubanItem() # 创建对象
            # item['film_name']=film_name # 这里就是一个赋值,item可以理解为一个安全的字典
            item['score'] = score
            item['main_star'] = main_star
            print('输出:',dict(item))  # 可以转换成真正的字典
            # 只要是返回值就是交个引擎的
            # return item # 解析出的数据交给引擎,引擎会交给管道==》需要打开管道,在settings.py
            # return 返回的是方法,这里要使用生成器,不断的生成25条数据不断的给到引擎,然后引擎就不断的给到管道 yield item ,使用return 只能输出一条数据
            yield item  # 这里与db.py文件不同的地方
        # ITEM_PIPELINES = {
        #     "douban.pipelines.DoubanPipeline": 300,
        # }
        # 数据交给管道,管道也要进行处理的pipelines.py
        # print(response.text) # 获取page页数据

'''
xpath抓取数据值有\r\n\t时,去掉的方法normalize-space()
'''
# 1、获取电影名字 extract()就是提取data里面的数据

以上已完成电影名字、主演信息、评分获取。

3.如何实现分页信息获取?如获取第2页...第n页

先解决一个问题,最近代码不显示行号了,先解决一波

File --> Settings -->Editor -->Appearance ,  之后勾选Show Line Numbers。

 先获取第2页电影数据:

url:https://www.douban.com/doulist/3936288/?start=25&sort=time&playable=0&sub_typ
以下绿色线条流程为获取第二页请求流程顺序

 主要代码:

 db3.py

import scrapy

from ..items import DoubanItem  # ..上上级
import re
class DbSpider(scrapy.Spider):
    name = "db3"
    # 域名可以在创建项目的时候自定义随便写,但是必须要有,不用的话在这里可以直接注释掉自己写想要的域名
    # allowed_domains = ["www.db233"]
    # start_urls = ["https://www.db233"]

    # allowed_domains = ["m.baidu.com"] # 域名
    allowed_domains = ["www.douban.com"]  # 域名
    # 这个网址通过交互式(scrapy shell +网址)爬不到数据
    # start_urls = ["https://m.baidu.com/sf?pd=topone_multi&top=%7B%22sfhs%22%3A1%7D&atn=index&word=%E8%B1%86%E7%93%A3%E7%94%B5%E5%BD%B1top250&lid=16638235655785603014&key=bd%2FbPtJ7umUkuPF3fz0H4wbbfR%2FIB8veb6rRjTDeeqEVS%2F1TIXYtLVMW25bRVfFa%2BdvPb0y98zHLTQOcnk8wmJEQqtz76fON2BcDkEuHIdg%3D&type=bpage"]
    # page页面的地址
    start_urls =["https://www.douban.com/doulist/3936288/"]
    # 一次性拿到xpath数据不一定正确,所以可以通过交互式平台先进行测试,
    # scrapy shell+网址
    def parse(self, response):
        # 获取电影信息(先在交互式平台测试好 通过scarpy shell) <以下是response 自带的xpath 要与交互式平台的xpath区分开,交互式安装了scrapy 就会有xpath
        # 通过extract()方法 从select对象中获取需要的信息
        # film_name=response.xpath('//div[@class="title"]/a/text()').extract()  # 是个列表
        node_list = response.xpath('//div[@class="bd doulist-subject"]')  # 共25个电影信息
        for node in node_list:
            # 1.获取电影名字

            # film_name=node.xpath('./div[@class="title"]/a/text()').extract()
            # 按以下写会出现 list index out of range,因为存在有几个第一个不存在空格情况
            # film_name=node.xpath('./div[@class="title"]/a/text()').extract()[1].strip()
            # 2.获取评分
            # response.xpath('//div[@class="rating"]/span[2]')
            score = node.xpath('./div[@class="rating"]/span[2]/text()').extract()[0].strip()
            # >> > node_xsk.xpath('./div[@class="rating"]/span[2]/text()').extract()[0]
            # '9.7'
            # >> >
            # 3.获取主演
            #>>> node.xpath('./div[@class="abstract"]/text()').extract()[1].strip()
            '导演: 弗兰克·德拉邦特'
            # 第一种写法:
            main_star=node.xpath('./div[@class="abstract"]/text()').extract()[1].strip()
            # 第二种写法......
            # 注意:extract()跟extract_first()一样
            # 要交给管道存储,先在 items.py中定义字段名,然后在db.py文件中导入from ..items import DoubanItem
            # 然后使用DoubanItem
            item=DoubanItem() # 创建对象
            # item['film_name']=film_name # 这里就是一个赋值,item可以理解为一个安全的字典
            item['score'] = score
            item['main_star'] = main_star
            print('输出:',dict(item))  # 可以转换成真正的字典
            # 只要是返回值就是交个引擎的
            # return item # 解析出的数据交给引擎,引擎会交给管道==》需要打开管道,在settings.py
            # return 返回的是方法,这里要使用生成器,不断的生成25条数据不断的给到引擎,然后引擎就不断的给到管道 yield item ,使用return 只能输出一条数据
            yield item  # 这里与db.py文件不同的地方
            # 如何获取第2页电影信息?
            # 需要先把第一页25条的数据for循环执行完成才能开始爬取第2页信息,第2页有24条数据
            # 第二页就是一个新的请求,找到对应url,并再次发起请求,引擎将对应的response交给self.parse重新解析,即再次执行for循环
            # url2="https://www.douban.com/doulist/3936288/?start=25&sort=time&playable=0&sub_type="
            # 如何获得第n页?要对url分析找到规律

            yield scrapy.Request('https://www.douban.com/doulist/3936288/?start=25&sort=time&playable=0&sub_type=',callback=self.parse) # callback 是回调函数
     

运行截图:(前两页共49条数据)

 如何获取第n页?先判断每页url的规律

分析不同页的url找到规律:===》25的倍数
https://www.douban.com/doulist/3936288/?start=0&sort=time&playable=0&sub_type= 第1页 0*25
https://www.douban.com/doulist/3936288/?start=25&sort=time&playable=0&sub_type= 1*25
https://www.douban.com/doulist/3936288/?start=50&sort=time&playable=0&sub_type= 2*25
https://www.douban.com/doulist/3936288/?start=75&sort=time&playable=0&sub_type= ...
https://www.douban.com/doulist/3936288/?start=100&sort=time&playable=0&sub_type= ...

https://www.douban.com/doulist/3936288/?start=200&sort=time&playable=0&sub_type= 第9页
https://www.douban.com/doulist/3936288/?start=225&sort=time&playable=0&sub_type= 第10页 9*25

定义一个类变量:page_num=0

 主要代码截图:

无法正常获取数据就增加下载延迟:

  运行截图(总共有10页数据,到第11页的时候就爬不到数据了,空的,db5.py优化)

省略...

db4.py源代码(注意:凡是使用爬虫去爬取数据时,都应提前想想爬取的网站上有没有反爬虫,就需要在settings.py中增加一些内容才能爬取到数据)

import scrapy

from ..items import DoubanItem  # ..上上级
import re
class DbSpider(scrapy.Spider):
    name = "db4"
    # 域名可以在创建项目的时候自定义随便写,但是必须要有,不用的话在这里可以直接注释掉自己写想要的域名
    # allowed_domains = ["www.db233"]
    # start_urls = ["https://www.db233"]

    # allowed_domains = ["m.baidu.com"] # 域名
    allowed_domains = ["www.douban.com"]  # 域名
    # 这个网址通过交互式(scrapy shell +网址)爬不到数据
    # page页面的地址
    start_urls =["https://www.douban.com/doulist/3936288/"]
    # 一次性拿到xpath数据不一定正确,所以可以通过交互式平台先进行测试,
    # scrapy shell+网址
    page_num=0 # 为类变量
    def parse(self, response):
        node_list = response.xpath('//div[@class="bd doulist-subject"]')  # 共25个电影信息
        for node in node_list:
            # film_name=node.xpath('./div[@class="title"]/a/text()').extract()
            score = node.xpath('./div[@class="rating"]/span[2]/text()').extract()[0].strip()
            main_star=node.xpath('./div[@class="abstract"]/text()').extract()[1].strip()
            item=DoubanItem() # 创建对象
            # item['film_name']=film_name # 这里就是一个赋值,item可以理解为一个安全的字典
            item['score'] = score
            item['main_star'] = main_star
            print('输出:',dict(item))  # 可以转换成真正的字典
            yield item  # 这里与db.py文件不同的地方
            self.page_num+=1
            print('page_num',self.page_num)
            # 如何获得第n页?要对url分析找到规律
            page_url='https://www.douban.com/doulist/3936288/?start={}&sort=time&playable=0&sub_type='.format(self.page_num*25)
            yield scrapy.Request(page_url,callback=self.parse) # callback 是回调函数


'''
分析不同页的url找到规律:===》25的倍数
https://www.douban.com/doulist/3936288/?start=0&sort=time&playable=0&sub_type=  第1页 0*25
https://www.douban.com/doulist/3936288/?start=25&sort=time&playable=0&sub_type=      1*25
https://www.douban.com/doulist/3936288/?start=50&sort=time&playable=0&sub_type=      2*25
https://www.douban.com/doulist/3936288/?start=75&sort=time&playable=0&sub_type=
https://www.douban.com/doulist/3936288/?start=100&sort=time&playable=0&sub_type=

https://www.douban.com/doulist/3936288/?start=200&sort=time&playable=0&sub_type= 第9页
https://www.douban.com/doulist/3936288/?start=225&sort=time&playable=0&sub_type= 第10页  9*25


'''

db5.py源代码(如果爬到第11页《共10页数据》) 没有数据程序就要自动停止,通过if...else实现

 以上已经实现豆瓣电影1-10页信息的爬取。

 

 

posted @ 2023-12-12 20:06  人生努力努力努力就好  阅读(55)  评论(0编辑  收藏  举报