Scrapy简介-快速开始-项目实战-注意事项-踩坑之路

news2025/1/12 10:40:34

scrapy项目模板地址:https://github.com/w-x-x-w/Spider-Project

Scrapy简介

Scrapy是什么?

  • Scrapy是一个健壮的爬虫框架,可以从网站中提取需要的数据。是一个快速、简单、并且可扩展的方法。Scrapy使用了异步网络框架来处理网络通讯,可以获得较快的下载速度,因此,我们不需要去自己实现异步框架。并且,Scrapy包含了各种中间件接口,可以灵活的完成各种需求。所以我们只需要定制开发几个模块就可以轻松的实现一个爬虫,用来抓取网页上的各种内容。
  • Scrapy并不是一个爬虫,它只是一个“解决方案”,也就是说,如果它访问到一个“一无所知”的网站,是什么也做不了的。Scrapy是用于提取结构化信息的工具,即需要人工的介入来配置合适的XPath或者CSS表达式。Scrapy也不是数据库,它并不会储存数据,也不会索引数据,它只能从一堆网页中抽取数据,但是我们却可以将抽取的数据插入到数据库中。

Scrapy架构

Scrapy Engine (引擎): 是框架的核心,负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。并在发生相应的动作时触发事件。
**Scheduler (调度器): **它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,提供给引擎。
**Downloader (下载器):**负责下载引擎发送的所有Requests请求,并将其获取到的Responses交还给引擎。
**Spider (爬虫):**负责处理由下载器返回的Responses,并且从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给Scrapy Engine,并且再次进入Scheduler。
**Item Pipeline (项目管道):**它负责处理Spider中获取到的Item,并进行进行后期处理(清理、验证、持久化存储)的地方.
**Downloader Middlewares (下载中间件):**引擎与下载器间的特定钩子,一个可以自定义扩展下载功能的组件。处理下载器传递给引擎的Response。
**Spider Middlewares(爬虫中间件):**引擎和Spider间的特定钩子,(处理进入Spider的Responses,和从Spider出去的Requests)

快速开始-项目实战

我们这里以某新闻网站新闻推送为例编写项目,仅用于学习,请勿恶意使用

安装 Scrapy

pip install Scrapy

创建项目

scrapy startproject 项目名
HuxiuSpider/
    scrapy.cfg
    HuxiuSpider/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
            ...

这些文件分别是:

  • scrapy.cfg: 项目的配置文件
  • HuxiuSpider/: 该项目的python模块。之后您将在此加入代码。
  • HuxiuSpider/items.py: 项目中的item文件.
  • HuxiuSpider/pipelines.py: 项目中的pipelines文件.
  • HuxiuSpider/settings.py: 项目的设置文件.
  • HuxiuSpider/spiders/: 放置spider代码的目录.

更改设置

  • 注释robotstxt_obey
# 第21行
# Obey robots.txt rules
# ROBOTSTXT_OBEY = True
  • 设置User-Agent
# 第18行
# Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = "HuxiuSpider (+http://www.yourdomain.com)"
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36'
  • 设置访问延迟
# 第29行
# 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 = 3

开启pipline

# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
   "HuxiuSpider.pipelines.HuxiuspiderPipeline": 300,
}

开启cookie(无需操作)(可选操作)

# Disable cookies (enabled by default)
#COOKIES_ENABLED = False

设置频率(可不操作)

# The download delay setting will honor only one of:
# 定义了每个域名同时发送的请求数量
CONCURRENT_REQUESTS_PER_DOMAIN = 2
# 定义了每个IP同时发送的请求数量
#CONCURRENT_REQUESTS_PER_IP = 16

命令行快速生成模板:

scrapy genspider huxiu_article api-article.huxiu.com

Spider是用户编写用于从单个网站(或者一些网站)爬取数据的类。
其包含了一个用于下载的初始URL,如何跟进网页中的链接以及如何分析页面中的内容, 提取生成 item 的方法。
为了创建一个Spider,您必须继承 scrapy.Spider 类, 且定义以下三个属性:

  • name: 用于区别Spider。 该名字必须是唯一的,您不可以为不同的Spider设定相同的名字。
  • start_urls: 包含了Spider在启动时进行爬取的url列表。 因此,第一个被获取到的页面将是其中之一。 后续的URL则从初始的URL获取到的数据中提取。(也可以删除此变量,但要重写start_requests方法)
  • parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。

以下为我们的第一个Spider代码,保存在 HuxiuSpider/spiders 目录下的 huxiu_article.py 文件中:
我们对于此段代码进行必要的解释:
向一个url发送post请求,发送一个时间戳,可以获取这个时间戳以后的新闻推送,然后就是推送数据,关于数据提取等操作可以点开链接页自行观察,太过简单。

爬虫程序模板:

新闻列表页爬虫

import json
import time

import scrapy

from HuxiuSpider.items import HuxiuspiderItem


class HuxiuArticleSpider(scrapy.Spider):
    def __init__(self):
        # 'https://www.huxiu.com/article/'
        self.url = 'https://api-article.huxiu.com/web/article/articleList'

    name = "huxiu_article"
    allowed_domains = ["api-article.huxiu.com"]

    def start_requests(self):
        timestamp = str(int(time.time()))
        form_data = {
            "platform": "www",
            "recommend_time": timestamp,
            "pagesize": "22"
        }
        yield scrapy.FormRequest(url=self.url, formdata=form_data, callback=self.parse)

    def parse(self, response):
        item = HuxiuspiderItem()
        res = response.json()
        success = res['success']
        print(res)
        if success:
            data = res['data']
            is_have_next_page = data['is_have_next_page']
            last_dateline = data['last_dateline']
            total_page = data['total_page']
            dataList = data['dataList']

            for data_obj in dataList:
                item['url'] = 'https://www.huxiu.com/article/' + data_obj['aid'] + '.html'
                item['title'] = data_obj['title']
                item['author'] = data_obj['user_info']['username']
                item['allinfo'] = json.dumps(data_obj, ensure_ascii=False)

                item['visited'] = False
                yield item

            if is_have_next_page:
                form_data = {
                    "platform": "www",
                    "recommend_time": str(last_dateline),
                    "pagesize": "22"
                }
                yield scrapy.FormRequest(url=self.url, formdata=form_data, callback=self.parse)
        else:
            raise Exception('请求新闻列表的时候失败了~')

Item模板:

Item 是保存爬取到的数据的容器;其使用方法和python字典类似, 并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。
类似在ORM中做的一样,您可以通过创建一个 scrapy.Item 类, 并且定义类型为 scrapy.Field 的类属性来定义一个Item。 (如果不了解ORM, 不用担心,您会发现这个步骤非常简单)(ORM其实就是使用类的方式与数据库进行交互)
首先根据需要从huxiu.com获取到的数据对item进行建模。 我们需要从dmoz中获取名字,url,以及网站的描述。 对此,在item中定义相应的字段。编辑 HuxiuSpider 目录中的 items.py 文件:

import scrapy

class HuxiuspiderItem(scrapy.Item):
    url = scrapy.Field()
    title = scrapy.Field()
    author = scrapy.Field()
    # 存储尽量多的信息是必要的,以应对需求变更
    allinfo=scrapy.Field()

    visited=scrapy.Field()

一开始这看起来可能有点复杂,但是通过定义item, 您可以很方便的使用Scrapy的其他方法。而这些方法需要知道您的item的定义。

piplines模板:

from pymongo import MongoClient
from pymongo.errors import DuplicateKeyError

class HuxiuspiderPipeline:
    def __init__(self):
        self.client=MongoClient('localhost',
                      username='spiderdb',
                      password='password',
                      authSource='spiderdb',
                      authMechanism='SCRAM-SHA-1')
        self.db = self.client['spiderdb']
        self.collection = self.db['huxiu_links']

        self.collection.create_index("url", unique=True)

    def process_item(self, item, spider):
        item = dict(item)

        try:
            self.collection.insert_one(item)
        except DuplicateKeyError as e:
            pass

        return item

    def close_spider(self, spider):
        self.client.close()

运行爬虫

进入项目的根目录,执行下列命令启动spider:

scrapy crawl huxiu_article
# scrapy crawl huxiu_article -o dmoz.csv

完善项目-多层爬取

yield scrapy.Request(item['url'], meta={'item': item}, callback=self.detail_parse)

https://blog.csdn.net/ygc123189/article/details/79160146

注意事项

自定义spider起始方式

也可以是查询数据库的结果,但要注意数据统一性,因为scrapy是异步爬取

自定义item类型与有无

spider爬取的结果封装到item对象中,再提交给pipeline持久化,那么当然也可以忽略item对象,传递你想要的数据格式直接到pipeline。

item与pipeline对应关系

item的意思是数据实例,一个item提交后,会经过所有的pipeline,pipeline的意思是管道,就是对数据的一系列操作,设置中的管道优先级就是管道处理数据的顺序,比如日志操作等。
如果要让某一个pipeline只处理某些类型的item,可以在item进入pipelne的时候判断一下是否是你想要处理的item类型。示例如下:

class doubanPipeline(object):
    def process_item(self, item, spider):
        #判断item是否为Item1类型
        if isinstance(item,doubanTextItem):
            # 操作item
        return item

scrapy是异步执行的

同时运行多个爬虫

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

settings = get_project_settings()

crawler = CrawlerProcess(settings)

crawler.crawl('exercise')
crawler.crawl('ua')

crawler.start()
crawler.start()

post表单数据传输需要是字符串

自定义请求头

import scrapy

class AddHeadersSpider(scrapy.Spider):
    name = 'add_headers'
    allowed_domains = ['sina.com']
    start_urls = ['https://www.sina.com.cn']
    headers = {
        'User-Agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; 360SE)',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.5,en;q=0.3",
        "Accept-Encoding": "gzip, deflate",
        'Content-Length': '0',
        "Connection": "keep-alive"
    }

    def start_requests(self):
        for url in self.start_urls:
            yield scrapy.Request(url, headers=self.headers, callback=self.parse)
            
    def parse(self,response):
        print("---------------------------------------------------------")
        print("response headers: %s" % response.headers)
        print("request headers: %s" % response.request.headers)
        print("---------------------------------------------------------")

scrapy的FormRequest发送的是表单数据类型,如果要发送json类型需要使用Request

ts = round(time.time() * 1000)
form_data = {
    "nodeId": id_str,
    "excludeContIds": [],
    "pageSize": '20',
    "startTime": str(ts),
    "pageNum": '1'
}
yield scrapy.Request(url=self.url,method='POST',headers=self.headers,
                     body=json.dumps(form_data), callback=self.parse,
                     meta={'id_str': id_str})

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

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

相关文章

[管理与领导-75]:IT基层管理者 - 辅助技能 - 4- 乌卡时代(VUCA )的职业规划

目录 一、什么是职业规划的主要内容 二、乌卡时代的职业规划特点 2.1 时代特点 2.2 个人能力要求 三、乌卡时代如何做好职业规划 一、什么是职业规划的主要内容 职业规划是一个有目标和有策略的过程,通过此过程,个人能够发展和管理自己的职业生涯。…

GPDB-内核原理-如何指定发送数据目的地

GPDB-内核原理-如何指定发送数据目的地 GPDB是一个分布式数据库,数据存放在各个segment上。Master用于接收用户请求,并将执行计划发送到各个segment上去执行。各个segment将数据发送个master汇总并返回用户。当进行join,join条件不是分布键时…

3.3.2 【MySQL】客户端和服务器通信中的字符集

3.3.2.1 编码和解码使用的字符集不一致的后果 我们知道字符 我 在 utf8 字符集编码下的字节串长这样: 0xE68891 ,如果一个程序把这个字节串发送到另一个程序里,另一个程序用不同的字符集去解码这个字节串,假设使用的是 gbk 字符集…

【Ubuntu搭建MQTT Broker及面板+发布消息、订阅主题】

Ubuntu搭建MQTT Broker及面板发布消息、订阅主题 配置curl数据源 curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash开始安装 sudo apt-get install emqx启动 sudo emqx start使用面板 根据自己的服务器是否开始了防火墙放行端口(1808…

【系统设计系列】 DNS和CDN

系统设计系列初衷 System Design Primer: 英文文档 GitHub - donnemartin/system-design-primer: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards. 中文版: https://github.com/donnemarti…

MIT6.828实验记录-Lab1

1.Lab1 刚刚入门,难度确实很大,大量的参考资料,知识点涉及的较深,好在每个实验,作者都给出了很多提示,让繁琐的实验变得有趣起来。逐个exercise进行,知识点有些断片,所以特意花点时…

excel中删除重复项

数据如图: 要删除姓名这一列的重复项,操作: (1)选中姓名这一列(2)点击“数据”(3)点击“删除重复项" 这是excel会自动检测出还有别的关联列 直接默认,点击删除重复项...弹出下面的界面 因为我们只要删除“姓名”列的重复值&…

C++智能指针之unique_ptr(保姆级教学)

目录 unique_ptr 概述 涉及程序 初始化 手动初始化 std::make_unique函数(C14) unique_ptr常规操作 不支持操作:该指针不支持拷贝和赋值操作;所以不能拷贝到容器里 移动语义std::move(); release(); reset(); *解应用…

【计算机网络】 子网划分

文章目录 IP地址分类子网掩码网关广播地址非默认子网掩码子网划分常见问题 IP地址分类 学会十进制和二进制的相互转换可以很快速的有规律的记住 子网掩码 又叫网络掩码,地址掩码,子网络遮罩,就是说把子网络遮起来,不让外界窥探到…

“安全即服务”为网络安全推开一道门

8月30日,三六零(下称“360”)集团发布了2023年半年报,其中安全业务第二季度收入6.54亿元,同比增长98.76%,环比增长157.16%,安全第二增长曲线已完全成型!特别值得一提的是&#xff0c…

【Unittest】Requests实现小程序项目接口测试

文章目录 一、搭建接口测试框架二、初始化日志三、定义全局变量四、封装接口五、编写测试用例六、生成测试报告 一、搭建接口测试框架 目录结构如下。 二、初始化日志 在utils.py文件中编写如下如下代码,初始化日志。 # 导入app.py全局变量文件 import app import l…

基于Zookeeper搭建Kafka高可用集群(实践可用)

目录 一、Zookeeper集群搭建 1.1 下载 & 解压 1.2 修改配置 1.3 标识节点 1.4 启动集群 1.5 集群验证 二、Kafka集群搭建 2.1 下载解压 2.2 拷贝配置文件 2.3 修改配置 2.4 启动集群 2.5 创建测试主题 2.6 写入数据测试 一、Zookeeper集群搭建 为保证集群高可…

SV中的随机化约束

1.多个变量相互依赖,如何进行随机化? 采用solve before (1)constraint c_valid_write_data {solve access_type before data;solve burst_length before data;(access_type TVIP_AXI_WRITE_ACCESS) -> data.size() burst…

算法通过村第五关-队列和Hash黄金笔记|LRU的设计与实现

文章目录 前言1. LRU的含义2. Hash双向链表实现LRU总结 前言 提示:我曾如此渴望命运的波澜,到最后才发现:人生最曼妙的风景,竟是内心的淡定从容。 我们层如此盼望世界的认可,到最后才知道:世界是自己&#…

01-Kafaka

1、Kafka 2 的安装与配置 1、上传kafka_2.12-1.0.2.tgz到服务器并解压: tar -zxf kafka_2.12-1.0.2.tgz -C /opt 2、配置环境变量并更新: 编辑profile配置文件: vim /etc/profile #设置kafka的环境变量export KAFKA_HOME/opt/kafka_2.1…

【ESP32--FreeRTOS 任务间的同步与通信】

本文主要记录【ESP32–FreeRTOS 任务间的同步与通信】的学习记录,邮件,信号量,事件组的使用和优缺点以及应用场景 📋 个人简介 💖 作者简介:大家好,我是喜欢记录零碎知识点的小菜鸟。&#x1f6…

软件测试之随机测试

目录 一、作随机测试之前的一些前提条件 二、随机测试功能点的选取 三、功能点的随机测试 在软件测试中除了根据测试用例和测试说明书进行功能测试外,还需要进行随机测试(Ad-hoc testing),随机测试是没有书面测试用例、记录期望…

【算法】插入排序

插入排序 插入排序代码实现代码优化 排序: 排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。 稳定性: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录&…

【算法】归并排序 详解

归并排序 详解 归并排序代码实现1. 递归版本2. 非递归版本 排序: 排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。 稳定性: 假定在待排序的记录序列中,存在多个具有相…

dpkt 处理linux cooked capture

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…