手把手学爬虫第二弹——Scrapy框架

一、什么是Scrapy?

    Scrapy是一个可以爬取网站数据、提取结构性数据而编写的开原框架。Scrapy的用途不仅限于爬虫,还可以用于数据挖掘、数据监测、以及自动化测试等。今天我就带大家一起学习Scrapy在爬虫的应用。
开发文档

二、Scrapy工作原理

    Scrapy框架简单分为五个部分,如下图所以,各部分负责不同的工作,相互协调完成工作。
请添加图片描述

  • Scrapy Engine: 正如它所处的位置一样,它是整个框架的核心,用于处理整个系统的数据流和事件。
  • Scheduler: 调度器,接受来自引擎的请求,在这里有一个URL队列,在引擎再次请求的时候将请求返回给引擎。
  • Downloader: 下载器。用于从网络上下载web资源。
  • Spider: 爬虫。从指定网页爬取需要的信息。
  • Item Pipeline: 项目管道。用于处理爬取到的数据,例如数据的清洗保存等。

三、Scrapy框架的基本应用

    Scrapy的安装和新建就不再赘述,不明白的可以去查看文档,这里我以一个简单的例子来讲解如何使用框架。爬取豆瓣TOP250的电影信息。

1.新建Scrapy项目

    首先新建一个框架项目后你会得到如下的树形结构的文件。
请添加图片描述

  • spiders:用于编写爬虫。
  • item.py:临时保存抓取到的数据,存储方式类似于字典。
  • middlewares.py:项目中间件,可以自定义插入代码扩展Scrapy功能。
  • pipelines文件:核心处理器。
  • settings.py:项目设置文件。
  • scrapy.pcfg:项目配置文件。

2.编写items.py

    这个文件是存储爬取数据的容器,存储形式类似于字典。

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class MovieItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()  # 电影名称
    info = scrapy.Field()  # 导演与演员
    score = scrapy.Field()  # 电影评分
    evaluation = scrapy.Field()  # 评价人数
    summary = scrapy.Field()  # 电影总结

3.编写settings.py

    全局设置都在这里,例如我们可以设置爬取间隔为1s。新建项目里面会有很多代码是注释的,我们不需要改动,需要对应的设置的时候再查看即可。
请添加图片描述

4.编写爬虫逻辑

    爬虫逻辑我们统一写在spider文件下,即在spider文件夹下新建.py文件。

# -*- coding: utf-8 -*-
# @Time : 2021/9/17 16:30
# @Author : KK
# @File : douban.py
# @Software: PyCharm 
# -*- coding: utf-8 -*-
import re
import scrapy
from scrapyTest.items import MovieItem


# 处理字符串中的空白符,并拼接字符串
def processing(strs):
    s = ''  # 定义保存内容的字符串
    for n in strs:
        n = ''.join(n.split())  # 去除空字符
        n = n.replace(" ", "")
        s = s + n  # 拼接字符串
    return s  # 返回拼接后的字符串


class MoviespiderSpider(scrapy.Spider):
    name = 'movieSpider'  # 爬虫的名称,这个名称是唯一的且也是必须的
    allowed_domains = ['movie.douban.com']  # 允许爬虫爬取的域名列表
    start_urls = ['https://movie.douban.com/top250']  # 爬虫起始访问的URL

    def parse(self, response):
        li_all = re.findall(r'<li>[\s\S]*?</li>', response.text)
        item = MovieItem()
        for each in li_all:
            names = re.findall(r'<span class="title">(.*)</span>', each)  # 获取电影名字相关信息
            item['name'] = processing(names)  # 处理电影名称信息
            infos = re.findall(r'导演:(.*?)<br>', each)  # 获取导演、主演等信息
            item['info'] = processing(infos)  # 处理导演、主演等信息
            scores = re.findall(r'<span class="rating_num" property="v:average">(.*)</span>', each)  # 获取电影评分
            item['score'] = processing(scores)
            evaluations = re.findall(r'<span>(.*)</span>', each)  # 获取评分人数
            item['evaluation'] = processing(evaluations)
            summarys = re.findall(r'<span class="inq">(.*)</span>', each)  # 获取评分人数
            item['summary'] = processing(summarys)
            yield item

            for i in range(1, 10):
                page = i * 25
                start = '?' + 'start=' + str(page)
                next_url = response.urljoin(start)
                yield scrapy.Request(url=next_url, callback=self.parse)

5.启动爬虫

    这时候一个简单的Scrapy爬虫就准备就绪了,在控制台输入

scrapy crawl movieSpider -o items.json
scrapy crawl保持不动
movieSpider

就可以启动爬虫了。但你会发现程序没有正常获取到数据,查看控制台输出发现返回值为403,这是我们的爬虫被服务器识别了,进行了反爬,解决办法是在settings.py文件加上我们的请求头进行伪装。
请添加图片描述
    这样启动我们每次都需要在控制台输入命令行,为了更加快捷的启动我们的项目,我们可以在项目文件根目录下新建一个main.py。

# -*- coding: utf-8 -*-
# @Time : 2021/9/17 17:01
# @Author : KK
# @File : main.py
# @Software: PyCharm 
from scrapy.cmdline import execute
import sys
import os

sys.path.append(os.path.dirname(os.path.abspath(__file__)))  # 大括号内即把该文件路径变为绝对路径
execute(["scrapy", 'crawl', 'movieSpider', "-o", "items.json"])

    至此我们的项目文件结构如下:

请添加图片描述

6.运行效果截图

红色的字体是正常的,项目运行信息就在这里面显示,不要认为红色就是报错了哈!!!!
请添加图片描述
请添加图片描述

四、Scrapy扩展

    相比于自己编写的爬虫代码,Scrapy结构更加清晰,爬取速度也更快,所以我们一般用于爬取数据量较大的大型网站。但需要注意的是这类网站的反爬机制一般很完善,这就需要我们进一步伪装自己的爬虫,下面我们一起学习一下如何自定义中间件。

1.设置随机请求头

    很多网页通过请求头判断是不是爬虫在访问,为了避免被服务器检测,我们可以自定义一个随机请求头的中间件。方法如下:

  • 在middlewares.py文件下加入如下代码:
from fake_useragent import UserAgent
# 自定义随机请求头的中间件
class RandomHeaderMiddleware(object):
    def __init__(self, crawler):
        self.ua = UserAgent()  # 随机请求头对象
        # 如果配置文件中不存在就使用默认的Google Chrome请求头
        self.type = crawler.settings.get("RANDOM_UA_TYPE", "chrome")

    @classmethod
    def from_crawler(cls, crawler):
        # 返回cls()实例对象
        return cls(crawler)

    # 发送网络请求时调用该方法
    def process_request(self, request, spider):
        # 设置随机生成的请求头
        request.headers.setdefault('User-Agent', getattr(self.ua, self.type))
  • 在settings.py加入如下代码
DOWNLOADER_MIDDLEWARES = {
   'scrapyTest.middlewares.RandomHeaderMiddleware': 400,

   # 'scrapyTest.middlewares.ScrapytestDownloaderMiddleware': 543,    # 默认中间件
}
RANDOM_UA_TYPE = "random"     # 设置请求头为随机,还可以是ie等
  • 使用随机请求头,编写一个测试爬虫
# -*- coding: utf-8 -*-
# @Time : 2021/9/17 19:29
# @Author : KK
# @File : headerSpider.py
# @Software: PyCharm 
# -*- coding: utf-8 -*-
import scrapy


class HeaderspiderSpider(scrapy.Spider):
    name = 'headerSpider'
    allowed_domains = ['www.baidu.com']
    start_urls = ['https://www.baidu.com/']

    def start_requests(self):
        # 设置爬取目标的地址
        urls = [
            'https://www.baidu.com/s?wd=%E7%99%BE%E5%BA%A6%E7%BF%BB%E8%AF%91&rsv_spt=1&rsv_iqid=0xa003c5490000a924&issp=1&f=3&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=02003390_8_hao_pg&rsv_enter=1&rsv_dl=ts_0&rsv_sug3=6&rsv_sug1=4&rsv_sug7=100&rsv_sug2=1&rsv_btype=i&prefixsug=baidu&rsp=0&inputT=3099&rsv_sug4=4027',
            'https://www.baidu.com/s?wd=%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE&rsv_spt=1&rsv_iqid=0xa003c5490000a924&issp=1&f=3&rsv_bp=1&rsv_idx=2&ie=utf-8&rqlang=cn&tn=02003390_8_hao_pg&rsv_enter=1&rsv_dl=ts_0&oq=%25E7%2599%25BE%25E5%25BA%25A6%25E7%25BF%25BB%25E8%25AF%2591&rsv_btype=t&inputT=1785&rsv_t=3f35TF2zzN98wRnfouxPtnf716zp3A%2BioNiu0jx9pBMEFCK0vPoF30WZV5cHOvfGVehfgGanCIE&rsv_sug3=9&rsv_sug1=7&rsv_sug7=100&rsv_pq=9a88ba610000b66d&rsv_sug2=1&prefixsug=%25E7%2599%25BE%25E5%25BA%25A6&rsp=0&rsv_sug4=3622',
        ]

        # 获取所有地址,有几个地址发送几次请求
        for url in urls:
            # 发送网络请求
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        # 打印每次网络请求的请求头信息
        print('请求信息为:', response.request.headers.get('User-Agent'))
        pass

  • 测试结果

这里你可能会报错,请参考我的bug记录!!
bug记录请添加图片描述

2.设置cookies

    cookies代表用户信息,当我们需要爬取登陆后的网页信息时,可以将其存储起来,这样就可以在下次使用的时候直接获取而不需要再次登录。在Scrapy中使用方法如下:

  • 在middlewares.py文件下加入如下代码:
# 自定义cookies中间件
class CookiesdemoMiddleware(object):
    # 初始化
    def __init__(self, cookies_str):
        self.cookies_str = cookies_str

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            # 获取配置文件中的cookies信息
            cookies_str=crawler.settings.get('COOKIES_DEMO')
        )

    cookies = {}  # 保存格式化以后的cookies

    def process_request(self, request, spider):
        for cookie in self.cookies_str.split(';'):  # 通过;分割cookies字符串
            key, value = cookie.split('=', 1)  # 将key与值进行分割
            self.cookies.__setitem__(key, value)  # 将分割后的数据保存至字典中
        request.cookies = self.cookies  # 设置格式化以后的cookies
  • 在settings.py加入如下代码
DOWNLOADER_MIDDLEWARES = {
    # 启动自定义cookies中间件
    'cookiesDemo.middlewares.CookiesdemoMiddleware': 201,
    # 启动自定义随机请求头中间件
   'cookiesDemo.middlewares.RandomHeaderMiddleware':202,
    # 禁用默认生成的配置信息
   'cookiesDemo.middlewares.CookiesdemoDownloaderMiddleware': None,
}
RANDOM_UA_TYPE = "random"     # 设置请求头为随机,还可以是ie等
# 定义从浏览器中获取的Cookies
COOKIES_DEMO = '浏览器获取的cookies'
  • 使用同上!!省略

3.设置代理

    在第一弹中我们学习了如何在普通爬虫中使用代理ip,接下来我们在scrapy中使用代理ip。

  • 在middlewares.py文件下加入如下代码:
class IpRandomProxyMiddleware(object):
    # 定义有效的代理ip列表
    PROXIES = [
        '117.88.177.0:3000',
        '117.45.139.179:9006',
        '202.115.142.147:9200',
        '117.87.50.89:8118']

    # 发送网络请求时调用
    def process_request(self, request, spider):
        proxy = random.choice(self.PROXIES)  # 随机抽取代理ip
        request.meta['proxy'] = 'http://' + proxy  # 设置网络请求所使用的代理ip
  • 在settings.py加入如下代码
 # 激活自定义随机获取代理ip的中间件
    'scrapyTest.middlewares.IpRandomProxyMiddleware': 203,
    # 禁用默认生成的配置信息
    'scrapyTest.middlewares.CookiesdemoDownloaderMiddleware': None,
  • 使用同上!!省略

4.下载文件

    Scrapy框架提供了专门处理下载的管道-pipeline,其中包括文件管道Files Pipeline和图像管Imges Pipeline。
    因为目前还没有使用过这种方式,先不做介绍,给大家推荐一篇文章,个人认为写的很详细了。

原文链接

五、总结

    写完文章又是晚上九点了,全程都是一边写一边调试代码,所有的代码都是在自己的环境跑通了才加上的,目的除了自己留下笔记,也为了和同样在学习爬虫的你一个参考。通过这篇文章你不仅可以学会Scrapy的基础使用,更有扩展内容,让你能熟练地使用这个框架!!

author: KK
time :2021年9月17日21:35:51
flag:5/30

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值