前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【论文复现】transformer

【论文复现】transformer

作者头像
Eternity._
发布于 2024-11-26 02:28:42
发布于 2024-11-26 02:28:42
23900
代码可运行
举报
文章被收录于专栏:登神长阶登神长阶
运行总次数:0
代码可运行

概述


Transformer模型,这一革命性的神经网络架构,由谷歌团队于2017年率先在机器翻译领域推出。针对传统模型在处理长距离文本依赖时的局限性和并行化困难,Transformer引入了一种全新的设计理念——自注意力机制(Self-Attention)。这一机制允许模型在处理每个输入位置时,都能灵活关联序列中的其他部分,极大地增强了模型捕捉长距离依赖的能力。此外,Transformer还融合了残差连接(Residual Connections)与层归一化(Layer Normalization)等优化策略,不仅加速了训练进程,还显著提升了模型的性能表现。

作为自然语言处理(NLP)领域的一座里程碑,Transformer模型摒弃了长达数十年之久的CNN与RNN架构,开创性地完全依赖Attention机制构建网络,并取得了非凡的成效。这一创举不仅让Attention机制大放异彩,更成为了当代大语言模型的主流选择。就模型本身而言,Attention机制的应用有效解决了NLP领域长期存在的长程依赖难题,同时,摆脱RNN架构的束缚,使得Transformer模型能够充分发挥并行计算的优势,极大提升了模型的运算效率。

本文所涉及的所有资源的获取方式:这里

模型架构


Transformer 是针对自然语言处理的 Seq2Seq(序列到序列)任务开发的,整体上沿用了 Seq2Seq 模型的 Encoder-Decoder(编码器-解码器)结构,整体架构如下图所示:

左侧和右侧分别对应着编码器(Encoder)和解码器(Decoder)结构。它们均由若干个基本的 Transformer 块(Block)组成(对应着图中的灰色框)。这里 N× 表示进行了 N 次堆叠。接下来将逐个介绍 Transformer 的实现细节和原理。

嵌入表示层


对于输入文本序列,首先通过输入嵌入层(Input Embedding)将每个单词转换为其相对应的向量表示。通常直接对每个单词创建一个向量表示。由于 Transfomer 模型不再使用基于循环的方式建模文本输入,序列中不再有任何信息能够提示模型单词之间的相对位置关系。在送入编码器端建模其上下文语义之前,一个非常重要的操作是在词嵌入中加入位置编码(Positional Encoding)这一特征。具体来说,序列中每一个单词所在的位置都对应一个向量。这一向量会与单词表示对应相加并送入到后续模块中做进一步处理。在训练的过程当中,模型会自动地学习到如何利用这部分位置信息。 为了得到不同位置对应的编码,Transformer 模型使用不同频率的正余弦函数如下所示:

[ PE(pos, 2i) = \sin\left(\frac{pos}{10000^{\frac{2i}{d}}}\right) ]
[ PE(pos, 2i+1) = \cos\left(\frac{pos}{10000^{\frac{2i}{d}}}\right) ]

其中,pos 表示单词所在的位置,2i 和 2i+ 1 表示位置编码向量中的对应维度,d 则对应位置编码的总维度。通过上面这种方式计算位置编码有这样几个好处:首先,正余弦函数的范围是在 [-1,+1],导出的位置编码与原词嵌入相加不会使得结果偏离过远而破坏原有单词的语义信息。其次,依据三角函数的基本性质,可以得知第 pos + k 个位置的编码是第 pos 个位置的编码的线性组合,这就意味着位置编码中蕴含着单词之间的距离信息。pytorch实现代码如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class PositionalEncoding(nn.Module):

    def __init__(self, d_model, max_len=5000):
        """
        输入
            d_model - 输入的隐藏层维度.
            max_len - 最大序列长度.
        """
        super().__init__()

        # 创建矩阵[SeqLen, HiddenDim]来表示输入的位置编码
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)
        pe = pe.unsqueeze(0)

        # 将一个张量注册为一个缓冲区(buffer),缓冲区通常用于存储模型的状态,但不是模型的参数
        # persistent 设置为 False,那么这个缓冲区不会被包括在模型的 state_dict() 中
        self.register_buffer('pe', pe, persistent=False)

    def forward(self, x):
        x = x + self.pe[:, :x.size(1)]
        return x

注意力层


Attention机制最先源于计算机视觉领域,其核心思想为当我们关注一张图片,我们往往无需看清楚全部内容而仅将注意力集中在重点部分即可。而在自然语言处理领域,我们往往也可以通过将重点注意力集中在一个或几个 token,从而取得更高效高质的计算效果。Attention 机制的特点是通过计算 Query (查询值)与Key(键值)的相关性为真值加权求和,从而拟合序列中每个词同其他词的相关关系。给定由单词语义嵌入及其位置编码叠加得到的输入表示,为了实现对上下文语义依赖的建模,进一步引入在自注意力机制中涉及到的三个元素:查询 q(Query),键 k(Key),值 v(Value)。在编码输入序列中每一个单词的表示的过程中,这三个元素用于计算上下文单词所对应的权重得分。直观地说,这些权重反映了在编码当前单词的表示时,对于上下文不同部分所需要的关注程度。 为了得到编码单词xi时所需要关注的上下文信息,通过位置i查询向量与其他位置的键向量做点积得到匹配分数 qi·k1, qi·k2, …,qi·kt。为了防止过大的匹配分数在后续 Softmax 计算过程中导致的梯度爆炸以及收敛效率差的问题,这些得分会除放缩因子√d以稳定优化。放缩后的得分经过 Softmax 归一化为概率之后,与其他位置的值向量相乘来聚合希望关注的上下文信息,并最小化不相关信息的干扰。计算过程如下图所示:

[ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V ]

为了进一步增强自注意力机制聚合上下文信息的能力,提出了多头自注意力(Multi-head Attention)的机制,以关注上下文的不同侧面。具体来说,上下文中每一个单词的表示xi经过多组线性矩阵映射到不同的表示子空间中。pytorch 实现代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def scaled_dot_product(q, k, v, mask=None):
    d_k = q.size()[-1]
    attn_logits = torch.matmul(q, k.transpose(-2, -1))
    attn_logits = attn_logits / math.sqrt(d_k)
    if mask is not None:
        attn_logits = attn_logits.masked_fill(mask == 0, -9e15)
    attention = F.softmax(attn_logits, dim=-1)
    values = torch.matmul(attention, v)
    return values, attention


class MultiheadAttention(nn.Module):

    def __init__(self, input_dim, embed_dim, num_heads):
        super().__init__()
        assert embed_dim % num_heads == 0, "embedding 维度必须整除 num_head"

        self.embed_dim = embed_dim
        self.num_heads = num_heads
        self.head_dim = embed_dim // num_heads

        # 为了提高效率,将权重矩阵qkv堆叠在一起
        self.qkv_proj = nn.Linear(input_dim, 3 * embed_dim)
        self.o_proj = nn.Linear(embed_dim, embed_dim)

        self._reset_parameters()

    def _reset_parameters(self):
        # 初始化
        nn.init.xavier_uniform_(self.qkv_proj.weight)
        self.qkv_proj.bias.data.fill_(0)
        nn.init.xavier_uniform_(self.o_proj.weight)
        self.o_proj.bias.data.fill_(0)

    def forward(self, x, mask=None, return_attention=False):
        batch_size, seq_length, _ = x.size()
        if mask is not None:
            mask = expand_mask(mask)
        qkv = self.qkv_proj(x)

        # 分离出Q, K, V
        qkv = qkv.reshape(batch_size, seq_length, self.num_heads, 3 * self.head_dim)
        qkv = qkv.permute(0, 2, 1, 3)  # [Batch, Head, SeqLen, Dims]
        q, k, v = qkv.chunk(3, dim=-1)

        # 计算 value和注意力
        values, attention = scaled_dot_product(q, k, v, mask=mask)
        values = values.permute(0, 2, 1, 3)  # [Batch, SeqLen, Head, Dims]
        values = values.reshape(batch_size, seq_length, self.embed_dim)
        o = self.o_proj(values)

        if return_attention:
            return o, attention
        else:
            return o

前馈层


前馈层接受自注意力子层的输出作为输入,并通过一个带有 Relu 激活函数的两层全连接网络对输入进行更加复杂的非线性变换。实验证明,这一非线性变换会对模型最终的性能产生十分重要的影响。计算过程如下图所示:

[ \text{FFN}(x) = \text{ReLU}(xW_1 + b_1)W_2 + b_2 ]

其中 W1, b1,W2, b2 表示前馈子层的参数。实验结果表明,增大前馈子层隐状态的维度有利于提升最终翻译结果的质量,因此,前馈子层隐状态的维度一般比自注意力子层要大。pytorch 实现代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
self.linear_net = nn.Sequential(
            nn.Linear(input_dim, dim_feedforward),
            nn.Dropout(dropout),
            nn.ReLU(inplace=True),
            nn.Linear(dim_feedforward, input_dim)
        )

残差连接和层归一化


由于Transformer 结构组成的网络结构通常都是非常庞大。编码器和解码器均由很多层基本的Transformer 块组成,每一层当中都包含复杂的非线性映射,这就导致模型的训练比较困难。因此,研究者们在 Transformer 块中进一步引入了残差连接与层归一化技术以进一步提升训练的稳定性。具体来说,残差连接主要是指使用一条直连通道直接将对应子层的输入连接到输出上去,从而避免由于网络过深在优化过程中潜在的梯度消失问题。此外,为了进一步使得每一层的输入输出范围稳定在一个合理的范围内,层归一化技术被进一步引入每个 Transformer 块的当中。层归一化技术可以有效地缓解优化过程中潜在的不稳定、收敛速度慢等问题。

编码器和解码器结构


transformer沿用了Seq2Seq模型的 Encoder-Decoder(编码器-解码器)结构。Encoder由N个(论文中取 N = 6)EncoderLayer 组成,每个 EncoderLayer又由两个sublayer(子层)组成,其中第一个子层为一个多头自注意力层,第二子层为一个全连接神经网络,实际是一个线性层+激活函数+ dropout + 线性层的全连接网络。 相比于编码器端,解码器端要更复杂一些。具体来说,解码器的每个 Transformer 块的第一个自注意力子层额外增加了注意力掩码,对应图中的掩码多头注意力(Masked Multi-Head Attention)部分。这主要是因为在翻译的过程中,编码器端主要用于编码源语言序列的信息,而这个序列是完全已知的,因而编码器仅需要考虑如何融合上下文语义信息即可。而解码端则负责生成目标语言序列,这一生成过程是自回归的,即对于每一个单词的生成过程,仅有当前单词之前的目标语言序列是可以被观测的,因此这一额外增加的掩码是用来掩盖后续的文本信息,以防模型在训练阶段直接看到后续的文本序列进而无法得到有效地训练。此外,解码器端还额外增加了一个多头注意力(Multi-Head Attention)模块,使用交叉注意力(Cross-attention)方法,同时接收来自编码器端的输出以及当前 Transformer 块的前一个掩码注意力层的输出。查询是通过解码器前一层的输出进行投影的,而键和值是使用编码器的输出进行投影的。它的作用是在翻译的过程当中,为了生成合理的目标语言序列需要观测待翻译的源语言序列是什么。基于上述的编码器和解码器结构,待翻译的源语言文本,首先经过编码器端的每个Transformer 块对其上下文语义的层层抽象,最终输出每一个源语言单词上下文相关的表示。解码器端以自回归的方式生成目标语言文本,即在每个时间步t,根据编码器端输出的源语言文本表示,以及前t−1个时刻生成的目标语言文本,生成当前时刻的目标语言单词。pytorch实现的编码器代码如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class EncoderBlock(nn.Module):

    def __init__(self, input_dim, num_heads, dim_feedforward, dropout=0.0):
        """
        输入:
            input_dim - 输入的维度
            num_heads -  注意力头的数量
            dim_feedforward - MLP中隐藏层的维数
            dropout - Dropout概率
        """
        super().__init__()

        # 多头注意力
        self.self_attn = MultiheadAttention(input_dim, input_dim, num_heads)

        # 两层 MLP
        self.linear_net = nn.Sequential(
            nn.Linear(input_dim, dim_feedforward),
            nn.Dropout(dropout),
            nn.ReLU(inplace=True),
            nn.Linear(dim_feedforward, input_dim)
        )

        self.norm1 = nn.LayerNorm(input_dim)
        self.norm2 = nn.LayerNorm(input_dim)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, mask=None):
        # 注意力部分
        attn_out = self.self_attn(x, mask=mask)
        x = x + self.dropout(attn_out)
        x = self.norm1(x)

        # MLP 部分
        linear_out = self.linear_net(x)
        x = x + self.dropout(linear_out)
        x = self.norm2(x)

        return x


class TransformerEncoder(nn.Module):

    def __init__(self, num_layers, **block_args):
        super().__init__()
        self.layers = nn.ModuleList([EncoderBlock(**block_args) for _ in range(num_layers)])

    def forward(self, x, mask=None):
        for l in self.layers:
            x = l(x, mask=mask)
        return x

    def get_attention_maps(self, x, mask=None):
        attention_maps = []
        for l in self.layers:
            _, attn_map = l.self_attn(x, mask=mask, return_attention=True)
            attention_maps.append(attn_map)
            x = l(x)
        return attention_maps

数据处理和模型训练


获取 cifar100 数据集

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from torchvision.datasets import CIFAR100

DATASET_PATH = "./datasets"
device = torch.device("cuda:0") if torch.cuda.is_available() else torch.device("cpu")
# ImageNet统计数据
DATA_MEANS = np.array([0.485, 0.456, 0.406])
DATA_STD = np.array([0.229, 0.224, 0.225])
TORCH_DATA_MEANS = torch.from_numpy(DATA_MEANS).view(1, 3, 1, 1)
TORCH_DATA_STD = torch.from_numpy(DATA_STD).view(1, 3, 1, 1)

# Resize to 224x224, and normalize
transform = transforms.Compose([transforms.Resize((224, 224)),
                                transforms.ToTensor(),
                                transforms.Normalize(DATA_MEANS, DATA_STD)
                                ])
# 加载训练数据集
train_set = CIFAR100(root=DATASET_PATH, train=True, transform=transform, download=True)
# 加载测试数据集
test_set = CIFAR100(root=DATASET_PATH, train=False, transform=transform, download=True)

使用 resnet 模型提取图片特征

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@torch.no_grad()
def extract_features(dataset, save_file):
    if not os.path.isfile(save_file):
        data_loader = data.DataLoader(dataset, batch_size=128, shuffle=False, drop_last=False, num_workers=4)
        extracted_features = []
        for imgs, _ in tqdm(data_loader):
            imgs = imgs.to(device)
            feats = pretrained_model(imgs)
            extracted_features.append(feats)
        extracted_features = torch.cat(extracted_features, dim=0)
        extracted_features = extracted_features.detach().cpu()
        torch.save(extracted_features, save_file)
    else:
        extracted_features = torch.load(save_file)
    return extracted_features

CHECKPOINT_PATH = "./saved_models"
train_feat_file = os.path.join(CHECKPOINT_PATH, "train_set_features.tar")
train_set_feats = extract_features(train_set, train_feat_file)

test_feat_file = os.path.join(CHECKPOINT_PATH, "test_set_features.tar")
test_feats = extract_features(test_set, test_feat_file)

自定义数据类,并构建dataloader

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class SetAnomalyDataset(data.Dataset):

    def __init__(self, img_feats, labels, set_size=10, train=True):
        """
        输入:
            img_feats - 图片的特征向量,形状为[num_imgs, img_dim]
            labels - 每个图片的类别标签
            set_size - 集合中图片的数目。从一个类中采样N-1个,从另一个类中采样1个。
            train - 是否是训练模式
        """
        super().__init__()
        self.img_feats = img_feats
        self.labels = labels
        self.set_size = set_size - 1
        self.train = train

        # 同个类别图片的下标
        self.num_labels = labels.max() + 1
        self.img_idx_by_label = torch.argsort(self.labels).reshape(self.num_labels, -1)

        if not train:
            self.test_sets = self._create_test_sets()

    def _create_test_sets(self):
        test_sets = []
        num_imgs = self.img_feats.shape[0]
        np.random.seed(42)
        test_sets = [self.sample_img_set(self.labels[idx]) for idx in range(num_imgs)]
        test_sets = torch.stack(test_sets, dim=0)
        return test_sets

    def sample_img_set(self, anomaly_label):
        """
        根据异常的标签,对一组新的图像进行采样。采样的图像来自与normaly_label不同的类
        """
        set_label = np.random.randint(self.num_labels - 1)
        if set_label >= anomaly_label:
            set_label += 1

        img_indices = np.random.choice(self.img_idx_by_label.shape[1], size=self.set_size, replace=False)
        img_indices = self.img_idx_by_label[set_label, img_indices]
        return img_indices

    def __len__(self):
        return self.img_feats.shape[0]

    def __getitem__(self, idx):
        anomaly = self.img_feats[idx]
        if self.train:
            img_indices = self.sample_img_set(self.labels[idx])
        else:
            img_indices = self.test_sets[idx]

        # concat图片同时把异常图片放在最后一个
        img_set = torch.cat([self.img_feats[img_indices], anomaly[None]], dim=0)
        indices = torch.cat([img_indices, torch.LongTensor([idx])], dim=0)
        label = img_set.shape[0] - 1

        return img_set, indices, label

# 将训练集划分成训练集和验证集
labels = train_set.targets
labels = torch.LongTensor(labels)
num_labels = labels.max() + 1
sorted_indices = torch.argsort(labels).reshape(num_labels, -1)
# 确定每个类的图像数量
num_val_exmps = sorted_indices.shape[1] // 10

# 获取验证和训练的图像索引
val_indices = sorted_indices[:, :num_val_exmps].reshape(-1)
train_indices = sorted_indices[:, num_val_exmps:].reshape(-1)

# 将相应的图像特征和标签分组
train_feats, train_labels = train_set_feats[train_indices], labels[train_indices]
val_feats, val_labels = train_set_feats[val_indices], labels[val_indices]

train_anom_dataset = SetAnomalyDataset(train_feats, train_labels, set_size=SET_SIZE, train=True)
val_anom_dataset = SetAnomalyDataset(val_feats, val_labels, set_size=SET_SIZE, train=False)
test_anom_dataset = SetAnomalyDataset(test_feats, test_labels, set_size=SET_SIZE, train=False)

train_anom_loader = data.DataLoader(train_anom_dataset, batch_size=64, shuffle=True, drop_last=True, num_workers=0,
                                    pin_memory=True)
val_anom_loader = data.DataLoader(val_anom_dataset, batch_size=64, shuffle=False, drop_last=False, num_workers=0)
test_anom_loader = data.DataLoader(test_anom_dataset, batch_size=64, shuffle=False, drop_last=False, num_workers=0)

模型训练和推理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
def train_anomaly(**kwargs):
    # 创建PyTorch Lightning训练器
    root_dir = os.path.join(CHECKPOINT_PATH, "SetAnomalyDetect")
    os.makedirs(root_dir, exist_ok=True)
    trainer = pl.Trainer(default_root_dir=root_dir,
                         callbacks=[ModelCheckpoint(save_weights_only=True, mode="max", monitor="val_acc")],
                         accelerator="cuda" if str(device).startswith("cuda") else "cpu",
                         devices=1,
                         max_epochs=100,
                         gradient_clip_val=2)
    trainer.logger._default_hp_metric = None  # Optional logging argument that we don't need

    # 检查是否存在预训练模型。如果存在,直接加载并跳过训练
    pretrained_filename = os.path.join(CHECKPOINT_PATH, "SetAnomalyDetect.ckpt")
    if os.path.isfile(pretrained_filename):
        print("Found pretrained model, loading...")
        model = AnomalyPredictor.load_from_checkpoint(pretrained_filename)
    else:
        model = AnomalyPredictor(max_iters=trainer.max_epochs * len(train_anom_loader), **kwargs)
        trainer.fit(model, train_anom_loader, val_anom_loader)
        model = AnomalyPredictor.load_from_checkpoint(trainer.checkpoint_callback.best_model_path)
        torch.save(model, pretrained_filename)

    # 在验证和测试集上测试最佳模型
    train_result = trainer.test(model, train_anom_loader, verbose=False)
    val_result = trainer.test(model, val_anom_loader, verbose=False)
    test_result = trainer.test(model, test_anom_loader, verbose=False)
    result = {"test_acc": test_result[0]["test_acc"], "val_acc": val_result[0]["test_acc"],
              "train_acc": train_result[0]["test_acc"]}

    model = model.to(device)
    return model, result

anomaly_model, anomaly_result = train_anomaly(input_dim=train_anom_dataset.img_feats.shape[-1],
                                              model_dim=256,
                                              num_heads=4,
                                              num_classes=1,
                                              num_layers=4,
                                              dropout=0.1,
                                              input_dropout=0.1,
                                              lr=5e-4,
                                              warmup=100)

使用方式


创建 python 虚拟环境 conda create -n trans python=3.10 安装依赖包 pip install -r requirements.txt 运行程序 python train.py


编程未来,从这里启航!解锁无限创意,让每一行代码都成为你通往成功的阶梯,帮助更多人欣赏与学习!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-11-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
爬虫框架scrapy
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中。 其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。
菲宇
2019/06/12
1.8K0
爬虫框架scrapy
[爬虫]scrapy框架
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
周小董
2019/03/25
1.3K0
[爬虫]scrapy框架
python爬虫 scrapy爬虫框架的基本使用
在编写爬虫的时候,如果我们使用 requests、aiohttp 等库,需要从头至尾把爬虫完整地实现一遍,比如说异常处理、爬取调度等,如果写的多了,的确会比较麻烦。利用现有的爬虫框架,可以提高编写爬虫的效率,而说到 Python 的爬虫框架,Scrapy 当之无愧是最流行最强大的爬虫框架了。
叶庭云
2020/09/17
1.6K0
scrapy框架爬虫_bootstrap是什么框架
Scrapy主要包括了以下组件: • 引擎(Scrapy): 用来处理整个系统的数据流,触发事务(框架核心); • 调度器(Scheduler): 用来接受引擎发过来的请求,压入队列中,并在引擎再次请求的时候返回。可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列,由它来决定下一个要抓取的网址是什么,同时去除重复的网址; • 下载器(Downloader): 用于下载网页内容,并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的); • 爬虫(Spiders): 爬虫是主要干活的,用于从特定的网页中提取自己需要的信息,即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面; • 项目管道(Pipeline): 负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据; • 下载器中间件(Downloader Middlewares): 位于Scrapy引擎和下载器之间的框架,主要是处理Scrapy引擎与下载器之间的请求及响应; • 爬虫中间件(Spider Middlewares): 介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出; • 调度中间件(Scheduler Middewares): 介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应。
全栈程序员站长
2022/09/27
6770
Python scrapy 安装与开发
Scrapy是采用Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取采集web站点信息并从页面中提取结构化的数据。
阳光岛主
2019/02/18
1.3K0
Python scrapy 安装与开发
爬虫系列(10)Scrapy 框架介绍、安装以及使用。
运行命令:scrapy startproject myfrist(your_project_name)
野原测试开发
2019/07/10
1.5K0
爬虫系列(10)Scrapy 框架介绍、安装以及使用。
爬虫框架 Scrapy 知识点简介
Scrapy框架因为功能十分强大,所以依赖很多库,不能直接安装,需要先安装依赖库,因为我的电脑在Windows下,所以这里展示Windows下的安装方法(如果有其他平台的需要,欢迎给我留言我在发出来)。
数据STUDIO
2022/04/11
3280
爬虫框架 Scrapy 知识点简介
教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神
Scrapy,Python开发的一个快速,高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。Scrapy用途广泛,可以用于数据挖掘、监测和 自动化测试 。 Scrapy吸引人的地方在于它是一个框架,任何人都可以根据需求方便的修改。它也提供了多种类型爬虫的基类,如BaseSpider、sitemap爬虫等,最新版本又提供了web2.0爬虫的支持。 Scratch,是抓取的意思,这个Python的爬虫框架叫Scrapy,大概也是这个意思吧,就叫它:小刮刮吧。 Scrapy 使用了
小小科
2018/05/03
2.1K0
教你分分钟学会用python爬虫框架Scrapy爬取心目中的女神
爬虫框架Scrapy总结笔记
由于工作需要,学习一下爬虫框架,在网上看了别人的笔记和教学视频,想总结一下便于以后复习用,然后和大家分享一下。
木野归郎
2021/03/11
4980
爬虫框架Scrapy总结笔记
爬虫框架Scrapy的第一个爬虫示例入门教程
豌豆贴心提醒,本文阅读时间8分钟 我们使用dmoz.org这个网站来作为小抓抓一展身手的对象。 首先先要回答一个问题。 问:把网站装进爬虫里,总共分几步? 答案很简单,四步: 新建项目 (Project):新建一个新的爬虫项目 明确目标(Items):明确你想要抓取的目标 制作爬虫(Spider):制作爬虫开始爬取网页 存储内容(Pipeline):设计管道存储爬取内容 好的,基本流程既然确定了,那接下来就一步一步的完成就可以了。 1.新建项目(Project) 在空目录下按住Shift键右击,选择
小小科
2018/05/03
1.2K0
爬虫框架Scrapy的第一个爬虫示例入门教程
scrapy爬虫框架教程(一)-- Scrapy入门
前言 转行做python程序员已经有三个月了,这三个月用Scrapy爬虫框架写了两百多个爬虫,不能说精通了Scrapy,但是已经对Scrapy有了一定的熟悉。准备写一个系列的Scrapy爬虫教程,一方面通过输出巩固和梳理自己这段时间学到的知识,另一方面当初受惠于别人的博客教程,我也想通过这个系列教程帮助一些想要学习Scrapy的人。 Scrapy简介 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。 其最初是为了 页面
木制robot
2018/04/13
1.5K0
scrapy爬虫框架教程(一)-- Scrapy入门
Python最火爬虫框架Scrapy入门与实践,豆瓣电影 Top 250 数据采集
Python爬虫框架Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,非常出名,非常强悍。所谓的框架就是一个已经被集成了各种功能(高性能异步下载,队列,分布式,解析,持久化等)的具有很强通用性的项目模板。对于框架的学习,重点是要学习其框架的特性、各个功能的用法即可。
二爷
2020/07/22
2.4K0
Python最火爬虫框架Scrapy入门与实践,豆瓣电影 Top 250 数据采集
Scrapy爬虫入门
快两周了,还没缓过来劲,python 黑帽的系列教程今天才开始捡起来。不过工作又要忙了,晚上照顾玄小魂,白天敲代码,抽时间写文章,真的有点心力交瘁。不过没关系,一切都会好起来的。 ---------------------------------------------------------------------------------------------------- 本篇文章,是转载过来的,Python黑客编程的后续课程也会详细讨论Scrapy的使用的。 原文链接:http://chenqx.
用户1631416
2018/04/12
1.2K0
Scrapy爬虫入门
爬虫之scrapy框架(一)
Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速、简单、可扩展的方式从网站中提取所需的数据。但目前Scrapy的用途十分广泛,可用于如数据挖掘、监测和自动化测试等领域,也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。
GH
2020/03/19
8520
3、web爬虫,scrapy模块介绍与使用
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中。
天降攻城狮
2019/07/03
8370
3、web爬虫,scrapy模块介绍与使用
【Python环境】Scrapy爬虫轻松抓取网站数据
网络爬虫(Web Crawler, Spider)就是一个在网络上乱爬的机器人。当然它通常并不是一个实体的机器人,因为网络本身也是虚拟的东西,所以这个“机器人”其实也就是一段程序,并且它也不是乱爬,而是有一定目的的,并且在爬行的时候会搜集一些信息。例如 Google 就有一大堆爬虫会在 Internet 上搜集网页内容以及它们之间的链接等信息;又比如一些别有用心的爬虫会在 Internet 上搜集诸如 foo@bar.com 或者 foo [at] bar [dot] com 之类的东西。 除此之外,还有一
陆勤_数据人网
2018/02/26
1.8K0
【Python环境】Scrapy爬虫轻松抓取网站数据
Python爬虫Scrapy入门
Scrapy是Python开发的一个快速、高层次的屏幕抓取和web抓取框架,用于抓取web站点并从页面中提取结构化的数据。
里克贝斯
2021/05/21
6790
Python爬虫Scrapy入门
Python网络爬虫04---Scrapy工作原理
scrapy内置非常好用的selectors用来抽取数据(extract data) — xpath,css
软件架构师Michael
2022/03/02
7390
精通Python爬虫框架Scrapy_php爬虫框架哪个好用
讲解Scrapy框架之前,为了让读者更明白Scrapy,我会贴一些网站的图片和代码。 但是,【注意!!!】 【以下网站图片和代码仅供展示!!如果大家需要练习,请自己再找别的网站练习。】 【尤其是政府网站,千万不能碰哦!】
全栈程序员站长
2022/11/01
1.3K0
scrapy 入门_scrapy官方文档
Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中。其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。Scrapy用途广泛,可以用于数据挖掘、监测和自动化测试。
全栈程序员站长
2022/09/20
1.1K0
相关推荐
爬虫框架scrapy
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档