Python библиотека Scrapy

Scrapy — это мощный фреймворк для веб-скрапинга на Python, специально предназначенный для обхода веб-страниц и извлечения информации.

Scrapy часто используется в таких приложениях, как интеллектуальный анализ данных, обработка информации или хранение исторических данных.

Scrapy имеет множество встроенных полезных функций, таких как обработка запросов, отслеживание состояния, обработка ошибок, управление ограничениями частоты запросов и т. д., что делает его очень подходящим для эффективного распределённого веб-скрапинга.

В отличие от простых библиотек веб-скрапинга (таких какrequestsиBeautifulSoup), Scrapy — это полнофункциональный фреймворк для веб-скрапинга с высокой степенью масштабируемости и гибкости, подходящий для сложных и крупномасштабных задач веб-скрапинга.

Официальный сайт Scrapy:https://scrapy.org/。

Возможности и введение в Scrapy:https://www.example.com/w3cnote/scrapy-detail.html。

Схема архитектуры Scrapy (зелёная линия — поток данных):

Работа Scrapy основана на следующих основных компонентах:

  • Spider: класс Spider, используемый для определения того, как извлекать данные с веб-страниц и как переходить по ссылкам на веб-страницах.
  • Item: Используется для определения и хранения собранных данных. Эквивалентен модели данных.
  • Pipeline: Используется для обработки собранных данных, обычно для очистки, хранения данных и других операций.
  • Промежуточное ПО: используется для обработки запросов и ответов, может использоваться для настройки прокси, обработки куки, пользовательских агентов и т. д.
  • Настройки: используются для настройки различных параметров проекта Scrapy, таких как задержка запросов, количество одновременных запросов и т. д.

Установка Scrapy

Перед использованием Scrapy его нужно сначала установить. Для установки мы используем pip:

pip install scrapy

Структура проекта Scrapy

Проект Scrapy — это структурированный каталог, содержащий несколько папок и модулей, предназначенный для того, чтобы помочь вам организовать код ваших пауков.

Scrapy использует инструменты командной строки для создания проектов пауков и управления ими. Вы можете использовать следующую команду для создания нового проекта Scrapy:

scrapy startproject myproject

Это создаст проект с именем myproject, со следующей примерной структурой проекта:

myproject/
    scrapy.cfg            # 项目的配置文件
    myproject/            # 项目源代码文件夹
        __init__.py
        items.py          # 定义抓取的数据结构
        middlewares.py    # 定义中间件
        pipelines.py      # 定义数据处理管道
        settings.py       # 项目的设置文件
        spiders/           # 存放爬虫代码的文件夹
            __init__.py
            myspider.py   # 自定义的爬虫代码

Написание простого паука Scrapy

Ниже приведён базовый пример паука Scrapy, который показывает, как извлекать данные с веб-страниц.

Мы создаём проект паука:

scrapy startproject example_test_spiders

Выполните указанную выше команду; в случае успеха будет выведено:

templates/project', created in:/Users/Example/example-test/example_test_spiders

You can start your first spider with:
    cd example_test_spiders
    scrapy genspider example example.com

Структура сгенерированного проекта выглядит следующим образом:

Затем перейдите в этот каталог:

cd example_test_spiders

Далее используйтеscrapy genspiderкоманду для создания паука:

scrapy genspider douban_spider movie.douban.com

Структура каталогов выглядит следующим образом:

В каталоге example_test_spiders создаётся файл с именем douban_spider.py, код которого выглядит следующим образом:

Пример

import scrapy


class DoubanSpiderSpider(scrapy.Spider):
    name = "douban_spider"
    allowed_domains = ["movie.douban.com"]
    start_urls = ["https://movie.douban.com"]

    def parse(self, response):
        pass

Пояснение к коду:

  • name: Определяет имя паука; оно должно быть уникальным.
  • allowed_domains: Ограничивает домен доступа паука, не позволяя пауку обходить страницы на других доменах.
  • start_urls: Определяет начальные страницы паука; паук начнет обход с этих страниц.
  • parse:parseМетод является основной частью каждого паука, используется для обработки ответов и извлечения данных. Он получаетresponseобъект, представляющий содержимое страницы, возвращенное сервером.

Напишите код паука

Перед написанием кода паука нам нужно учесть несколько моментов:

  • Такие сайты, как Douban, могут обнаружить поведение паука; рекомендуется установить USER_AGENT и DOWNLOAD_DELAY, чтобы имитировать поведение обычного пользователя.
  • При сборе данных, пожалуйста, соблюдайте правила файла robots.txt целевого сайта, чтобы не создавать слишком большую нагрузку на сервер.
  • Если вы сканируете слишком часто, вы можете вызвать блокировку по IP.

Измените конфигурацию settings.py

Добавьте следующую конфигурацию в settings.py, чтобы имитировать запросы браузера и обойти механизмы защиты от сбора данных:

# 设置 User-Agent
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'

# 不遵守 robots.txt 规则
ROBOTSTXT_OBEY = False

# 设置下载延迟,避免过快请求
DOWNLOAD_DELAY = 2

# 启用自动限速扩展
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 2
AUTOTHROTTLE_MAX_DELAY = 5

В коде паука добавьте пользовательские заголовки запросов (такие как User-Agent и Referer), чтобы еще больше имитировать поведение браузера.

Откройте файл douban_spider.py и измените его содержимое следующим образом:

Пример

import scrapy

class DoubanSpider(scrapy.Spider):
    name = "douban_spider"
    start_urls = [
        'https://movie.douban.com/top250',
    ]

    def start_requests(self):
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
            'Referer': 'https://movie.douban.com/',
        }
        for url in self.start_urls:
            yield scrapy.Request(url, headers=headers, callback=self.parse)

    def parse(self, response):
        for movie in response.css('div.item'):
            yield {
                'title': movie.css('span.title::text').get(),
                'rating': movie.css('span.rating_num::text').get(),
                'quote': movie.css('span.inq::text').get(),
            }

        # Обработка пагинации
        next_page = response.css('span.next a::attr(href)').get()
        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)

Анализ кода:

  1. name = "douban_spider": Определяет имя паука.

  2. start_urls: Определяет начальный URL, с которого паук начинает обход (страница Douban Movie Top 250).

  3. parsemethod:

    • Использует CSS-селекторы для извлечения названия, рейтинга и описания каждого фильма.

    • span.title::text: Извлекает название фильма.

    • span.rating_num::text: Извлекает рейтинг фильма.

    • span.inq::text: Извлекает описание фильма.

  4. Обработка пагинации:

    • Используйтеspan.next a::attr(href)чтобы извлечь ссылку на следующую страницу.

    • Если следующая страница существует, используйтеresponse.followчтобы продолжить сканирование.

Выполните следующую команду в командной строке, чтобы запустить паука:

scrapy crawl douban_spider -o douban_movies.csv

Это запустит паука и сохранит извлечённые данные в файл douban_movies.csv.

Примечание: вышеуказанный контент предназначен только для учебных целей. При сборе данных соблюдайте правила файла robots.txt целевого веб-сайта.


Общие методы

1. Методы паука

Название метода Описание Пример
start_requests() Генерирует начальный запрос; вы можете настроить заголовки запроса, методы запроса и т. д. yield scrapy.Request(url, callback=self.parse)
parse(response) Обрабатывает ответ и извлекает данные; это основной метод паука. yield {'title': response.css('h1::text').get()}
follow(url, callback) Автоматически обрабатывает относительные URL-адреса и генерирует новые запросы для пагинации или навигации по ссылкам. yield response.follow(next_page, callback=self.parse)
closed(reason) Вызывается при закрытии паука, используется для очистки ресурсов или записи логов. def closed(self, reason): print('Spider closed:', reason)
log(message) Информация журнала. self.log('This is a log message')

2. Методы извлечения данных

Название метода Описание Пример
response.css(selector) Используйте CSS-селекторы для извлечения данных. title = response.css('h1::text').get()
response.xpath(selector) Используйте XPath-селекторы для извлечения данных. title = response.xpath('//h1/text()').get()
get() fromSelectorListИзвлечь первый совпадающий результат (строку) из title = response.css('h1::text').get()
getall() fromSelectorListИзвлечь все совпадающие результаты (список) из titles = response.css('h1::text').getall()
attrib Извлечь атрибуты текущего узла. link = response.css('a::attr(href)').get()

3. Методы запроса и ответа

Название метода Описание Пример
scrapy.Request(url, callback, method, headers, meta) Создать новый запрос. yield scrapy.Request(url, callback=self.parse, headers=headers)
response.url Получить URL текущего ответа. current_url = response.url
response.status Получить код состояния ответа. if response.status == 200: print('Success')
response.meta Получить дополнительные данные, переданные в запросе. value = response.meta.get('key')
response.headers Получить заголовки ответа. content_type = response.headers.get('Content-Type')

4. Методы промежуточного ПО и конвейера

Название метода Описание Пример
process_request(request, spider) Обработать запрос перед его отправкой (промежуточное ПО загрузчика). request.headers['User-Agent'] = 'Mozilla/5.0'
process_response(request, response, spider) Обработать ответ после его возврата (промежуточное ПО загрузчика). if response.status == 403: return request.replace(dont_filter=True)
process_item(item, spider) Обработать извлечённые данные (конвейер). if item['price'] < 0: raise DropItem('Invalid price')
open_spider(spider) Вызывается при запуске паука (конвейер). def open_spider(self, spider): self.file = open('items.json', 'w')
close_spider(spider) Вызывается при закрытии паука (конвейер). def close_spider(self, spider): self.file.close()

5. Инструменты и методы расширений

Название метода Описание Пример
scrapy shell Запустить интерактивную оболочку Shell для отладки и тестирования селекторов. scrapy shell 'http://example.com'
scrapy crawl <spider_name> Запустить указанного паука. scrapy crawl myspider -o output.json
scrapy check Проверить корректность кода паука. scrapy check
scrapy fetch Скачать содержимое указанного URL. scrapy fetch 'http://example.com'
scrapy view Посмотреть страницу, загруженную Scrapy, в браузере. scrapy view 'http://example.com'

6. Общие настройки (дляsettings.py)

Параметр настройки Описание Пример
USER_AGENT Установите User-Agent в заголовке запроса. USER_AGENT = 'Mozilla/5.0'
ROBOTSTXT_OBEY Соблюдать лиrobots.txtправила. ROBOTSTXT_OBEY = False
DOWNLOAD_DELAY Установите задержку загрузки, чтобы не делать запросы слишком быстро. DOWNLOAD_DELAY = 2
CONCURRENT_REQUESTS Установите количество одновременных запросов. CONCURRENT_REQUESTS = 16
ITEM_PIPELINES Включите конвейеры. ITEM_PIPELINES = {'myproject.pipelines.MyPipeline': 300}
AUTOTHROTTLE_ENABLED Включите расширение auto-throttle. AUTOTHROTTLE_ENABLED = True

7. Другие распространённые методы

Название метода Описание Пример
response.follow_all(links, callback) Обрабатывайте ссылки пакетами и генерируйте запросы. yield from response.follow_all(links, callback=self.parse)
response.json() Преобразовать содержимое ответа в формат JSON. data = response.json()
response.text Получить текстовое содержимое ответа. html = response.text
response.selector Получить содержимое ответаSelectorобъект. title = response.selector.css('h1::text').get()

В таблице выше перечислены часто используемые методы в Scrapy и их функции. Эти методы охватывают различные аспекты разработки краулеров, включая генерацию запросов, извлечение данных, обработку промежуточного ПО, операции с конвейером и т. д. Освоив эти методы, вы сможете эффективно писать и управлять краулерами Scrapy. Для более подробных возможностей обратитесь кОфициальная документация Scrapy。


Примеры использования метода

1. start_requests()

start_requests()Метод является точкой входа краулера Scrapy, используемой для генерации начальных запросов. Обычно начальный URL краулера задаётся в этом методе.

Пример

import scrapy

class MySpider(scrapy.Spider):
    name = 'myspider'
   
    def start_requests(self):
        urls = [
            'http://example.com/page1',
            'http://example.com/page2',
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

2. parse()

parse()Этот метод — метод обработки ответов по умолчанию, используемый для разбора ответов и извлечения данных или создания новых запросов.

Пример

def parse(self, response):
    # Извлечь заголовок страницы
    title = response.css('title::text').get()
    yield {
        'title': title
    }

3. parse_item()

parse_item()Метод используется для разбора ответа отдельного элемента (Item), обычно для извлечения структурированных данных.

Пример

def parse_item(self, response):
    item = {}
    item['name'] = response.css('div.name::text').get()
    item['price'] = response.css('div.price::text').get()
    yield item

4. follow()

follow()Метод используется для создания новых запросов и автоматической обработки ответов, обычно для отслеживания ссылок.

Пример

def parse(self, response):
    for link in response.css('a::attr(href)'):
        yield response.follow(link, self.parse_item)

5. yield

yieldКлючевое слово используется для генерации запросов или элементов (Item) и передачи их движку Scrapy для обработки.

Пример

def parse(self, response):
    yield {
        'title': response.css('title::text').get()
    }

6. Item

ItemКласс используется для определения структур данных, обычно для хранения данных, извлечённых с веб-страниц.

Пример

import scrapy

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

7. ItemLoader

ItemLoaderКласс используется для загрузки и заполнения объектов Item, упрощая рабочий процесс извлечения и обработки данных.

Пример

from scrapy.loader import ItemLoader
from myproject.items import MyItem

def parse(self, response):
    loader = ItemLoader(item=MyItem(), response=response)
    loader.add_css('name', 'div.name::text')
    loader.add_css('price', 'div.price::text')
    yield loader.load_item()

8. Request

RequestКласс используется для создания объектов HTTP-запросов, обычно для определения URL-адресов запросов, методов обратного вызова и т. д.

Пример

import scrapy

def parse(self, response):
    yield scrapy.Request(url='http://example.com/page3', callback=self.parse_item)

9. Response

ResponseКласс представляет объект HTTP-ответа, содержащий такую информацию, как содержимое HTML и код состояния, возвращаемый сервером.

Пример

def parse(self, response):
    print(response.status)  # Вывести код состояния ответа
    print(response.body)    # Вывести содержимое ответа

10. Selector

SelectorКласс используется для извлечения данных из документов HTML или XML, поддерживая селекторы XPath и CSS.

Пример

def parse(self, response):
    title = response.xpath('//title/text()').get()
    yield {
        'title': title
    }

11. CrawlSpider

CrawlSpiderЭто специальный класс Spider, используемый для обработки сложных правил обхода и отслеживания ссылок.

Пример

from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor

class MyCrawlSpider(CrawlSpider):
    name = 'mycrawlspider'
    allowed_domains = ['example.com']
    start_urls = ['http://example.com']

    rules = (
        Rule(LinkExtractor(allow=('page/\d+',)), callback='parse_item'),
    )

    def parse_item(self, response):
        yield {
            'title': response.css('title::text').get()
        }

12. LinkExtractor

LinkExtractorКласс используется для извлечения ссылок из ответов, обычно для автоматического отслеживания ссылок на страницах.

Пример

from scrapy.linkextractors import LinkExtractor

def parse(self, response):
    extractor = LinkExtractor(allow=('page/\d+',))
    links = extractor.extract_links(response)
    for link in links:
        yield scrapy.Request(link.url, callback=self.parse_item)

13. Pipeline

PipelineКласс используется для обработки собранных данных, обычно для очистки данных, хранения и других операций.

Пример

class MyPipeline:
    def process_item(self, item, spider):
        # Обработка данных элемента
        return item

14. Middleware

MiddlewareКласс используется для промежуточной обработки запросов и ответов, обычно для изменения заголовков запросов, обработки исключений и т. д.

Пример

class MyMiddleware:
    def process_request(self, request, spider):
        # Изменить заголовки запроса
        request.headers['User-Agent'] = 'MyCustomUserAgent'
        return None
Другие расширения