目 录CONTENT

文章目录

Scrapy 入门_第一步_实战豆瓣电影TOP250

小张的探险日记
2021-09-07 / 0 评论 / 0 点赞 / 870 阅读 / 5,021 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2021-09-07,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

Scrapy 入门_第一步_实战豆瓣电影TOP250


学习东西喜欢先做出效果,会用是第一步,然后再去了解原理。

1.爬虫需求

​ 爬取豆瓣电影TOP250的数据,

​ 爬取字段:排名、封面、电影名称、主演阵容、电影信息、评分、评价人数、名言

​ 写入 txt 文件

image-20210512005926917

2.实现效果

​ 爬取的信息写入 txt文件

image-20210512010138667

3.爬虫设计

3.1 目标分析

​ 首先 F12 查看 html 代码结构,并观察分页参数

​ 搜索的电影信息都在 一个 class=“item” 的div中

image-20210512010411545

​ 观察地址栏发现 分页规律

​ 第一页:

https://movie.douban.com/top250?start=0&filter=

​ 第二页:

https://movie.douban.com/top250?start=25&filter=

​ 第三页:

https://movie.douban.com/top250?start=50&filter=

3.2 代码设计

​ 这里学习使用 Scrapy 爬取数据。

​ Scrapy 项目结构

.
├── dianyingTop250          #外层目录
│   ├── __init__.py         #初始化脚本    
│   ├── __pycache__         #Python缓存文件。暂时无视
│   ├── items.py            #Items代码模板,继承类自scrapy.Item
│   ├── middlewares.py      #Middlewares代码模板(继承类)
│   ├── pipelines.py        #Pipelines代码模板(继承类)
│   ├── settings.py         #Scrapy爬虫的配置文件
│   └── spiders             #Spiders代码模板目录 我们写爬虫的地方
│       ├── __init__.py
│       └── __pycache__
└── scrapy.cfg              #部署爬虫的配置文件

​ 先搭建一个Scrapy 工程

​ 新建一个 python 工程

image-20210512010912114

​ 在case 1 下 运行 scrapy 创建工程的命令

​ 没有安装 scrapy 的 运行 pip install scrapy 即可安装 scrapy。

scrapy startproject dianyingTop250

代码结构如下,这里是我已经搭建好,并运行的项目,所以多了mian.py 和 top250.txt 文件

image-20210512011159918

​ 进入到 dianyingTop250 的目录下执行命令,新建一个爬虫,并指定 要爬取的网站,注意不需要带http 或https协议。

scrapy genspider jobbole movie.douban.com

完成出现如下文件,这里的代码是我已经写好的

image-20210512011646690

​ 定义需要爬取的字段

image-20210512011335179

爬虫主体代码

from urllib.request import Request

import scrapy

from ..items import Dianyingtop250Item


class Top250Spider(scrapy.Spider):
    # 爬虫名称
    name = 'top250'
    # 规定爬虫爬取网页的域名
    allowed_domains = ['movie.douban.com']
    # 开始爬取的url
    start_urls = []

    # 我们爬取10页的 豆瓣电影 Top 250
    # 简单点 我们知道要爬取10页的数据,先把要爬取的10页数据的 url 生成放入start_urls
    for i in range(0, 250, 25):
        start_urls.append('https://movie.douban.com/top250?start=' + str(i) + '&filter=')

    def parse(self, response):
        """
            此方法 负责解析 爬取的内容
            以下主要考验 xpath 语法的熟练程度
            xpath 学习 : https://www.runoob.com/xpath/xpath-tutorial.html
        """
        list_li = response.xpath('//div[@class="item"]')
        for li in list_li:
            """
            	这里有一个 很坑的地方,导入Dianyingtop250Item时,
            	工具生成的 import 语句 在运行时出错,需要手动改为
            	from ..items import Dianyingtop250Item
            """
            item = Dianyingtop250Item()
            # 排名
            item['ranking'] = li.xpath('.//div[1]/em/text()').extract_first()
            # 电影封面
            item['front_cover'] = li.xpath('.//div/a/img//@src').extract_first()
            title = li.xpath('.//div[2]/div[1]/a')
            title_text = title[0].xpath('string(.)').extract()[0].strip()
            # 电影title
            item['movie_name'] = title_text.replace(' ','').replace('\n','')
            # 主演信息
            item['star_list'] = li.xpath('.//div[2]/div[2]/p[1]/text()[1]').extract_first().strip()
            # 电影信息
            item['movie_information'] = li.xpath('.//div[2]/div[2]/p[1]/text()[2]').extract_first().strip()
            # 电影评分
            item['grade'] = li.xpath('.//div[2]/div[2]/div/span[2]/text()').extract_first().strip()
            # 评价人数
            item['evaluators_count'] = li.xpath('.//div[2]/div[2]/div/span[4]/text()').extract_first().strip()
            # 名言引用
            quote = li.xpath('.//div[2]/div[2]/p[2]/span/text()')
            if len(quote) > 0:
                item['saying'] = quote.extract_first().strip()
            else:
                item['saying'] = ''
            # 运行完成后 会进入管道,管道需要在 setting.py 中配置    
            yield item

管道代码

​ 主要是 拿到item 中的数据,已追加的形式 塞入txt 文件。

# 处理管道
class Dianyingtop250Pipeline:
    def process_item(self, item, spider):
        # 写入文件夹
        with open('top250.txt','a+',encoding='utf-8') as f:
            f.write('排名:{}\n 封面:{} \n 电影名称:{} \n 主演阵容:{} \n 电影信息:{} \n 评分:{} \n'
                    '评价人数:{} \n 名言:{} \n\r'.format(item['ranking'],item['front_cover'],
                                              item['movie_name'],item['star_list'],
                                              item['movie_information'],item['grade']
                                              ,item['evaluators_count'],item['saying'],))

​ 配置scrapy 爬虫

​ ROBOTSTXT_OBEY = False 设置不遵守爬虫规则,一般网站都有reboot.txt, 如果网站不允许你爬取,scrapy 默认会准守它的规则,这里 一般自行设置为 False。

​ 其他的注释都写得很清楚了

image-20210512012318219

3.3 扩展输出结果方式_输出JSON 格式文件

​ 在 pipelines.py 文件 新增一个 管道 class, 并在 Dianyingtop250Pipeline 上面用到的管道中返回 item,

用于 此管道的对象使用。

class Dianyingtop250JSONPipeline:
    def process_item(self, item, spider):
        with open('top250.json', 'a+', encoding='utf-8') as f:
            """
            Python 3中的json在做dumps操作时,会将中文转换成unicode编码,
            并以16进制方式存储,再做逆向操作时,会将unicode编码转换回中文
            json
            dump有一个ensure_ascii参数,当它为True的时候,
            所有非ASCII码字符显示为\\uXXXX序列,只需在dump时将ensure_ascii设置为False即可,此时存入json的中文即可正常显示
            """
            f.write(json.dumps(dict(item),ensure_ascii=False) + '\n')
        return item

设置中新增管道类,这里数字越小 优先级 越高。

image-20210512231215126

写入结果集如下。

image-20210512231314452

3.4 扩展 Scrapy 下载电影封面
###### 3.4.1 自定义管道实现

在 pipelines.py 文件 添加 CustomDownloadPipeline 类,把文件下载到

#自定义管道 实现文件下载
class CustomDownloadPipeline:

    def create_dir(self, dir_path):
        if not os.path.exists(dir_path): os.mkdir(dir_path)

    def process_item(self,item,spider):
        #电影封面
        front_cover = item['front_cover']
        ranking = item['ranking']
        # 创建目录,如果没有则创建
        self.create_dir('frontCover')
        request.urlretrieve(front_cover,'frontCover/'+ranking+'.png')
        return item
    
    # 暂时没用到,本来想用电影名称的, 电影名称含有特殊符号
    def convert_to_pinyin(self,world):
        # 将中文汉字转换成不带声调的拼音
        to_pinyin = [''.join(i) for i in pypinyin.pinyin(world, style=pypinyin.NORMAL)]
        to_pinyin = ''.join(to_pinyin)
        return to_pinyin

配置中 添加 自定义管道类 CustomDownloadPipeline

image-20210513002605818

效果如下

image-20210513002236624

3.4.2 使用 Scrapy 提供的 FilesPipeline 下载封面

​ item 添加两个属性,file_urls 用于存放待下载的文件链接,files 用于存放 下载完成的文件对象。

image-20210513005138707

​ 爬虫下 多赋值属性 file_urls

image-20210513005327363

​ 最后设置 文件下载的管道类 scrapy.pipelines.files.FilesPipeline 固定写法,并设置文件下载后存储的位置。

image-20210513005354238

效果如下:

image-20210513005821251

FilesPipeline 请求的请求头是固定的,有些网站对Scrapy 做了特定处理,那么就会爬取不了,这时候可以自定义类,继承 FilesPipeline 重写 get_media_requests 方法。

3.4.3 使用 Scrapy 提供的 ImagesPipeline下载封面

​ 同 FilesPipeline ,使用 ImagesPipeline 也需要 特定的属性

image-20210513012800429

​ 赋值图片链接地址

image-20210513012845027

​ 为了区分,我把 FilesPipeline 的存储路径换成了 files

​ ps: 一定要安装 pip install pillow ,否则执行后无效,这是 ImagesPipeline 的依赖库。

image-20210513012924797

运行效果

image-20210513013111153

虽然不是每天都能完成计划,但也要坚持,赶回来。加油 2021-05-12 1:26:00

继续继续,每天一点点 都是在进步 2021-05-13 1:31:00

成功不是凭梦想和希望,而是凭努力和实践。

img

0

评论区