为了账号安全,请及时绑定邮箱和手机立即绑定

Scrapy教程:新手入门全指南

标签:
爬虫
概述

Scrapy是一款强大的Python框架,用于抓取网站内容并结构化存储。它支持异步网络请求和多种数据解析方式,如XPath和CSS选择器。本文将详细介绍Scrapy的安装、配置及项目结构,并提供scrapy教程中的关键知识点和实战案例。

Scrapy简介与安装

Scrapy 是一个用于抓取网站并提取结构化数据的 Python 框架。它被设计用于快速抓取数据并遵循网站的链接结构,支持异步网络请求,能够处理大规模的数据抓取任务。Scrapy 提供了丰富的功能,包括内置的中间件支持、强大的XPath和CSS选择器、内置的Spider和Item管道等。Scrapy 的架构设计使得它可以轻松地扩展和维护,非常适合用于构建复杂的网络爬虫项目。同时,Scrapy 还提供了强大的错误处理机制和自动防止被网站屏蔽的能力,使得开发者可以专注于数据抓取的逻辑设计。

Scrapy是什么

Scrapy 是一个用于抓取网站并提取结构化数据的 Python 框架。它被设计用于快速抓取数据并遵循网站的链接结构,支持异步网络请求,能够处理大规模的数据抓取任务。Scrapy 提供了丰富的功能,包括内置的中间件支持、强大的XPath和CSS选择器、内置的Spider和Item管道等。Scrapy 的架构设计使得它可以轻松地扩展和维护,非常适合用于构建复杂的网络爬虫项目。同时,Scrapy 还提供了强大的错误处理机制和自动防止被网站屏蔽的能力,使得开发者可以专注于数据抓取的逻辑设计。

Scrapy安装方法

使用pip安装

Scrapy 通常通过 Python 的包管理工具 pip 来安装。首先确保已安装 Python 3.6(或更高版本)和 pip。在安装 Python 时,一般会附带安装 pip,但如果没有安装,则可以通过运行 python -m ensurepip 安装。

安装 Scrapy 可以直接执行以下命令:

pip install scrapy

使用virtualenv创建虚拟环境

为了更好地管理 Python 项目,建议使用 virtualenv 创建一个虚拟环境来安装 Scrapy。创建虚拟环境的命令如下:

virtualenv my_project

然后激活虚拟环境:

source my_project/bin/activate

在虚拟环境下安装 Scrapy:

pip install scrapy
Scrapy环境配置

安装完 Scrapy 后,需要配置 Scrapy 环境。Scrapy 配置主要涉及 Scrapy 的设置文件 settings.py,它位于 Scrapy 项目的根目录中。配置文件 settings.py 可以设置各种 Scrapy 选项,如下载延迟、日志级别、代理和用户代理等。

一个典型的 settings.py 文件内容如下:

# settings.py
BOT_NAME = 'my_spider'
SPIDER_MODULES = ['my_spider.spiders']
NEWSPIDER_MODULE = 'my_spider.spiders'

DOWNLOAD_DELAY = 1  # 下载延迟
LOG_LEVEL = 'INFO'  # 日志级别
ITEM_PIPELINES = {
    'my_spider.pipelines.MyPipeline': 300,  # 自定义管道
}
设置代理和用户代理

settings.py 中还可以设置代理和用户代理:

# 设置代理
HTTP_PROXY = 'http://proxy.example.com:8080'
DOWNLOADER_MIDDLEWARES = {
    'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 1,
}

# 设置用户代理
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
Scrapy项目创建与结构解析

创建 Scrapy 项目是开始抓取数据的第一步。Scrapy 提供了命令行工具来帮助创建和管理项目。

创建Scrapy项目

创建 Scrapy 项目使用 scrapy startproject 命令。命令格式如下:

scrapy startproject my_project

这将创建一个名为 my_project 的 Scrapy 项目,项目结构如下:

my_project/
    scrapy.cfg
    my_project/
        __init__.py
        items.py
        middlewares.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
项目结构详解

Scrapy 项目的结构如下:

  • scrapy.cfg:项目配置文件,用于配置 Scrapy 的运行环境。
  • my_project/:项目的主目录。
    • __init__.py:空文件,用于标识这个目录是一个 Python 包。
    • items.py:定义数据模型的文件。
    • middlewares.py:定义中间件的文件。
    • pipelines.py:定义数据处理管道的文件。
    • settings.py:项目的全局配置文件。
    • spiders/:存放爬虫脚本的目录。
    • __init__.py:空文件,用于标识这个目录是一个 Python 包。

items.py

items.py 文件定义了爬取数据的结构。一个典型的 items.py 文件如下:

# items.py
import scrapy

class MyItem(scrapy.Item):
    name = scrapy.Field()
    description = scrapy.Field()

middlewares.py

middlewares.py 文件定义了各种中间件,用于处理请求和响应,例如代理中间件、用户代理中间件等。一个简单的中间件示例如下:

# middlewares.py
from scrapy import signals

class MyMiddleware(object):
    @classmethod
    def from_crawler(cls, crawler):
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request, spider):
        # 拦截请求
        return None

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

pipelines.py

pipelines.py 文件定义了数据处理管道,用于处理 Item 对象,例如清洗数据、持久化数据等。一个简单的管道示例如下:

# pipelines.py
class MyPipeline(object):
    def process_item(self, item, spider):
        # 清洗数据
        return item

settings.py

settings.py 文件是项目的全局配置文件,可以设置各种 Scrapy 的选项,例如下载延迟、日志级别等。一个典型的 settings.py 文件如下:

# settings.py
BOT_NAME = 'my_project'
SPIDER_MODULES = ['my_project.spiders']
NEWSPIDER_MODULE = 'my_project.spiders'

DOWNLOAD_DELAY = 1
LOG_LEVEL = 'INFO'
ITEM_PIPELINES = {
    'my_project.pipelines.MyPipeline': 300,
}

spiders/

spiders/ 目录存放所有爬虫脚本,每个脚本都继承自 scrapy.Spider 类。一个简单的爬虫示例如下:

# spiders/my_spider.py
import scrapy

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

    def parse(self, response):
        # 解析页面
        pass
Scrapy爬虫编写基础

编写 Scrapy 爬虫是数据抓取的核心任务。Scrapy 提供了强大的功能来帮助我们编写高效的爬虫。

爬虫的定义与特点

Scrapy 爬虫是用于自动抓取网页数据的程序。一个 Scrapy 爬虫通常包含以下几个部分:

  • 名称:每个爬虫都必须有一个唯一的名称。
  • 初始 URL:爬虫开始抓取的 URL 列表。
  • 解析函数:定义如何解析响应数据,提取内容并跟踪链接。
  • 处理数据:通过管道处理提取的数据。

特点

  • 异步处理:Scrapy 使用异步网络请求,提高了抓取效率。
  • 灵活解析:支持 XPath、CSS 选择器等多种解析方式。
  • 扩展性强:支持中间件、管道、信号等扩展机制。
  • 错误处理:内置错误处理机制,防止因网络问题导致任务失败。
编写第一个简单的Scrapy爬虫

编写一个简单的 Scrapy 爬虫,抓取网站的标题和链接。

创建爬虫文件

spiders/ 目录下创建一个新的 Python 文件,例如 example_spider.py

# spiders/example_spider.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}
        for url in response.css('a::attr(href)').getall():
            yield response.follow(url, self.parse)

解析函数

  • parse 函数是 Scrapy 爬虫的默认解析函数。
  • response.css('h1::text').getall() 用于提取所有 <h1> 标签中的文本。
  • response.css('a::attr(href)').getall() 用于提取所有 <a> 标签的 href 属性。
  • response.follow(url, self.parse) 用于跟踪链接并继续抓取。

运行命令

运行爬虫使用 scrapy crawl 命令:

scrapy crawl example

这将启动名为 example 的爬虫并开始抓取数据。

Scrapy高级特性介绍

Scrapy 提供了多种高级特性来增强数据抓取的灵活性和效率。本节介绍 XPath 和 CSS 选择器,以及中间件和管道的使用。

XPath与CSS选择器

XPath 和 CSS 选择器是 Scrapy 中常用的解析工具,用于提取 HTML 文档中的内容。

XPath 示例

XPath 是一种在 XML 文档中查找信息的强大语言,Scrapy 中可以使用 XPath 来提取 HTML 中的内容。例如,提取所有 <p> 标签中的文本:

# 使用XPath提取<p>标签中的文本
for paragraph in response.xpath('//p/text()').getall():
    print(paragraph)

CSS选择器示例

CSS 选择器是另一种常用的解析工具,语法简单且易于阅读。例如,提取所有 <a> 标签的 href 属性:

# 使用CSS选择器提取所有<a>标签的href属性
for link in response.css('a::attr(href)').getall():
    print(link)

特点比较

  • XPath:适合复杂的查询,支持多种语法。
  • CSS 选择器:语法简单,适用于简单的查询。

实践示例

演示如何使用 XPath 和 CSS 选择器提取网页内容。假设要抓取一个简单的 HTML 页面:

<!DOCTYPE html>
<html>
<head><title>Example Page</title></head>
<body>
    <h1>Page Title</h1>
    <p>Paragraph 1</p>
    <ul>
        <li><a href="/link1">Link 1</a></li>
        <li><a href="/link2">Link 2</a></li>
    </ul>
</body>
</html>

使用 XPath 提取 <h1> 标签的文本:

titles = response.xpath('//h1/text()').getall()
print(titles)

使用 CSS 选择器提取 <a> 标签的 href 属性:

links = response.css('a::attr(href)').getall()
print(links)
中间件与管道的使用

Scrapy 中的中间件和管道可以增强数据抓取的灵活性和处理能力。

中间件

中间件包括请求中间件和响应中间件,用于处理请求和响应。

请求中间件

请求中间件用于修改请求和响应,例如添加代理或处理重定向。

# middlewares.py
from scrapy import signals

class ExampleMiddleware(object):
    @classmethod
    def from_crawler(cls, crawler):
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request, spider):
        request.meta['proxy'] = 'http://example.com:8080'
        return request

    def process_response(self, request, response, spider):
        return response

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

响应中间件

响应中间件用于处理响应,例如解析响应内容或处理重定向。

class AnotherMiddleware(object):
    def process_response(self, request, response, spider):
        response = response.replace(body=response.body.replace(b'old', b'new'))
        return response

管道

管道用于处理数据,例如清洗数据或持久化数据。

简单的管道示例

定义一个简单的管道,用于清洗数据:

# pipelines.py
class ExamplePipeline(object):
    def process_item(self, item, spider):
        item['title'] = item['title'].strip()
        return item

注册管道

settings.py 中注册管道:

# settings.py
ITEM_PIPELINES = {
    'my_project.pipelines.ExamplePipeline': 300,
}

实践示例

演示如何使用中间件和管道处理数据。假设要抓取一个简单的 HTML 页面:

<!DOCTYPE html>
<html>
<head><title>Example Page</title></head>
<body>
    <h1>Page Title</h1>
    <p>Paragraph 1</p>
    <ul>
        <li><a href="/link1">Link 1</a></li>
        <li><a href="/link2">Link 2</a></li>
    </ul>
</body>
</html>

使用中间件修改请求和响应:

# middlewares.py
class ExampleMiddleware(object):
    def process_request(self, request, spider):
        request.meta['proxy'] = 'http://example.com:8080'
        return request

    def process_response(self, request, response, spider):
        response = response.replace(body=response.body.replace(b'old', b'new'))
        return response

注册中间件:

# settings.py
DOWNLOADER_MIDDLEWARES = {
    'my_project.middlewares.ExampleMiddleware': 543,
}

使用管道清洗数据:

# pipelines.py
class ExamplePipeline(object):
    def process_item(self, item, spider):
        item['title'] = item['title'].strip()
        return item

注册管道:

# settings.py
ITEM_PIPELINES = {
    'my_project.pipelines.ExamplePipeline': 300,
}
Scrapy实战演练

Scrapy 的实战演练包括简单的网页数据抓取和动态网页数据抓取。

实战案例一:简单的网页数据抓取

一个简单的网页数据抓取案例用于演示如何抓取网站的内容。假设要抓取一个简单的 HTML 页面:

<!DOCTYPE html>
<html>
<head><title>Example Page</title></head>
<body>
    <h1>Page Title</h1>
    <p>Paragraph 1</p>
    <ul>
        <li><a href="/link1">Link 1</a></li>
        <li><a href="/link2">Link 2</a></li>
    </ul>
</body>
</html>

编写爬虫

创建一个新的爬虫文件 simple_spider.py

# spiders/simple_spider.py
import scrapy

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

    def parse(self, response):
        # 提取标题
        title = response.css('h1::text').get()
        print(f'Title: {title}')

        # 提取段落
        paragraphs = response.css('p::text').getall()
        for p in paragraphs:
            print(f'Paragraph: {p}')

        # 跟踪链接
        for url in response.css('a::attr(href)').getall():
            yield response.follow(url, self.parse)

运行爬虫

运行爬虫使用 scrapy crawl 命令:

scrapy crawl simple

这将抓取 http://example.com 页面的标题、段落和链接,并跟踪链接继续抓取。

实战案例二:动态网页数据抓取

动态网页数据抓取涉及到抓取 JavaScript 渲染的页面内容,通常使用 Selenium 或其他工具加载 JavaScript。

编写爬虫

创建一个新的爬虫文件 dynamic_spider.py

# spiders/dynamic_spider.py
import scrapy
from selenium import webdriver
from scrapy.selector import Selector

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

    def __init__(self):
        self.driver = webdriver.Chrome()

    def parse(self, response):
        self.driver.get(response.url).get()
        sel = Selector(text=self.driver.page_source)
        # 提取数据
        for item in sel.css('div.item'):
            yield {
                'title': item.css('h2::text').get(),
                'link': item.css('a::attr(href)').get(),
                'desc': item.css('p::text').get(),
            }
        self.driver.quit()

运行爬虫

运行爬虫使用 scrapy crawl 命令:

scrapy crawl dynamic

这将使用 Selenium 加载 JavaScript 并抓取页面内容。

Scrapy常见问题与优化建议

在使用 Scrapy 进行数据抓取时,可能会遇到一些常见问题,同时也可以通过一些技巧进行性能优化。

常见问题解答

问题1:爬虫被网站屏蔽

解决方案

  1. 使用代理:通过代理服务器访问网站,避免 IP 被封。
  2. 设置 User-Agent:修改请求头的 User-Agent,模拟不同的浏览器访问。
  3. 设置下载延迟:在 settings.py 中设置 DOWNLOAD_DELAY,减缓访问速度。
  4. 遵守网站规则:遵守网站的 robots.txt 规则,避免过度抓取。

问题2:抓取数据不全

解决方案

  1. 检查解析规则:确保解析规则准确匹配目标内容。
  2. 调试日志:查看请求和响应日志,分析数据抓取情况。
  3. 增加解析深度:增加解析深度,抓取更多层级的链接。

问题3:性能瓶颈

解决方案

  1. 优化解析规则:简化解析规则,减少不必要的解析步骤。
  2. 异步处理:利用 Scrapy 的异步特性,提高抓取效率。
  3. 合理使用中间件:在中间件中进行缓存、代理处理等,减轻服务器压力。
性能优化技巧

优化解析规则

解析规则的效率直接影响抓取性能。优化解析规则可以通过减少解析步骤、减少不必要的循环等方法。

# 不优化的解析规则
for item in response.css('div.item'):
    title = item.css('h2::text').get()
    link = item.css('a::attr(href)').get()
    desc = item.css('p::text').get()
    yield {
        'title': title,
        'link': link,
        'desc': desc,
    }

# 优化后的解析规则
items = response.css('div.item')
for item in items:
    yield {
        'title': item.css('h2::text').get(),
        'link': item.css('a::attr(href)').get(),
        'desc': item.css('p::text').get(),
    }

异步处理

Scrapy 使用异步网络请求,可以显著提高抓取效率。确保代码中尽量避免阻塞操作。

使用中间件

在中间件中进行缓存、代理处理等操作可以减轻服务器压力。

# 使用缓存中间件
class CacheMiddleware(object):
    cache = {}

    def process_request(self, request, spider):
        if request.url in self.cache:
            return self.cache[request.url]
        else:
            response = self.fetch(request)
            self.cache[request.url] = response
            return response

    def fetch(self, request):
        # 实际抓取请求
        return scrapy.http.HtmlResponse(url=request.url)

其他建议

  1. 合理使用管道:管道可以进行数据清洗和持久化处理,减少主抓取过程的压力。
  2. 监控和日志:通过日志监控抓取状态,及时发现问题。
  3. 分布式抓取:使用分布式部署提高抓取效率。

实践示例

假设要抓取一个简单的 HTML 页面:

<!DOCTYPE html>
<html>
<head><title>Example Page</title></head>
<body>
    <h1>Page Title</h1>
    <p>Paragraph 1</p>
    <ul>
        <li><a href="/link1">Link 1</a></li>
        <li><a href="/link2">Link 2</a></li>
    </ul>
</body>
</html>

优化解析规则:

# 优化后的解析规则
items = response.css('div.item')
for item in items:
    yield {
        'title': item.css('h2::text').get(),
        'link': item.css('a::attr(href)').get(),
        'desc': item.css('p::text').get(),
    }

使用缓存中间件:

# 缓存中间件
class CacheMiddleware(object):
    cache = {}

    def process_request(self, request, spider):
        if request.url in self.cache:
            return self.cache[request.url]
        else:
            response = self.fetch(request)
            self.cache[request.url] = response
            return response

    def fetch(self, request):
        # 实际抓取请求
        return scrapy.http.HtmlResponse(url=request.url)

注册缓存中间件:


# settings.py
DOWNLOADER_MIDDLEWARES = {
    'my_project.middlewares.CacheMiddleware': 543,
}
``

通过以上优化,可以显著提高 Scrapy 的抓取效率和稳定性。
点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消