爬虫 — Scrapy 框架(二)

news2024/12/25 15:54:14

目录

  • 一、Scrapy 核心文件
    • 1、spider
    • 2、Request
    • 3、构造 post 请求
    • 4、response
  • 二、案例
  • 三、Scrapy 下载中间件
    • 1、执行顺序
    • 2、使用方法
    • 3、Download Middlewares 默认方法
    • 4、代理 IP
      • 4.1、工作原理
      • 4.2、分类
      • 4.3、查看 IP 地址
      • 4.4、常用代理
  • 四、Scrapy 爬虫中间件
  • 五、Scrapy 下载图片
  • 六、Scrapy CrawlSpider 全站爬取
    • 1、LinkExtractors 链接提取器
    • 2、Rule 规则类
    • 3、使用步骤
  • 七、Scrapy 模拟登录
  • 八、作业

一、Scrapy 核心文件

1、spider

  • 根据 url 生成 request 对象并且指定对应的方法处理 Response,第一个 request 请求,通过起始 url 产生的。
  • 解析数据,返回的 item 实例或者 request 实例。
  • 在解析方法中,通常使用 Selectors(css, lxml) 提取数据。
  • 返回管道完成数据的存储。

2、Request

在这里插入图片描述

url:请求 url,必须以字符串形式提供。

callback:响应返回的回调函数,默认是调用 parse 方法。

method:HTTP 请求方式,默认是 get 请求。

headers:请求头信息,一般在 settings.py 文件中设置。

body:data 可以采用 body 传递(使用较少)。

cookies:传递 cookies,单独设置 cookie。

meta:传参,字典形式的额外元数据,可以在请求之间传递数据,例如在不同回调之间传递参数。

encoding:响应的编码方式。

priority:设置调用请求的优先级,数值越大,优先级越高。

dont_filter:对该请求进行去重处理,默认为 False 是过滤,True 是不过滤。

errback:处理请求错误的回调函数,通常用于处理请求超时或其它错误情况。

flags:请求的标志位,可以通过添加标志位来修改请求的默认行为。

cb_kwargs:传参,字典形式的回调参数,可以在回调函数中访问这些参数。

meta 和 cb_kwargs 传参区别

meta

是用于在请求过程中在不同的中间件和回调函数之间传递数据。

它可以存储和传递更多的信息,并且可以在整个请求过程中的多个环节中使用。

是请求对象的属性,可以在整个请求过程中的多个中间件和回调函数之间共享和传递数据。

# meta
# 传值
yield scrapy.Request(url, callback=self.parse_page, meta={'category': 'books'})
# 取值
def parse_page(self, response):
    category = response.meta['category']
    print("Category:", category)

cb_kwargs

主要用于在请求之间传递数据给回调函数。它是通过在使用 scrapy.Request 创建请求时传递额外的参数来实现的。

是针对每个请求的回调函数的参数进行设置,它的作用范围仅限于当前请求与回调函数之间。

# cb_kwargs
# 传值
yield scrapy.Request(url, callback=self.parse_page, cb_kwargs={'title': 'Page Title'})
# 取值
def parse_page(self, response, title):
    print("Page Title:", title)

3、构造 post 请求

import scrapy # 导入 Scrapy 库,用于构建爬虫

# 定义 FanyiSpider 类,继承自 scrapy.Spider 类
class FanyiSpider(scrapy.Spider):
    # 爬虫的名称
    name = 'fanyi'
    # 允许爬取的域名
    allowed_domains = ['fanyi.so.com']
    # 起始 url
    start_urls = ['https://fanyi.so.com/index/search?eng=1&validate=&ignore_trans=0&query=hello']
    # post 请求携带参数
    data = {
        'eng': '1',
        'ignore_trans': '0',
        'query': 'hello',
    }

    # 定义 start_requests 方法,用于生成初始请求,重写的父类方法
    def start_requests(self):
        # 使用 FormRequest 发送 post 请求(FormRequest 类是继承 Request 类)
        yield scrapy.FormRequest(self.start_urls[0], callback=self.parse, formdata=self.data)

    # 解析函数,处理响应并提取数据
    def parse(self, response):
        # 打印响应数据中的翻译结果
        print(response.json()['data']['fanyi'])
        # 输入翻译内容
        query = input("请输入翻译内容")
        # post 请求携带参数
        data = {
            'eng': '1',
            'ignore_trans': '0',
            'query': query,
        }
        # 发送新的 post 请求并将响应交给 parse 方法处理
        yield scrapy.FormRequest(self.start_urls[0], callback=self.parse, formdata=data)

4、response

一般都是由 scrapy 自动构建。

response.request.headers:获取请求头的信息

response.status:获取状态码

response.body:获取字节数据

response.text:获取文本数据

response.json:获取 json 格式的数据

response.xpath/css:解析数据

response.meta.get(key):获取传递参数

二、案例

目标网站: https://careers.tencent.com/search.html?pcid=40001
需求:翻页获取前10页数据,爬取首页的职位名字-详情页的工作职责和工作要求

# start.py
from scrapy import cmdline  # 使用 cmdline 模块来执行命令行命令

# 使用 Scrapy 执行名为 spider 的爬虫
cmdline.execute('scrapy crawl spider'.split())
# spider.py
import scrapy  # 导入 scrapy 库,用于构建爬虫
import json  # 导入 json 库,用于处理 JSON 数据
import datetime  # 导入 datetime 库,用于获取当前时间
from Tencent_Job.items import TencentJobItem  # 导入自定义的数据项类 TencentJobItem

# 定义 SpiderSpider 类,继承自 scrapy.Spider 类
class SpiderSpider(scrapy.Spider):
    # 爬虫的名称
    name = 'spider'
    # 允许爬取的域名
    allowed_domains = ['careers.tencent.com']
    # 获取当前时间
    current_time = datetime.datetime.now()
    # 将当前时间转换为时间戳字符串
    post_time = str(int(current_time.timestamp()))
    # 初始页码
    page = 1
    # 链接 url
    base_url = 'https://careers.tencent.com/tencentcareer/api/post/Query?timestamp={}&countryId=&cityId=&bgIds=&productId=&categoryId=40001001,40001002,40001003,40001004,40001005,40001006&parentCategoryId=&attrId=&keyword=&pageIndex={}&pageSize=10&language=zh-cn&area='
    # 起始 url
    start_urls = [base_url.format(post_time,page)]

    # 定义解析函数,用于解析响应数据
    def parse(self, response):
        # 从响应中获取数据列表
        datas = json.loads(response.text)['Data']['Posts']
        # 遍历数据列表
        for data in datas:
            # 职位名字
            title = data['RecruitPostName']
            # PostId
            post_id = data['PostId']
            # 详情页 url
            post_url = 'https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=' + self.post_time + '&postId=' + post_id + '&language=zh-cn'
            # 发送请求并指定回调函数以及传递的参数
            yield scrapy.Request(post_url, callback=self.detail_pages, cb_kwargs={'title': title})

        # 判断页码
        if self.page < 10:
            # 页码
            self.page = self.page + 1
            # 发送请求并指定回调函数
            yield scrapy.Request(self.base_url.format(self.post_time,self.page), callback=self.parse)

    # 定义职位详情页解析函数
    def detail_pages(self, response, **title):
        # 创建爬取的数据项
        item = TencentJobItem()
        # 职位名字
        item['title'] = title['title']
        # 工作职责
        item['responsibility'] = json.loads(response.text)['Data']['Responsibility']
        # 工作要求
        item['requirement'] = json.loads(response.text)['Data']['Requirement']
        # 返回数据项
        yield item
# items.py
import scrapy  # 导入Scrapy库,用于构建爬虫

# 自定义的Item类,用于存储爬取的数据
class TencentJobItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    # 职位名字
    title = scrapy.Field()
    # 工作职责
    responsibility = scrapy.Field()
    # 工作要求
    requirement = scrapy.Field()
# pipelines.py
from itemadapter import ItemAdapter  # 导入 itemadapter 库,用于适配数据项
import csv  # 导入 csv 库,用于处理 CSV 文件

# 定义 TencentJobPipeline 类
class TencentJobPipeline:
    # 构造函数,初始化操作
    def __init__(self):
        # 打开 CSV 文件,以追加模式写入,指定编码为 utf-8-sig,确保中文不乱码,设置换行符为空
        self.f = open("腾讯.csv", "a", encoding='utf-8-sig', newline="")
        # 定义 CSV 文件的字段名
        self.fieldnames = ['title', 'responsibility', 'requirement']
        # 创建 DictWriter 对象,用于写入 CSV 文件
        self.writer = csv.DictWriter(self.f, fieldnames=self.fieldnames)
        # 写入表头
        self.writer.writeheader()

    # 数据处理函数,用于处理爬取到的数据项
    def process_item(self, item, spider):
        # 写入数据
        self.writer.writerow(item)
        # 返回数据项
        return item
# settings.py
# 不打印日志信息
LOG_LEVEL = 'WARNING'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
}
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'Tencent_Job.pipelines.TencentJobPipeline': 300,
}

三、Scrapy 下载中间件

在 Scrapy 中,下载中间件(Download Middleware)是一种机制,用于在发送请求和获取响应之间对请求和响应进行处理和操作。下载中间件允许在整个请求-响应周期中拦截、修改和生成请求,以及拦截、修改和生成响应。

下载中间件主要用于以下几个方面:

  • 请求处理:下载中间件可以拦截并修改将要发送的请求。可以在请求被发送到服务器之前对其进行预处理,例如添加自定义的请求头、修改请求参数或 url 等。
  • 代理和用户代理设置:通过下载中间件,可以轻松地为请求设置代理服务器,以及设置自定义的用户代理(User-Agent)。这对于处理需要使用代理或模拟不同浏览器的场景非常有用。
  • 请求过滤和调度优化:下载中间件可以用于对请求进行过滤和调度优化。可以根据特定的规则或条件过滤掉某些请求,或者对请求进行调度优化,例如动态地设置请求的优先级、延迟等。
  • 响应处理:下载中间件可以拦截并修改从服务器返回的响应。可以对响应进行预处理、提取数据、添加额外的数据等。还可以根据响应的状态码进行处理,例如重试、错误处理等。

1、执行顺序

要使用下载中间件,需要在 Scrapy 项目的设置文件(settings.py)中进行配置。

可以配置多个下载中间件,并按顺序定义它们的优先级。

Scrapy 会按照配置的顺序依次调用下载中间件,直到最后一个中间件完成处理或返回响应。

  • 中间件是多个,数字越小,越靠近引擎,数字越大,越靠近下载器。

  • 处理请求时,数字越小,优先级越高,

  • 处理响应时,数字越大,优先级越高。

2、使用方法

编写一个 Download Middlewares,定义一个类,然后在 settings 中开启。

# middlewares.py
# 自定义随机生成 UA 的中间件
class RandomUserAgentMiddewar:
    def __init__(self):
        # 初始化 user_agent 列表,包含多个浏览器的 User-Agent 字符串
        self.user_agent = [
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36',
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36',
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36',
        ]

    # 重写 process_request 方法
    # 处理请求,引擎发送 request 请求到下载器之前,会调用这个方法。
    # 启用中间件,要去 settigns.py 文件中开启。
    def process_request(self, request, spider):
        # 在请求头中设置随机选择的 User-Agent
        request.headers['user-agent'] = random.choice(self.user_agent)
# settings.py
# Enable or disable downloader middlewares
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
    # 'middle.middlewares.MiddleDownloaderMiddleware': 543,
    'middle.middlewares.RandomUserAgentMiddewar': 543,
}

3、Download Middlewares 默认方法

# middlewares.py
class TencentJobDownloaderMiddleware:
    
    # 对请求进行处理和修改
    # 处理请求,引擎发送 request 请求到下载器之前,会调用这个方法
    # 启用中间件,要去 settigns.py 文件中开启
    def process_request(self, request, spider):
        # request:请求对象,spider:爬虫对象
        
        # Called for each request that goes through the downloader
        # middleware.
		
        # 按照需求和处理逻辑,返回以下几种结果之一
        # Must either:
        # 会继续处理下一个请求,直到下载把 request 得到 response 才会结束
        # - return None: continue processing this request
        # 不继续处理请求,会进入到最后一个中间件,调用 process_response,直接处理响应对象
        # - or return a Response object
        # 会重新进入到第一个中间件 process_request 重新处理请求
        # - or return a Request object
        # 触发异常
        # - or raise IgnoreRequest: process_exception() methods of
        #   installed downloader middleware will be called
        return None
    
    # 对响应进行处理和修改
    # 每个响应经过下载中间件时都会调用该方法
    def process_response(self, request, response, spider):
        # request:请求对象,response:响应对象,spider:爬虫对象
        
        # Called with the response returned from the downloader.

        # 按照需求和处理逻辑,返回以下几种结果之一
        # Must either;
        # 表示对响应进行处理和修改后,将修改后的响应返回,后续的下载中间件和爬虫将使用该修改后的响应进行进一步处理
        # - return a Response object
        # 表示对响应进行处理后,生成一个新的请求对象,并将其返回,该新的请求对象将被发送到下载器进行处理
        # - return a Request object
        # 表示忽略该响应,将不再调用其它下载中间件的 process_response 方法,并继续执行已安装的其它下载中间件的 process_exception 方法。
        # - or raise IgnoreRequest
        return response
    
    # 处理请求过程中的异常
    def process_exception(self, request, exception, spider):
        # request:请求对象,exception:引发的异常对象,spider:爬虫对象
        
        # Called when a download handler or a process_request()
        # (from other downloader middleware) raises an exception.

        # 按照需求和处理逻辑,返回以下几种结果之一
        # Must either:
        # 表示继续处理当前的异常,即继续执行后续的下载中间件的 process_exception 方法
        # - return None: continue processing this exception
        # 表示停止处理异常,并将该响应对象作为最终的结果返回,后续的下载中间件和爬虫将使用该响应对象进行进一步处理
        # - return a Response object: stops process_exception() chain
        # 表示停止处理异常,并将该请求对象作为最终的结果返回,该新的请求对象将被重新发送到下载器进行处理
        # - return a Request object: stops process_exception() chain
        pass

4、代理 IP

代理 IP(Proxy IP)是一种通过中间服务器转发网络请求的方式,隐藏真实客户端的 IP 地址并代表客户端进行网络通信。使用代理 IP 可以实现一些特定的目标,例如绕过网络封锁、提高网络访问速度、隐藏真实身份等。

4.1、工作原理

客户端发送网络请求时,将请求发送给代理服务器而不是直接发送给目标服务器。

代理服务器接收到请求后,替代客户端向目标服务器发送请求,并将响应返回给客户端。

目标服务器将响应发送给代理服务器,代理服务器再将响应转发给客户端。

4.2、分类

透明代理(Transparent Proxy)

代理服务器会将客户端的真实 IP 地址传递给目标服务器,目标服务器可以直接获得客户端的真实 IP。

匿名代理(Anonymous Proxy)

代理服务器会隐藏客户端的真实 IP 地址,并使用自己的 IP 地址作为代理发送请求,但目标服务器仍然可以检测到使用了代理。

高匿代理(Elite Proxy)

代理服务器完全隐藏客户端的真实 IP 地址,并使用自己的 IP 地址作为代理发送请求,目标服务器无法检测到使用了代理。

4.3、查看 IP 地址

在终端输入 ipconfig 命令——内网 IP,私有地址

在浏览器地址栏输入 ipip.net——外网,上网的 IP

4.4、常用代理

快代理、豌豆代理

四、Scrapy 爬虫中间件

爬虫中间件(Spider Middleware)是 Scrapy 中的一种中间件,位于引擎和爬虫之间,主要处理发生给爬虫的响应和 spider 输出结果。中间件可以是多个,数字越小,越靠近引擎,数字越大,越靠近爬虫。

使用爬虫中间件,需要在 settings.py 文件里开启爬虫中间件。

# settings.py
# Enable or disable spider middlewares
# See https://docs.scrapy.org/en/latest/topics/spider-middleware.html
SPIDER_MIDDLEWARES = {
 'myproject.middlewares.CustomSpiderMiddleware': 543,
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware': None,
}

五、Scrapy 下载图片

Scrapy 为下载 item 中包含的文件提供了一个可重用的 item pipelines,这些 pipeline 有些共同的方法和结构,常用的有 Files Pipline 和 Images Pipeline。

Images Pipeline 使用步骤

1、先创建项目。

在终端输入命令

scrapy startproject BiaoQingBao

cd BiaoQingBao

scrapy genspider images fabiaoqing.com

2、在 settings.py 文件中修改一些参数。

# settings.py
# 不打印日志信息
LOG_LEVEL = 'WARNING'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
}

3、新建一个 start.py 用来运行代码。

# start.py
# 使用 cmdline 模块来执行命令行命令
from scrapy import cmdline

# 使用 Scrapy 执行名为 images 的爬虫
cmdline.execute('scrapy crawl images'.split())

4、在 items.py 定义字段。

# items.py
import scrapy # 导入 Scrapy 库,用于构建爬虫

class BiaoqingbaoItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    # 图片链接
    img_url = scrapy.Field()
    # 图片标题
    img_title = scrapy.Field()
    pass

5、在 images.py 里做数据解析。

# images.py
import scrapy  # 导入 Scrapy 库,用于构建爬虫
import re  # 导入 re 模块,用于进行正则表达式匹配
from BiaoQingBao.items import BiaoqingbaoItem  # 导入自定义的 Item 类,用于存储爬取的数据

class SpiderSpider(scrapy.Spider):
    # 爬虫的名称
    name = 'images'
    # 允许爬取的域名
    # allowed_domains = ['fabiaoqing.com']
    # 链接 url
    base_url = 'https://fabiaoqing.com/biaoqing/lists/page/{}.html'
    # 页码
    page = 1
    # 起始 url
    start_urls = [base_url.format(page)]

    def parse(self, response):
        # 解析数据,找所有的 img 标签
        images = response.xpath('//img[@class="ui image lazy"]')
        # 遍历获取每一个 img 标签,解析里面的图片 url 以及标题
        for img in images:
            # 创建一个 MyScrapyItem 实例,用于存储爬取的数据
            item = BiaoqingbaoItem()
            # 图片 url
            item['img_url'] = img.xpath('@data-original').get()
            # 标题
            title = img.xpath('@title').get()
            # 正则表达式替换标题特殊字符
            item['img_title'] = re.sub(r'[?/\\<>*:(), ]', '', title)
            # 返回 item,将其传递给引擎
            yield item
            
        # 进行翻页处理
        if self.page <= 10:
            self.page += 1
            # 获取数据
            yield scrapy.Request(self.base_url.format(self.page), callback=self.parse)

6、如果爬取的速度过快,会被服务器识别是一个程序,可以设置一下爬取的速度。

在 settings.py 文件里找到以下代码,取消注释。

# settings.py
# Configure a delay for requests for the same website (default: 0)
# See https://docs.scrapy.org/en/latest/topics/settings.html#download-delay
# See also autothrottle settings and docs
# 设置爬取时间
DOWNLOAD_DELAY = 0.5

7、在 pipelines.py 里做下载图片并处理相关的请求。

# pipelines.py
import scrapy  # 导入 Scrapy 库,用于构建爬虫
from itemadapter import ItemAdapter  # 导入 itemadapter 模块中的 ItemAdapter 类,用于简化和处理爬虫中的数据项
from scrapy.pipelines.images import ImagesPipeline  # 导入 scrapy.pipelines.images 模块中的 ImagesPipeline 类,用于处理爬取的图片数据

# 定义 BiaoqingbaoPipeline 类,继承自 ImagesPipeline 类
class BiaoqingbaoPipeline(ImagesPipeline):
    # def process_item(self, item, spider):
    #     return item
    # 专门下载图片的方法
    def get_media_requests(self, item, info):
        # 获取图片 url
        img_url = item['img_url']
        # 发起图片下载请求
        yield scrapy.Request(img_url)

8、在 settings.py 中指定保存的路径并开启管道。

# settings.py
# 指定保存的路径
IMAGES_STORE = 'F:\Scrapy\BiaoQingBao\images'
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   'BiaoQingBao.pipelines.BiaoqingbaoPipeline': 300,
}

在 start.py 运行代码

WARNING: File (code: 403): Error downloading file from <GET https://img.soutula.com/large/ceeb653ely8heu3ipe30zg20af0dw4pp.gif> referred in

出现错误 403,说明被服务器识别出是爬虫程序了。

保存图片时出现反爬,检查图片的来源。

9、修改 pipelines.py 文件,携带请求头。

# pipelines.py
import scrapy  # 导入 Scrapy 库,用于构建爬虫
from itemadapter import ItemAdapter  # 导入 itemadapter 模块中的 ItemAdapter 类,用于简化和处理爬虫中的数据项
from scrapy.pipelines.images import ImagesPipeline  # 导入 scrapy.pipelines.images 模块中的 ImagesPipeline 类,用于处理爬取的图片数据

# 定义 BiaoqingbaoPipeline 类,继承自 ImagesPipeline 类
class BiaoqingbaoPipeline(ImagesPipeline):
    # def process_item(self, item, spider):
    #     return item
    # 请求头
    head = {
        'Referer': 'https://fabiaoqing.com/'
    }
    # 专门下载图片的方法
    def get_media_requests(self, item, info):
        # 获取图片 url
        img_url = item['img_url']
        # 发起图片下载请求
        yield scrapy.Request(img_url, headers=self.head)

10、保存图片的缺点是,文件名不方便看,需要使用 file_path 重新给图片命名。

# pipelines.py
import scrapy  # 导入 Scrapy 库,用于构建爬虫
from itemadapter import ItemAdapter  # 导入 itemadapter 模块中的 ItemAdapter 类,用于简化和处理爬虫中的数据项
from scrapy.pipelines.images import ImagesPipeline  # 导入 scrapy.pipelines.images 模块中的 ImagesPipeline 类,用于处理爬取的图片数据

# 定义 BiaoqingbaoPipeline 类,继承自 ImagesPipeline 类
class BiaoqingbaoPipeline(ImagesPipeline):
    # def process_item(self, item, spider):
    #     return item
    # 请求头
    head = {
        'Referer': 'https://fabiaoqing.com/'
    }
    # 专门下载图片的方法
    def get_media_requests(self, item, info):
        # 获取图片 url
        img_url = item['img_url']
        # 发起图片下载请求
        yield scrapy.Request(img_url, headers=self.head)

    # 重新给图片命名
    def file_path(self, request, response=None, info=None, *, item=None):
        # 名称
        img_name = item['img_title']
        # 指定保存文件夹
        return f'full/{img_name}.jpg'

注意:

错误信息:ImagesPipeline requires installing Pillow 4.0.0 or later

解决方案:pip install Pillow

六、Scrapy CrawlSpider 全站爬取

Scrapy 的 CrawlSpider 是一个高级的 Spider 类,用于处理常见的基于规则的爬取任务。CrawlSpider 扩展了 Scrapy 的 Spider 类,并提供了一些方便的功能,如自动跟进链接、规则匹配和提取等。是基于全站数据的爬取,将所有的数据爬取下来。

1、LinkExtractors 链接提取器

使用 LinkExtractors 可以不用自己提取想要的 url,然后发送请求。这些都可以交给 LinkExtractors,它会在所有页面中找到满足规则的 url,实现自动的爬取。

class scrapy.linkextractors.LinkExtractor(
 allow = (),
 deny = (),
 allow_domains = (),
 deny_domains = (),
 deny_extensions = None,
 restrict_xpaths = (),
 tags = ('a','area'),
 attrs = ('href'),
 canonicalize = True,
 unique = True,
 process_value = None
)

主要参数讲解

allow:允许的 url,所有满足这个正则表达式的 url 都会被提取。

deny:禁止的 url,所有满足这个正则表达式的 url 都不会被提取。

allow_domains:允许的域名,只有在这个里面指定的域名的 url 才会被提取。

deny_domains:禁止的域名,所有在这个里面指定的域名的 url 都不会被提取。

restrict_xpaths:严格的 xpath,和 allow 共同过滤链接。

2、Rule 规则类

定义爬虫的规则类。

class scrapy.spiders.Rule(
 link_extractor,
 callback = None,
 cb_kwargs = None,
 follow = None,
 process_links = None,
 process_request = None
)

主要参数讲解

link_extractor:一个 LinkExtractor 对象,用于定义爬取规则。

callback:满足这个规则的 url,应该要执行的回调函数。因为 CrawlSpider 使用了 parse 作为回调函数,因此不要覆盖 parse 作为回调函数自己的回调函数。

follow:指定根据该规则从 response 中提取的链接是否需要跟进。

process_links:从 link_extractor 中获取到链接后会传递给这个函数,用来过滤不需要爬取的链接。

3、使用步骤

1、创建项目。

scrapy startproject 项目名

cd 项目名

scrapy genspider -t crawl 爬虫文件名 域名

在这里插入图片描述

imgs_names.py 文件代码

# imgs_names.py
import scrapy  # 导入 Scrapy 库,用于构建爬虫
from scrapy.linkextractors import LinkExtractor  # 导入 scrapy.linkextractors 模块中的 LinkExtractor 类,用于从网页中提取 url 链接
from scrapy.spiders import CrawlSpider, Rule  # 导入 scrapy.spiders 模块中的 CrawlSpider 类和 Rule 类,用于实现基于规则的爬取方式和定义爬取规则

# 定义 ImgsNamesSpider 类,继承自 CrawlSpider 类
class ImgsNamesSpider(CrawlSpider):
    # 爬虫的名称
    name = 'imgs_names'
    # 允许爬取的域名
    allowed_domains = ['baidu.com']
    # 设置起始 url 列表
    start_urls = ['http://baidu.com/']

    # 创建一个规则对象
    rules = (
        # LinkExtractor:实例化了对象
        # allow:提取 url 的正则表达式
        # callback:回调函数,提取的 url 生成一个 requests 请求,请求发送给引擎,指定数据解析的方法
        # follow:指定根据规则从 requests 提取的链接是否继续提取
        Rule(LinkExtractor(allow=r'Items/'), callback='parse_item', follow=True),
    )

    # 解析方法,用于处理爬取到的响应数据
    def parse_item(self, response):
        # 创建空的数据项字典
        item = {}
        # 解析数据项的域名 id
        # item['domain_id'] = response.xpath('//input[@id="sid"]/@value').get()
        # 解析数据项的名称
        # item['name'] = response.xpath('//div[@id="name"]').get()
        # 解析数据项的描述
        # item['description'] = response.xpath('//div[@id="description"]').get()
        # 返回数据项
        return item

2、在 settings.py 文件中修改一些参数。

# settings.py
# 不打印日志信息
LOG_LEVEL = 'WARNING'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'
}
# 设置爬取时间
DOWNLOAD_DELAY = 0.5

3、新建一个 start.py 用来运行代码。

# start.py
# 使用 cmdline 模块来执行命令行命令
from scrapy import cmdline

# 使用 Scrapy 执行名为 imgs_names 的爬虫
cmdline.execute('scrapy crawl imgs_names'.split())

4、在 imgs_names.py 中获取全站数据。

# imgs_names.py
import scrapy  # 导入 Scrapy 库,用于构建爬虫
from scrapy.linkextractors import LinkExtractor  # 导入 scrapy.linkextractors 模块中的 LinkExtractor 类,用于从网页中提取 url 链接
from scrapy.spiders import CrawlSpider, Rule  # 导入 scrapy.spiders 模块中的 CrawlSpider 类和 Rule 类,用于实现基于规则的爬取方式和定义爬取规则

# 定义 ImgsNamesSpider 类,继承自 CrawlSpider 类
class ImgsNamesSpider(CrawlSpider):
    # 爬虫的名称
    name = 'imgs_names'
    # 允许爬取的域名
    # allowed_domains = ['fabiaoqing.com']
    # 设置起始 url 列表
    start_urls = ['https://fabiaoqing.com/biaoqing/lists/page/1.html']

    # 创建一个规则对象
    rules = (
        # 定义规则列表
        Rule(LinkExtractor(allow=r'/biaoqing/lists/page/\d+.html'), callback='parse_item', follow=True),
    )

    # 解析方法,用于处理爬取到的响应数据
    def parse_item(self, response):
        # 创建空的数据项字典
        item = {}
        # 直接获取整个页面图片标题,返回的数据类型是 list
        lst = response.xpath('//img[@class="ui image lazy"]/@title').getall()
        # 打印图片标题
        print(lst)
        # 返回数据项
        return item

七、Scrapy 模拟登录

1、创建项目。

scrapy startproject login

cd login

scrapy genspider example example.com

2、新建一个 start.py 用来运行代码。

# start.py
# 使用 cmdline 模块来执行命令行命令
from scrapy import cmdline

# 使用 Scrapy 执行名为 example 的爬虫
cmdline.execute('scrapy crawl example'.split())

3、在 spiders 文件夹下的 example.py 文件中编写代码。

# spiders/example.py
import scrapy  # 导入 Scrapy 库

class ExampleSpider(scrapy.Spider):
    name = 'example'  # 爬虫的名字,用于启动爬虫时的标识
    allowed_domains = ['qq.com']  # 允许爬取的域名
    start_urls = ['https://user.qzone.qq.com/1234567890']  # 起始 URL,爬虫会从这个 URL 开始爬取数据

    def parse(self, response):  # 解析函数,用于处理响应数据
        print(response.text)  # 打印响应的 HTML 文本内容

4、设置 cookie

4.1、方式一:直接携带 cookie 登录

在 settings.py 文件中修改一些参数;

# settings.py
# 不打印日志信息
LOG_LEVEL = 'WARNING'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# Override the default request headers:
DEFAULT_REQUEST_HEADERS = {
    'Cookie':'_qpsvr_localtk=0.6206021496459884; uin=o1234567890; skey=@kalEm2dQT; RK=2r/cU4cJEh; ptcz=8235ccaac75bae8201f47a835b216cd97d8f530349b6865815d301b699dec7c5; p_uin=o1234567890; pt4_token=VNY2rJ1KBn7v9iHp1eFMfaRrxmzuEogpZimR20ookP4_; p_skey=C03fYXYvuuIISyOKcJeMrd6nKddc0iNkh-9p-VkMg7U_; Loading=Yes; welcomeflash=1234567890_58028; qz_screen=1707x960; 1234567890_todaycount=0; 1234567890_totalcount=711; pgv_pvid=5798017608; pgv_info=ssid=s9552383352; QZ_FE_WEBP_SUPPORT=1; scstat=18; cpu_performance_v8=2; __Q_w_s__QZN_TodoMsgCnt=1',
    'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.3',
}
# Disable cookies (enabled by default)
COOKIES_ENABLED = False

注意:

在 settings.py 直接携带 cookie 是不生效,还需要将 COOKIES_ENABLED = False 注释取消掉。

4.2、方式二:在中间件设置 cookie

可以直接在 proces_request 的方法上直接修改,也可以自定义⼀个中间件类,但里面的方法名称不能随便修改。

# middlewares.py
# 自定义中间件
class CookieDownloaderMiddleware:
    def process_request(self, request, spider):
        # 把 cookie 添加到请求里面,格式要求必须是字典格式的数据
        cookie_str = "_qpsvr_localtk=0.6206021496459884; uin=o1234567890; skey=@kalEm2dQT; RK=2r/cU4cJEh; ptcz=8235ccaac75bae8201f47a835b216cd97d8f530349b6865815d301b699dec7c5; p_uin=o1234567890; pt4_token=VNY2rJ1KBn7v9iHp1eFMfaRrxmzuEogpZimR20ookP4_; p_skey=C03fYXYvuuIISyOKcJeMrd6nKddc0iNkh-9p-VkMg7U_; Loading=Yes; welcomeflash=1234567890_58028; qz_screen=1707x960; 1234567890_todaycount=0; 1234567890_totalcount=711; pgv_pvid=5798017608; pgv_info=ssid=s9552383352; QZ_FE_WEBP_SUPPORT=1; scstat=18; __Q_w_s__QZN_TodoMsgCnt=1; cpu_performance_v8=25"
        cookie_dict = {i.split("=")[0]: i.split("=")[1] for i in cookie_str.split("; ")}
        request.cookies = cookie_dict
        return None
# settings.py
# 不打印日志信息
LOG_LEVEL = 'WARNING'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False
# Disable cookies (enabled by default)
COOKIES_ENABLED = True
# Enable or disable downloader middlewares
# See https://docs.scrapy.org/en/latest/topics/downloader-middleware.html
DOWNLOADER_MIDDLEWARES = {
    'login.middlewares.LoginDownloaderMiddleware': 543,
    'login.middlewares.CookieDownloaderMiddleware': 541,
}
  • 当 COOKIES_ENABLED 是注释的时候 scrapy 默认没有开启 cookie。
  • 当 COOKIES_ENABLED 没有注释,设置为 False 的时候 scrapy 默认使用了 settings 里面的 cookie。
  • 当 COOKIES_ENABLED 设置为 True 的时候 scrapy 就会把 settings 的 cookie 关掉,使用自定义 cookie。

4.3、方式三:爬虫文件中,重写 start_rquests 方法

# spiders/example.py
import scrapy  # 导入 Scrapy 库

class QzoneSpider(scrapy.Spider):
    name = 'example'  # 爬虫的名字,用于启动爬虫时的标识
    allowed_domains = ['qq.com']  # 允许爬取的域名
    start_urls = ['https://user.qzone.qq.com/1234567890']  # 起始 URL,爬虫会从这个 URL 开始爬取数据
    cookie_str = "_qpsvr_localtk=0.6206021496459884; uin=o1234567890; skey=@kalEm2dQT; RK=2r/cU4cJEh; ptcz=8235ccaac75bae8201f47a835b216cd97d8f530349b6865815d301b699dec7c5; p_uin=o1234567890; pt4_token=VNY2rJ1KBn7v9iHp1eFMfaRrxmzuEogpZimR20ookP4_; p_skey=C03fYXYvuuIISyOKcJeMrd6nKddc0iNkh-9p-VkMg7U_; Loading=Yes; welcomeflash=1234567890_58028; qz_screen=1707x960; 1234567890_todaycount=0; 1234567890_totalcount=711; pgv_pvid=5798017608; pgv_info=ssid=s9552383352; QZ_FE_WEBP_SUPPORT=1; scstat=18; __Q_w_s__QZN_TodoMsgCnt=1; cpu_performance_v8=25"

    def start_requests(self):
        # 解析 cookie 字符串,将其转换为字典形式
        cookie_dict = {i.split("=")[0]: i.split("=")[1] for i in self.cookie_str.split("; ")}
        yield scrapy.Request(
            url=self.start_urls[0],  # 使用第一个起始 URL
            callback=self.parse,  # 响应后交给 parse 方法处理
            cookies=cookie_dict  # 设置请求的 Cookie
        )

    def parse(self, response):
        print(response.text)  # 打印响应的 HTML 文本内容
        pass  # 占位符,表示这个函数暂时不做任何处理,可以根据需要添加解析逻辑

八、作业

目标网站:https://github.com/login

需求:以抓包的形式完成模拟登录

1、创建项目

scrapy startproject github_login

cd github_login

scrapy genspider github github.com

2、新建一个 start.py 用来运行代码。

# start.py
# 使用 cmdline 模块来执行命令行命令
from scrapy import cmdline

# 使用 Scrapy 执行名为 github_login 的爬虫
cmdline.execute('scrapy crawl github'.split())

3、在 settings.py 文件中修改一些参数。

# settings.py
# 不打印日志信息
LOG_LEVEL = 'WARNING'
# Obey robots.txt rules
ROBOTSTXT_OBEY = False

4、抓包分析 POST 数据

多次输入错误的用户名和密码,看 POST 请求数据,哪些是变化的,哪些是不变的

在这里插入图片描述

5、在 spiders 文件夹下的 github.py 文件中编写代码。

# spiders/github.py
import scrapy  # 导入 Scrapy 库

# 定义一个名为 GithubSpider 的 Spider 类,继承自 Scrapy 的 Spider 类
class GithubSpider(scrapy.Spider):  
    name = 'github'  # 设置 Spider 的名字为'github'
    allowed_domains = ['github.com']  # 允许爬取的域名
    start_urls = ['https://github.com/login']  # 起始 URL,即登录页面的 URL

    # 定义一个名为 parse 的方法,用于处理登录页面的响应
    def parse(self, response):  
        # 提取 authenticity_token、timestamp 和 timestamp_secret 参数值
        authenticity_token = response.css('input[name="authenticity_token"]::attr(value)').get()
        timestamp = response.css('input[name="timestamp"]::attr(value)').get()
        timestamp_secret = response.css('input[name="timestamp_secret"]::attr(value)').get()

        # 构造登录请求的 POST 数据
        data_dict = {
            'commit': 'Sign in',  # 提交按钮的值
            'authenticity_token': authenticity_token,  # 登录页面中的 authenticity_token 值
            'login': 'XXX',  # GitHub 用户名
            'password': 'XXX',  # GitHub 密码
            'webauthn-support': 'supported',  # WebAuthn 支持情况
            'webauthn-iuvpaa-support': 'unsupported',  # WebAuthn 支持情况
            'return_to': 'https://github.com/login',  # 返回到登录页面
            'timestamp': timestamp,  # 时间戳
            'timestamp_secret': timestamp_secret  # 时间戳密钥
        }

        # 构造登录请求
        yield scrapy.FormRequest.from_response(
            response,
            formdata=data_dict,  # POST 数据字典
            callback=self.after_login  # 登录成功后处理响应的回调函数
        )

    # 定义一个名为 after_login 的方法,用于处理登录后的响应
    def after_login(self, response):
        if response.status == 200:  # 如果响应的状态码为200(HTTP成功),表示登录成功
            print('登录成功!')  # 打印登录成功的消息
        else:  # 如果响应状态码不是200,表示登录失败
            print('登录失败!')  # 打印登录失败的消息

记录学习过程,欢迎讨论交流,尊重原创,转载请注明出处~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1023031.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基础课-解析几何

1.平面直角坐标系 两点A(x1,y1)与B(x2,y2)之间的距离: 2.两点斜率公式 3.点到直线的距离 平行线之间的距离 4.平面直线方程的几种形式 点斜式 点P(x0,y0),斜率为k的直线方程:y-y0k(x-x0) 5.圆

会员管理系统H5-01会员开卡

我们前边7篇文章讲解的是PC端的功能&#xff0c;还需要为商家提供一套移动端的后台管理程序。在微搭中&#xff0c;移动端的后台程序我们可以使用H5进行开发&#xff0c;开发完毕后可以启用登录&#xff0c;这样管理员就可以在手机上进行操作。 01 创建应用 登录微搭后台&…

企业选择预测性维护解决方案的常见问题和PreMaint的策略

预测性维护技术在现代制造业中扮演着越来越重要的角色&#xff0c;有助于提高设备可靠性、降低维护成本并最大程度地减少停机时间。然而&#xff0c;一些企业在选择预测性维护解决方案时仍存在一些常见问题和误解。在这篇文章中&#xff0c;我们将探讨一些常见问题&#xff0c;…

Python与数据分析--Matplotlib-1

目录 1.Matplotlib库函数导入 2.简单尝试绘图 3.绘制多条折线图 4.绘制多种颜色风格曲线 5.图片内容文本操作实例 6.图例设置实例 7.坐标轴设置实例 1.Matplotlib库函数导入 #导入matplotlib库 import matplotlib as mpl import matplotlib.pyplot as plt #平常一般用第…

手把手教你前端 NodeJs 常用技术和第三方库使用详细教程(每周更新中)

dotenv 加载环境变量 dotenv是一个用于在Node.js项目中加载环境变量的库。它允许你将环境变量存储在一个名为.env的文件中&#xff0c;并在你的应用程序中轻松访问这些变量。 dotenv 官方网站&#xff1a;https://www.dotenv.org/docs 要使用dotenv&#xff0c;你需要首先在你…

(2023,微调节,多纵横比训练,细化模型)SDXL:用于高分辨率图像合成的改进的潜在扩散模型

SDXL: Improving Latent Diffusion Models for High-Resolution Image Synthesis 公众号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 改进稳定扩散 2.1 架构与规模 …

Python基础数据结构入门必读指南

更多资料获取 作者主页&#xff1a;涛哥聊Python 个人网站&#xff1a;涛哥聊Python 大家好&#xff0c;我是涛哥&#xff0c;今天为大家分享的是Python中常见的数据结构。 1.数组 含义&#xff1a;数组是一种有序的数据结构&#xff0c;其中的元素可以按照索引来访问。数组…

DMNet复现(二)之模型篇:Density map guided object detection in aerial image

以前用Swin Transformer Tiny训练了40epoch的&#xff0c;官方用的Faster RCNN&#xff0c;这里先用Swin Transformer Tiny进行测试。 模型训练 采用基于MMDetection的框架Swin Transformer Tiny进行训练&#xff0c;训练方法可参考官方教程。 融合检测 Global Image 检测 …

无涯教程-JavaScript - SEC函数

描述 SEC函数返回Angular的割线。 语法 SEC (number)争论 Argument描述Required/OptionalNumberNumber is the angle in radians for which you want the secant.Required Notes 数字的绝对值必须小于2 ^ 27 如果Angular为度,则将Angular乘以PI()/180或使用RADIANS函数将…

彻底学会Unity中UGUI中UI元素自适应问题

彻底学会Unity中UGUI中UI元素自适应问题 包会的简单版教程 狂飙模式&#xff1a; 经过自我进化学习&#xff0c;终于参悟。看完这个教程&#xff0c;你也可以&#xff01; 1.扫盲UGUI的理解&#xff1a; Unity3d 中的UI都是画在画布上的。就像画一幅画&#xff0c;首先我们需…

iPhone NFC 设置教程(门禁卡/公交卡/校园卡等等)

苹果手机如何开启NFC功能呢&#xff1f;相信不少小伙伴都对iPhone手机里的NFC用法都不太了解。尽管小米、华为、荣耀、一加、oppo、vivo等安卓手机的NFC使用已经满大街了&#xff0c;不仅功能齐全而且快捷安全&#xff0c;但是这一功能在苹果手机上还很鸡肋&#xff0c;因为它对…

DBSCAN聚类的Python 实现

一、说明 DBSCAN&#xff08;Density-Based Spatial Clustering of Applications with Noise&#xff09;聚类是一种基于密度的聚类算法。它能够根据数据点的密度来将数据划分为不同的类别&#xff0c;并可以自动识别离群点。DBSCAN聚类算法的核心思想是将密度高的数据点划分为…

MongoDB——关于NumberLong处理大整数

1、问题 MongoDB根据某个Long类型ID查询数据查不出来 db.getCollection(school_work_section).find({school_work_section_id:577199363866206209}); 2、解决办法 Long类型的需要在NumberLong的对象里加上双引号才能查出来 db.getCollection(school_work_section).find({sc…

初识C语言——详细入门一(系统性学习day4)

目录 前言 一、C语言简单介绍、特点、基本构成 简单介绍&#xff1a; 特点&#xff1a; 基本构成&#xff1a; 二、认识C语言程序 标准格式&#xff1a; 简单C程序&#xff1a; 三、基本构成分类详细介绍 &#xff08;1&#xff09;关键字 &#xff08;2&#xf…

搭建ELK+Filebead+zookeeper+kafka实验

一、ELKFilebeadzookeeperkafka架构 第一层&#xff1a;数据采集层&#xff08;Filebeat&#xff09; 数据采集层位于最左边的业务服务集群上&#xff0c;在每个业务服务器上面安装了filebead做日志收集&#xff0c;然后把采集到的原始日志发送到kafkazookeeper集群上。 第二…

文件拷贝【 使用字节流完成文件的复制(支持一切文件类型的复制)】

需求&#xff1a; 把某个视频复制到 E:\\videocopy\\new.mp4 思路&#xff1a; 根据 数据源 创建字节输入流对象根据 目的地 创建字节输出流对象读写数据&#xff0c;复制视频释放资源 可以拷贝 视频 &#xff0c;图片 &#xff0c;文本.txt 等文件 package com.csdn.d2_byte_…

Linux grep命令

①grep命令——过滤文件 这是txt.txt的内容 通过grep管道符查找gcc内容在txt.txt文件中 查找gcc所处行位置&#xff0c;加上-n 查找有多个相同内容的数据 ②wc命令——数量统计 统计数据如图&#xff1a; ③管道符——左边结果作为右边输入 如下图所示统计txt.txt文件"-&…

连续性数据进行Meta荟萃分析

Meta荟萃分析&#xff08;也称Meta分析&#xff0c;元分析&#xff0c;异质性分析等&#xff09;&#xff0c;其是一种综合各种文献结论&#xff0c;进而汇总综合评价的方法&#xff0c;Meta分析常用于医学、心理学、教育学、生态学等专业领域。通俗地看&#xff0c;Meta分析是…

物 理 层

二、物理层 1、物理层的基本概念 物理层的作用:尽可能的屏蔽掉传输媒体和通信手段的差异&#xff0c;使物理层上面的数据链路层感觉不到这些差异&#xff0c;使其只需要考虑如何完成本层的协议和服务 1.1、物理层的主要任务 机械特性&#xff1a;指明接口所用的接线器的形状…

【计算机视觉】1. 计算机视觉基础理论知识和框架(Basic Concepts)

什么是计算机视觉? 一、什么是计算机视觉二、二个研究维度三、研究挑战3.1 像素与语义之间的GAP3.2 视觉变化3.3 光照变化3.4 尺度变化3.5 形态变化3.6 背景复杂3.7 遮挡3.8 内外 四、计算机视觉框架4.1 计算机视觉基础4.2 深度学习算法理论基础4.3 深度学习算法 五、计算机视…