Scrapy爬取异步加载的数据


前言

当我们爬虫遇到懒加载的数据该怎么办呢,首先我们就会想到用selenium模拟人为滑动不断加载数据,最后再获取数据,但是selenium速度又太慢,那么使用selenium+scrapy就刚好可以解决这个问题,下面是一个使用scrapy抓取懒加载数据的一个小案例,代码和方法的不足,还请各位大牛指点一二!!!


Scrapy中间件

1 scrapy中间件的分类和作用

1.1 scrapy中间件的分类

Scrapy中间件可以分为以下几类:

  • 请求中间件(Request Middleware)
    请求中间件作用于发送给服务器的每个请求,可以用于对请求进行修改、添加请求头、设置代理等。主要的方法是process_request(request, spider)。如果一个中间件返回了一个Response对象,Scrapy将不再继续处理该请求,而是直接将该Response返回给爬虫。
  • 下载中间件(Downloader Middleware)
    下载中间件作用于接收到的每个响应,可以用于对响应进行修改、处理异常、设置代理等。主要的方法是process_response(request, response, spider)。类似于请求中间件,如果一个中间件返回了一个Response对象,Scrapy将不再继续处理该响应,而是直接将该Response返回给爬虫。
  • 异常中间件(Spider Middleware)
    异常中间件用于处理请求和响应过程中产生的异常,可以对异常进行自定义处理。主要的方法是process_exception(request, exception, spider)。

2 scrapy中间件的作用

  • crapy中间件的主要作用是在请求和响应的处理过程中进行拦截和处理,对爬虫进行全局性的控制和干预。中间件可以用于实现诸如请求和响应处理、代理设置、用户代理(User-Agent)随机切换、Cookie处理、错误处理、自定义重试逻辑等功能。
  • 但在scrapy默认的情况下 两种中间件都在middlewares.py一个文件中
  • 爬虫中间件使用方法和下载中间件相同,常用下载中间件

2 下载中间件的使用方法:

process_request(request, spider):

  • 作用
    • 在发送请求之前对请求进行预处理,允许你修改请求或添加自定义的请求头信息等
  • 参数
    • request:即将发送的请求对象。
    • spider:爬虫实例,可以在中间件中访问爬虫的属性和方法。
  • 返回值
    • 返回一个None,表示继续处理该请求,将其发送给服务器。
    • 返回一个Response对象,表示中间件处理了请求,并将这个自定义的响应返回给爬虫,不会再继续发送该请求。
    • 返回一个Request对象,表示中间件处理了请求,并返回一个新的请求对象给爬虫,Scrapy会继续处理这个新的请求。

process_response(request, response, spider):

  • 作用
    • 在接收到响应后对响应进行预处理,允许你修改响应内容、处理异常情况等。
  • 参数
    • request:对应的请求对象。
    • response:接收到的响应对象。
    • spider:爬虫实例,可以在中间件中访问爬虫的属性和方法。
  • 返回值
    • 返回一个Response对象,表示中间件处理了响应,并将这个自定义的响应返回给爬虫,不会再继续处理该响应。
    • 返回一个Request对象,表示中间件处理了响应,并返回一个新的请求对象给爬虫,Scrapy会继续处理这个新的请求。
    • 返回一个None,表示继续处理该响应,将其返回给爬虫。

process_exception(request, exception, spider):

  • 作用

    • 在请求或响应处理过程中产生异常时进行处理,允许你对异常进行自定义处理或进行错误重试等操作。
  • 参数

    • request:产生异常的请求对象。
    • exception:产生的异常对象。
    • spider:爬虫实例,可以在中间件中访问爬虫的属性和方法。
  • 返回值

    • 返回一个Request对象,表示中间件处理了异常,并返回一个新的请求对象给爬虫,Scrapy会继续处理这个新的请求。
    • 返回一个None,表示继续处理异常,Scrapy将按照默认方式处理异常。
  • 在这些方法中,你可以根据需求对请求和响应进行修改,处理异常情况,实现自定义的重试逻辑等。同时,你还可以利用spider参数访问爬虫的属性和方法,以便更好地与爬虫进行交互和控制。如:spider.name

  • 需要注意的是,这些方法在中间件中的执行顺序是由它们在DOWNLOADER_MIDDLEWARES设置项中的优先级决定的。优先级数值越小,优先级越高,即优先执行。因此,在实现自定义的下载中间件时,你可以根据功能的需要和依赖关系,合理设置中间件的优先级。

3 抓取某易新闻

3.1 抓取前分析

抓取国内、国际两大板块的数据

  • 分析
    国内、国际两大板块的数据是动态加载的,并不是跟着当前的请求一起返回的

  • 解决方法
    1、通过selenium配合爬虫抓取页面提取数据
    2、找到加载动态数据的url地址 通过爬虫进行抓取

3.2 代码配置

  • 配置settings.py文件
# Scrapy settings for wangyi project
BOT_NAME = 'wangyi'

SPIDER_MODULES = ['wangyi.spiders']
NEWSPIDER_MODULE = 'wangyi.spiders'

# 默认请求头
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36'

# 用于更换随机请求头
USER_AGENTS_LIST = [
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
"Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
"Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
"Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
"Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
"Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5" ]

LOG_LEVEL = 'ERROR'
ROBOTSTXT_OBEY = False

DOWNLOADER_MIDDLEWARES = {
   'wangyi.middlewares.WangyiDownloaderMiddleware': 543,
}
ITEM_PIPELINES = {
   'wangyi.pipelines.WangyiPipeline': 300,
}
  • 爬虫代码wy.py
import scrapy
from selenium import webdriver
from selenium.webdriver import ChromeOptions
from selenium.webdriver.chrome.options import Options
from wangyi.items import WangyiItem

class WySpider(scrapy.Spider):
    name = "wy"
    # allowed_domains = ["抓取的网站域名"]
    start_urls = ["抓取网站的起始url"]
    li_index = [1, 2]  # 索引为1 和2 的俩 为国内和国际板块的url
    page_url = []  # 存放所需要板块的url
    # 隐藏浏览器界面
    chrome_option = Options()
    chrome_option.add_argument('--headless')
    chrome_option.add_argument('--disable-gpu')
    # 防止检测
    chrome_option.add_experimental_option('excludeSwitches', ['enable-automation'])
    chrome_option.add_experimental_option('useAutomationExtension', False)
    # 导入配置
    driver = webdriver.Chrome(options=chrome_option)
    
    def parse(self, response, **kwargs):
        # 抓取国内和国际板块的数据
        # 返回了所有板块的url
        url_list = response.xpath('/html/body/div/div[3]/div[2]/div[2]/div/ul/li/a/@href').extract()
        # print(url_list)
        for i in range(len(url_list)):
            if i in self.li_index:
                url = url_list[i]
                # 把板块对应的url存放起来
                self.page_url.append(url)
                yield scrapy.Request(url, callback=self.parse_detail)

    # 对于板块请求后的处理
    def parse_detail(self, response):
        url_list = response.xpath('/html/body/div/div[3]/div[3]/div[1]/div[1]/div/ul/li/div/div/div/div[1]/h3/a/@href').extract()
        for url in url_list:
            yield scrapy.Request(url, callback=self.parse_detail_con)

    def parse_detail_con(self, response):
        items = WangyiItem()
        title = response.xpath('//*[@id="container"]/div[1]/h1/text()').extract_first()
        con = response.xpath('//*[@id="content"]/div[2]/p/text()').extract()[1:]
        items['title'] = title
        items['con'] = con
        print(items)
        yield items
  • Middlewares.py
import time
from scrapy.http import HtmlResponse
from wangyi.settings import USER_AGENTS_LIST
import random

class WangyiSpiderMiddleware:
	···
class WangyiDownloaderMiddleware:
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the downloader middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request, spider):
        ua = random.choice(USER_AGENTS_LIST)  # 每次随机一个请求头
        request.headers['User-Agent'] = ua  # 设置请求头
        return None

    def process_response(self, request, response, spider):
        driver = spider.driver  # 获取爬虫中的driver属性
        # 如果是板块的url我们就进行抓取
        if request.url in spider.page_url:
            driver.get(request.url)  # 使用selenium抓取刚才的请求
            # 滚动条滚动到最下方
            driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')
            time.sleep(1)
            # 拖动两次
            driver.execute_script('window.scrollTo(0, document.body.scrollHeight)')
            time.sleep(1)
            text = driver.page_source
            # 构造HTML响应 篡改响应
            return HtmlResponse(url=request.url, body=text, request=request, encoding='utf-8')
        return response

    def process_exception(self, request, exception, spider):
        # Called when a download handler or a process_request()
        # (from other downloader middleware) raises an exception.

        # Must either:
        # - return None: continue processing this exception
        # - return a Response object: stops process_exception() chain
        # - return a Request object: stops process_exception() chain
        print('process_exception')


    def spider_opened(self, spider):
        spider.logger.info("Spider opened: %s" % spider.name)

3.3 打印结果

在这里插入图片描述

总结

本文介绍了Scrapy中间件的使用方法,主要涵盖了下载中间件的详细说明。下载中间件是Scrapy中的一类中间件,用于在请求和响应的处理过程中进行拦截和处理。主要的三个方法是process_request、process_response和process_exception。

  1. process_request(request,
    spider)方法用于在发送请求之前对请求进行预处理,允许你修改请求或添加自定义的请求头信息等。可以返回一个None,表示继续处理该请求,将其发送给服务器;或返回一个Response对象,表示中间件处理了请求,并将自定义的响应返回给爬虫,不再继续发送该请求;或返回一个Request对象,表示中间件处理了请求,并返回一个新的请求对象给爬虫,Scrapy会继续处理这个新的请求。

  2. process_response(request, response,
    spider)方法用于在接收到响应后对响应进行预处理,允许你修改响应内容、处理异常情况等。可以返回一个Response对象,表示中间件处理了响应,并将自定义的响应返回给爬虫,不再继续处理该响应;或返回一个Request对象,表示中间件处理了响应,并返回一个新的请求对象给爬虫,Scrapy会继续处理这个新的请求;或返回一个None,表示继续处理该响应,将其返回给爬虫。

  3. process_exception(request, exception,
    spider)方法用于处理请求或响应处理过程中产生的异常,允许你对异常进行自定义处理或进行错误重试等操作。可以返回一个Request对象,表示中间件处理了异常,并返回一个新的请求对象给爬虫,Scrapy会继续处理这个新的请求;或返回一个None,表示继续处理异常,Scrapy将按照默认方式处理异常。

本文还提供了一个使用Scrapy抓取懒加载数据的小案例,通过配合Selenium和Scrapy实现了动态加载数据的抓取。案例中的爬虫通过下载中间件对板块URL进行抓取,使用Selenium模拟浏览器滚动实现动态加载,然后将抓取到的数据返回给爬虫进行处理。感兴趣的小伙伴可以自行配置管道进行保存。

总的来说,下载中间件是Scrapy强大灵活的功能之一,通过定制中间件,可以实现对请求和响应的全局性处理,提高爬虫的灵活性和可靠性。同时,也可以配合其他工具如Selenium等,实现对动态加载数据的抓取。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值