【python】用 Scrapy 实现高效爬虫项目

用 Scrapy 实现高效爬虫项目

Scrapy 是一个功能强大的 Python 爬虫框架,以其高效、灵活、可扩展性而闻名。无论是处理简单的爬取任务,还是构建复杂的分布式爬虫项目,Scrapy 都能提供强有力的支持。本文将从 Scrapy 的核心概念、项目结构、优化技巧等方面,带你掌握用 Scrapy 构建高效爬虫的技巧。


一、Scrapy 的核心概念

要理解 Scrapy,首先需要掌握以下几个核心概念:

  • Spider: 爬虫类,定义爬取逻辑和处理逻辑。
  • Request: 发起 HTTP 请求,支持各种参数(如 headers、cookies 等)。
  • Response: 请求的结果,包含网页内容及相关信息。
  • Item: 数据结构,用于存储爬取到的内容。
  • Pipeline: 数据处理管道,用于清洗、存储数据。
  • Middleware: 中间件,用于处理请求和响应的行为。

二、快速搭建 Scrapy 项目

1. 创建项目

使用 scrapy startproject 命令快速生成项目模板:

scrapy startproject myproject

生成的项目结构如下:

myproject/
    scrapy.cfg           # 项目配置文件
    myproject/
        __init__.py
        items.py        # 定义数据结构
        middlewares.py  # 定义中间件
        pipelines.py    # 定义数据管道
        settings.py     # 项目设置
        spiders/        # 存放爬虫文件

2. 编写 Spider

Spider 是 Scrapy 的核心,用于定义爬取的逻辑。

创建一个简单的爬虫:

scrapy genspider example example.com

编辑 example.py

import scrapy

class ExampleSpider(scrapy.Spider):
    name = "example"
    start_urls = ['http://example.com']

    def parse(self, response):
        for title in response.css('h1::text').getall():
            yield {'title': title}

运行爬虫:

scrapy crawl example

三、高效数据提取技巧

1. 使用 CSS 和 XPath 选择器

Scrapy 提供了便捷的 CSS 和 XPath 选择器,可以轻松提取网页内容:

  • CSS 示例
titles = response.css('h1::text').getall()
  • XPath 示例
titles = response.xpath('//h1/text()').getall()

2. 使用 Item 提取结构化数据

定义一个 Item 来存储爬取的数据:

# items.py
import scrapy

class ExampleItem(scrapy.Item):
    title = scrapy.Field()
    url = scrapy.Field()

在 Spider 中使用 Item

from myproject.items import ExampleItem

def parse(self, response):
    item = ExampleItem()
    item['title'] = response.css('h1::text').get()
    item['url'] = response.url
    yield item

四、提升爬虫性能的设置和优化

1. 配置并发与延迟

settings.py 中配置以下参数来提升爬取速度:

# 设置并发数
CONCURRENT_REQUESTS = 16

# 降低爬取延迟
DOWNLOAD_DELAY = 0.5

# 每个域名的并发请求数
CONCURRENT_REQUESTS_PER_DOMAIN = 8

2. 启用持久化功能

Scrapy 提供了断点续爬的功能,可以通过以下命令启用:

scrapy crawl example --set JOBDIR=crawls/example

3. 启用缓存

对于开发和调试阶段,可以启用缓存以减少网络请求:

HTTPCACHE_ENABLED = True
HTTPCACHE_EXPIRATION_SECS = 86400  # 缓存 1 天

五、处理反爬的常见技巧

1. 设置 User-Agent

为避免被目标网站屏蔽,可以设置 User-Agent

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'

2. 使用代理

通过设置代理来隐藏真实 IP:

DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 543,
}

PROXY_POOL = [
    'http://123.123.123.123:8080',
    'http://111.111.111.111:8080',
]

import random

class ProxyMiddleware:
    def process_request(self, request, spider):
        request.meta['proxy'] = random.choice(PROXY_POOL)

3. 模拟浏览器行为

启用 scrapy-playwrightscrapy-selenium 模拟浏览器行为,处理 JavaScript 渲染的网站:

pip install scrapy-playwright

配置 settings.py

DOWNLOAD_HANDLERS = {
    'http': 'scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler',
    'https': 'scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler',
}

PLAYWRIGHT_BROWSER_TYPE = 'chromium'

六、数据存储与导出

1. 导出为 CSV 或 JSON 文件

运行爬虫时直接导出数据:

scrapy crawl example -o output.json

2. 使用 Pipeline 存储到数据库

编辑 pipelines.py,将数据存入数据库:

import sqlite3

class SQLitePipeline:

    def open_spider(self, spider):
        self.connection = sqlite3.connect('example.db')
        self.cursor = self.connection.cursor()
        self.cursor.execute('CREATE TABLE IF NOT EXISTS data (title TEXT, url TEXT)')

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

    def process_item(self, item, spider):
        self.cursor.execute('INSERT INTO data (title, url) VALUES (?, ?)', (item['title'], item['url']))
        self.connection.commit()
        return item

启用 Pipeline:

ITEM_PIPELINES = {
    'myproject.pipelines.SQLitePipeline': 300,
}

七、监控与调试

1. 使用 scrapy shell 调试

scrapy shell 'http://example.com'

在交互环境中测试选择器和解析逻辑。

2. 启用日志记录

settings.py 中设置日志级别:

LOG_LEVEL = 'INFO'

八、分布式爬虫的实现

通过 scrapy-redis 实现分布式爬虫,使用 Redis 存储任务队列和爬取状态。

安装 scrapy-redis

pip install scrapy-redis

配置爬虫使用 Redis 队列:

# settings.py
DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
SCHEDULER = 'scrapy_redis.scheduler.Scheduler'
SCHEDULER_PERSIST = True
REDIS_URL = 'redis://localhost:6379'

在 Spider 中继承 RedisSpider

from scrapy_redis.spiders import RedisSpider

class DistributedSpider(RedisSpider):
    name = 'distributed'
    redis_key = 'distributed:start_urls'

    def parse(self, response):
        yield {'url': response.url}

建议

Scrapy 是一个高效的爬虫框架,通过灵活的配置和扩展,可以轻松应对各种复杂场景。从基础的 Spider 编写到性能优化,再到分布式爬取,Scrapy 都为开发者提供了丰富的工具链。在实际项目中,根据具体需求选择合适的功能,可以最大化 Scrapy 的潜力。

九、Scrapy 实战:实现一个新闻爬虫

为了更好地理解 Scrapy 的使用,下面将通过一个实战案例,演示如何构建一个新闻爬虫,爬取指定新闻网站的文章标题、链接以及发布日期。我们将结合前面讲解的技巧,确保爬虫高效、稳定并能处理反爬措施。

1. 确定目标网站

假设我们要爬取一个新闻网站(例如 example.com),并提取以下信息:

  • 文章标题
  • 文章链接
  • 文章发布日期

2. 创建 Scrapy 项目

首先,创建 Scrapy 项目:

scrapy startproject news_scraper

进入项目目录:

cd news_scraper

3. 编写 Spider

使用 scrapy genspider 创建一个新的爬虫:

scrapy genspider news_spider example.com

编辑 news_spider.py,编写爬虫逻辑:

import scrapy

class NewsSpider(scrapy.Spider):
    name = "news_spider"
    start_urls = ['http://example.com/news']

    def parse(self, response):
        for article in response.css('div.article'):
            title = article.css('h2 a::text').get()
            link = article.css('h2 a::attr(href)').get()
            date = article.css('span.date::text').get()

            yield {
                'title': title,
                'link': response.urljoin(link),
                'date': date
            }

        # 翻页逻辑
        next_page = response.css('a.next_page::attr(href)').get()
        if next_page:
            yield response.follow(next_page, self.parse)

4. 运行爬虫

运行爬虫并输出结果到 JSON 文件:

scrapy crawl news_spider -o news.json

5. 处理反爬

目标网站可能会有反爬机制,如 IP 限制、请求频率控制等。我们可以通过以下方式进行优化:

1. 设置 User-Agent

修改 settings.py 文件,设置 User-Agent 伪装成真实浏览器:

USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36'
2. 设置请求延迟

通过配置 DOWNLOAD_DELAY,降低爬取速度,减少被封禁的风险:

DOWNLOAD_DELAY = 1  # 1秒的延迟
CONCURRENT_REQUESTS = 8  # 设置并发请求数
3. 使用代理池

为了避免因频繁请求同一网站而被封,我们可以使用代理池。首先,安装 scrapy-proxies 库:

pip install scrapy-proxies

然后,在 settings.py 中配置代理:

DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 543,
}

PROXY_POOL = [
    'http://123.123.123.123:8080',
    'http://111.111.111.111:8080',
    # 添加更多代理地址
]

import random

class ProxyMiddleware:
    def process_request(self, request, spider):
        request.meta['proxy'] = random.choice(PROXY_POOL)
4. 启用缓存

为了提高开发效率,避免频繁请求,启用缓存:

HTTPCACHE_ENABLED = True
HTTPCACHE_EXPIRATION_SECS = 86400  # 缓存1天

6. 数据存储与清洗

1. 存储到数据库

如果数据量较大,可以将数据存储到数据库中,而不是直接导出到文件。我们可以通过 Scrapy 的 Pipeline 功能将数据存入 SQLite 数据库。

首先,创建一个数据库 Pipeline:

# pipelines.py
import sqlite3

class SQLitePipeline:

    def open_spider(self, spider):
        self.connection = sqlite3.connect('news.db')
        self.cursor = self.connection.cursor()
        self.cursor.execute('CREATE TABLE IF NOT EXISTS news (title TEXT, link TEXT, date TEXT)')

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

    def process_item(self, item, spider):
        self.cursor.execute('INSERT INTO news (title, link, date) VALUES (?, ?, ?)', 
                            (item['title'], item['link'], item['date']))
        self.connection.commit()
        return item

settings.py 中启用该 Pipeline:

ITEM_PIPELINES = {
    'news_scraper.pipelines.SQLitePipeline': 1,
}
2. 数据清洗

如果从网页提取的数据不完全或者需要处理额外的字段(如日期格式化),可以在 Pipeline 中进行数据清洗。例如,将日期格式化为统一的标准格式:

from datetime import datetime

class DateFormatPipeline:

    def process_item(self, item, spider):
        item['date'] = datetime.strptime(item['date'], '%Y-%m-%d').strftime('%d/%m/%Y')
        return item

settings.py 中启用:

ITEM_PIPELINES = {
    'news_scraper.pipelines.DateFormatPipeline': 2,
    'news_scraper.pipelines.SQLitePipeline': 1,
}

7. 分布式爬虫(可选)

如果爬取的新闻量巨大,可以使用 scrapy-redis 来实现分布式爬虫。通过 Redis 存储 URL 队列并在多个爬虫实例之间共享任务。

首先,安装 scrapy-redis

pip install scrapy-redis

settings.py 中进行配置:

DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
SCHEDULER = 'scrapy_redis.scheduler.Scheduler'
SCHEDULER_PERSIST = True
REDIS_URL = 'redis://localhost:6379'

修改 Spider 以使用 Redis:

from scrapy_redis.spiders import RedisSpider

class RedisNewsSpider(RedisSpider):
    name = "redis_news_spider"
    redis_key = 'news:start_urls'

    def parse(self, response):
        for article in response.css('div.article'):
            title = article.css('h2 a::text').get()
            link = article.css('h2 a::attr(href)').get()
            date = article.css('span.date::text').get()
            yield {'title': title, 'link': link, 'date': date}

十、总结与展望

在这篇博客中,我们通过实战示例讲解了如何使用 Scrapy 构建高效的新闻爬虫项目。通过合理的配置、性能优化、反爬机制处理及数据存储管理,我们能确保爬虫高效、稳定并能够适应大规模的数据抓取需求。

关键技巧总结:

  • 高效的数据提取:合理使用 CSS 和 XPath 选择器,提取结构化数据。
  • 性能优化:通过设置并发、延迟、使用代理池等手段提升爬虫效率。
  • 数据存储:将爬取的数据存储到数据库或文件中,确保数据持久化。
  • 反爬机制:通过伪装 User-Agent、使用代理、模拟浏览器等手段绕过反爬措施。
  • 分布式爬取:通过 Scrapy-Redis 实现分布式爬虫,处理大规模数据抓取任务。

通过这些技巧,你可以开发出一个高效、稳定、能够应对复杂挑战的 Scrapy 爬虫项目。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux 进程信号的产生

目录 0.前言 1. 通过终端按键产生信号 1.1 CtrlC:发送 SIGINT 信号 1.2 Ctrl\:发送 SIGQUIT 信号 1.3 CtrlZ:发送 SIGTSTP 信号 2.调用系统命令向进程发信号 3.使用函数产生信号 3.1 kill 函数 3.2 raise 函数 3.3 abort 函数 4.由软件条件产…

【大数据学习 | HBASE高级】hive操作hbase

一般在查询hbase的数据的时候我们可以直接使用hbase的命令行或者是api进行查询就行了,但是在日常的计算过程中我们一般都不是为了查询,都是在查询的基础上进行二次计算,所以使用hbase的命令是没有办法进行数据计算的,并且对于hbas…

微信小程序 https://thirdwx.qlogo.cn 不在以下 downloadFile 合法域名列表中

授权登录后,拿到用户头像进行加载,但报错提示: https://thirdwx.qlogo.cn 不在以下 downloadFile 合法域名列表中 解决方法一(未完全解决,临时处理):在微信开发者工具将不校验...勾上就可以访问…

rk3399开发环境使用Android 10初体验蓝牙功能

版本 日期 作者 变更表述 1.0 2024/11/10 于忠军 文档创建 零. 前言 由于Bluedroid的介绍文档有限,以及对Android的一些基本的知识需要了(Android 四大组件/AIDL/Framework/Binder机制/JNI/HIDL等),加上需要掌握的语言包括Java/C/C等&#xff0…

1. Django中的URL调度器 (项目创建与简单测试)

1. 创建 Django 项目 运行以下命令创建一个名为 blog_project 的 Django 项目: django-admin startproject blog_project2. 创建博客应用 Django 中,项目可以包含多个应用。创建一个名为 blog 的应用: cd blog_project python manage.py …

数据结构(初阶4)---循环队列详解

循环队列 1.循环队列的结构  1).逻辑模式 2.实现接口  1).初始化  2).判断空和满  3).增加  4).删除  5).找头  6).找尾 3.循环队列的特点 1.循环队列的结构 1).逻辑模式 与队列是大同小异的, 其中还是有一个指向队列头的head指针, 也有一个指向尾…

【蓝桥杯算法】Java的基础API

1. BigInteger 的使用 1.1. 判素数 package 模板;import java.math.BigInteger; import java.util.Scanner;public class 判素数 {static Scanner in new Scanner(System.in);public static void main(String[] args) {int q in.nextInt();while (q-- > 0) {BigInteger …

STM32设计井下瓦斯检测联网WIFI加Zigbee多路节点协调器传输

目录 目录 前言 一、本设计主要实现哪些很“开门”功能? 二、电路设计原理图 1.电路图采用Altium Designer进行设计: 2.实物展示图片 三、程序源代码设计 四、获取资料内容 前言 本系统基于STM32微控制器和Zigbee无线通信技术,设计了…

320页PDF | 集团IT蓝图总体规划报告-德勤(限免下载)

一、前言 这份报告是集团IT蓝图总体规划报告-德勤。在报告中详细阐述了德勤为某集团制定的全面IT蓝图总体规划,包括了集团信息化目标蓝图、IT应用规划、数据规划、IT集成架构、IT基础设施规划以及IT治理体系规划等关键领域,旨在为集团未来的信息化发展提…

Python毕业设计选题:基于django+vue的二手物品交易系统

开发语言:Python框架:djangoPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 管理员登录 管理员功能界面 用户管理 店铺管理 二手物品管理 广告管理 留言反馈 订单…

Android CoordinatorLayout:打造高效交互界面的利器

目录 一、CoordinatorLayout 介绍及特点 二、使用方法 2.1 创建 CoordinatorLayout 布局 2.2 添加需要协调的子视图 2.3 自定义 Behavior 三、结语 相关推荐 在Android开发中,面对复杂多变的用户界面需求,CoordinatorLayout以其强大的交互管理能力…

docker-hub 无法访问,使用windows魔法拉取docker images再上传到linux docker环境中

云机的服务器是可以docker拉取镜像的,但是本地的虚拟机、物理服务器等网络环境不好的情况,是无法访问docker-hub的,即使更换了docker镜像源国内源也无法使用。 本文章使用 在魔法网络环境下的windows,下载docker images后&#xf…

在Ubuntu22.04上源码构建ROS noetic环境

Ubuntu22.04上源码构建ROS noetic 起因准备环境创建工作目录并下载源码安装编译依赖包安装ros_comm和rosconsole包的两个补丁并修改pluginlib包的CMakeLists的编译器版本编译安装ROS noetic和ros_test验证 起因 最近在研究VINS-Mono从ROS移植到ROS2,发现在编写feat…

【linux学习指南】VSCode部署Ubantu云服务器,与Xshell进行本地通信文件编写

文章目录 📝前言🌠 步骤🌉测试同步 🚩总结 📝前言 本文目的是讲使用Vscode连接Ubantu,与本地Xshell建立通信同步文件编写。 查看本机系统相关信息: cat /etc/lsb*DISTRIB_IDUbuntu: 表示这是 Ubuntu 发行…

【JavaSE线程知识总结】

多线程 一.创建线程1.多线程创建方式一(Thread)2.多线程创键方式二(Runnable)3.线程创建方式三 二.线程安全问题解决办法1.使用同步代码块synchornized 2 .使用Lock解决线程安全问题 三.总结 线程就是程序内部的一条执行流程 一.创建线程 常用的方法 Thread.currentThread()…

用OMS进行 OceanBase 租户间数据迁移的测评

基本概念 OceanBase迁移服务(,简称OMS),可以让用户在同构或异构 RDBMS 与OceanBase 数据库之间进行数据交互,支持数据的在线迁移,以及实时增量同步的复制功能。 OMS 提供了可视化的集中管控平台&#xff…

第一个 Flutter 项目(1)共46节

前端开发工具vs code,安装Flutter sdk,如果你的下载速度比较慢,可以选择这个😄 flutter sdk 解压码:stwq 配置可以看这Flutter 新建工程一直等待 解决办法-CSDN博客 如果你是新的 Flutter 开发者,我们建…

POI实现根据PPTX模板渲染PPT

目录 1、前言 2、了解pptx文件结构 3、POI组件 3.1、引入依赖 3.2、常见的类 3.3、实现原理 3.4、关键代码片段 3.4.1、获取ppt实例 3.4.2、获取每页幻灯片 3.4.3、循环遍历幻灯片处理 3.4.3.1、文本 3.4.3.2、饼图 3.4.3.3、柱状图 3.4.3.4、表格 3.4.3.5、本地…

高级数据结构——hash表与布隆过滤器

文章目录 hash表与布隆过滤器1. hash函数2. 选择hash函数3. 散列冲突3.1 负载因子3.2 冲突解决3. STL中的散列表 4. 布隆过滤器4.1 背景1. 应用场景2. 常见的处理场景: 4.2 布隆过滤器构成4.3 原理4.4 应用分析4.5 要点 5. 分布式一致性hash5.1 缓存失效问题 6. 大数…

小程序19-微信小程序的样式和组件介绍

在小程序中不能使用 HTML 标签,也就没有 DOM 和 BOM,CSS 也仅支持部分选择器 小程序提供了 WXML 进行页面结构的编写,WXSS 进行页面的样式编写 WXML 提供了 view、text、image、navigator等标签构建页面结构,小程序中标签称为组件…