Downloader Middleware — это промежуточное ПО загрузки, которое представляет собой модуль обработки между запросом и ответом Scrapy. Давайте сначала посмотрим на его архитектуру, как показано на рисунке ниже.
Планировщик берет запрос из очереди и отправляет его загрузчику для выполнения загрузки, этот процесс будет обрабатываться промежуточным программным обеспечением загрузчика. Кроме того, когда загрузчик завершит загрузку запроса и вернет ответ пауку, он снова будет обработан промежуточным программным обеспечением загрузчика.
Другими словами, во всей архитектуре Downloader Middleware играет роль в следующих двух местах:
Перед тем, как планировщик отправит поставленный в очередь запрос Doanloader для загрузки, то есть мы можем изменить его до того, как запрос выполнит загрузку.
Прежде чем ответ, сгенерированный после загрузки, будет отправлен пауку, то есть мы можем изменить сгенерированный ответ до того, как он будет проанализирован пауком.
Функция Downloader Middleware очень мощная, и такие функции, как изменение User-Agent, обработка перенаправления, настройка прокси-сервера, повторная попытка при сбое, настройка файлов cookie и т. д., должны быть реализованы вместе с ним. Давайте взглянем на подробное использование промежуточного программного обеспечения Downloader.
1. Инструкция по применению
Следует отметить, что Scrapy на самом деле предоставил много промежуточного программного обеспечения загрузчика, такого как промежуточное программное обеспечение, отвечающее за повторную попытку при сбое, автоматическое перенаправление и другие функции.DOWNLOADER_MIDDLEWARES_BASE
переменная определена.
DOWNLOADER_MIDDLEWARES_BASE
Содержимое переменной следующее:
{
'scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware': 100,
'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware': 300,
'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware': 350,
'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware': 400,
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware': 500,
'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
'scrapy.downloadermiddlewares.ajaxcrawl.AjaxCrawlMiddleware': 560,
'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware': 580,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 590,
'scrapy.downloadermiddlewares.redirect.RedirectMiddleware': 600,
'scrapy.downloadermiddlewares.cookies.CookiesMiddleware': 700,
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
'scrapy.downloadermiddlewares.stats.DownloaderStats': 850,
'scrapy.downloadermiddlewares.httpcache.HttpCacheMiddleware': 900,
}
Это формат словаря. Имя ключа словаря — это имя промежуточного программного обеспечения загрузчика, встроенного в Scrapy. Значение ключа представляет собой приоритет вызова. Приоритет — число. Чем меньше число, тем ближе к движку Scrapy , Чем больше номер, тем ближе к Downloader. , Downloader Middleware с меньшими номерами будет вызываться первым.
Если в проект необходимо добавить промежуточное программное обеспечение загрузчика, определенное вами,DOWNLOADER_MIDDLEWARES_BASE
Переменные не могут быть изменены напрямую. Scrapy предоставляет еще одну переменную настройкиDOWNLOADER_MIDDLEWARES
, мы можем напрямую изменить эту переменную, чтобы добавить наше собственное промежуточное ПО Downloader и отключитьDOWNLOADER_MIDDLEWARES_BASE
Промежуточное программное обеспечение загрузчика, определенное внутри. Давайте подробно рассмотрим использование Downloader Middleware.
Основной метод
Встроенное ПО промежуточного слоя Downloader в Scrapy предоставляет базовые функции для Scrapy, но в реальных проектах нам часто приходится определять промежуточное ПО Downloader отдельно. Не волнуйтесь, процесс очень простой, нам нужно всего лишь реализовать несколько методов.
Каждое промежуточное ПО загрузчика определяет класс с одним или несколькими методами. Основные методы следующие.
process_request(request, spider)
.process_response(request, response, spider)
.process_exception(request, exception, spider)
.
Нам нужно реализовать хотя бы один метод для определения промежуточного программного обеспечения загрузчика. Давайте посмотрим на подробное использование этих трех методов.
1. process_request(request, spider)
Прежде чем запрос будет отправлен загрузчику движком Scrapy,process_request()
Метод будет вызван, то есть до того, как Запрос будет отправлен из очереди и загружен и выполнен Загрузчиком, мы можем использоватьprocess_request()
Метод обрабатывает запрос. Возвращаемое значение метода должно быть одним из следующих: None, Response object, Request object или throw.IgnoreRequest
аномальный.
process_request()
Параметры метода следующие.
request
, является объектом запроса, то есть обрабатываемым запросом.spider
, является объектом Паука, то есть Пауком, соответствующим этому Запросу.
Различные типы возврата имеют разные эффекты. Ниже приводится сводка различных ситуаций возврата.
Когда возвращается None, Scrapy продолжит обработку запроса, а затем выполнит другие промежуточные программы Downloader.
process_request()
Метод не заканчивается, пока загрузчик не выполнит запрос и не получит ответ. Этот процесс на самом деле является процессом изменения запроса.Различные промежуточные программы загрузчика изменяют запрос по очереди в соответствии с установленным порядком приоритетов и, наконец, отправляют его загрузчику для выполнения.При возврате в виде объекта Response промежуточное ПО загрузчика с более низким приоритетом
process_request()
иprocess_exception()
метод больше не будет вызываться, каждый компонент Downloader Middlewareprocess_response()
Вместо этого методы вызываются последовательно. После завершения вызова объект Response напрямую отправляется в Spider для обработки.При возврате в качестве объекта запроса промежуточное ПО загрузчика с более низким приоритетом
process_request()
Метод перестает выполняться. Этот запрос будет возвращен в очередь планирования. Фактически, это совершенно новый запрос, ожидающий планирования. Если запланировано планировщиком, то все промежуточное ПО загрузчикаprocess_request()
Методы будут повторно выполнены по порядку.если
IgnoreRequest
выдается исключение, все ПО промежуточного слоя загрузчикаprocess_exception()
Методы выполняются последовательно. Если нет метода для обработки этого исключения, то запросerrorback()
метод будет вызван обратно. Если исключение не было обработано, оно игнорируется.
2. process_response(request, response, spider)
После того, как загрузчик выполнит загрузку запроса, он получит соответствующий ответ. Движок Scrapy отправит ответ пауку для разбора. Перед отправкой мы все можем использоватьprocess_response()
метод обработки ответа. Возвращаемое значение метода должно быть одним из объектов Request, Response или вызывать исключение IgnoreRequest.
process_response()
Параметры метода следующие.
request
, является объектом Запроса, то есть Запросом, соответствующим этому Отклику.response
, является объектом Response, то есть обработанным Response.spider
, является объектом Spider, то есть Spider, соответствующим этому Response.
Ниже приводится сводка различных ситуаций возврата.
При возврате в качестве объекта запроса промежуточное ПО загрузчика с более низким приоритетом
process_response()
Метод больше не будет вызываться. Объект запроса будет возвращен в очередь планирования для планирования, что эквивалентно совершенно новому запросу. Тогда запрос будетprocess_request()
методы обрабатываются последовательно.При возврате в виде объекта Response промежуточное ПО загрузчика с более низким приоритетом
process_response()
Метод будет продолжать вызываться и продолжать обрабатывать объект Response.Если выдается исключение IgnoreRequest, запрос
errorback()
метод перезвонит. Если исключение не было обработано, оно игнорируется.
3. process_exception(request, exception, spider)
Когда загрузчик илиprocess_request()
Когда метод выдает исключение, напримерIgnoreRequest
аномальный,process_exception()
метод будет вызван. Возвращаемое значение метода должно быть одним из None, объекта Response и объекта Request.
process_exception()
Параметры метода следующие.
request
, является объектом запроса, то есть запросом, вызвавшим исключение.exception
, является объектом Exception, то есть выброшенным исключением.spdier
, является объектом Spider, то есть Spider, соответствующим Запросу.
Ниже приведены различные возвращаемые значения.
Если возвращено значение «Нет», промежуточное ПО загрузчика с более низким приоритетом
process_exception()
Будет продолжать вызываться последовательно, пока все методы не будут отправлены.При возврате в виде объекта Response промежуточное ПО загрузчика с более низким приоритетом
process_exception()
метод больше не вызывается постоянно, каждое промежуточное ПО Downloaderprocess_response()
Вместо этого методы вызываются последовательно.При возврате в качестве объекта запроса промежуточное ПО загрузчика с более низким приоритетом
process_exception()
Он больше не будет вызываться, а объект запроса будет возвращен в очередь планирования для планирования, что эквивалентно совершенно новому запросу. Тогда запрос будетprocess_request()
методы обрабатываются последовательно.
Приведенное выше содержание представляет собой подробную логику использования этих трех методов. Прежде чем использовать их, у вас должно быть четкое представление об обработке возвращаемых значений этих трех методов. При настройке промежуточного программного обеспечения загрузчика вы также должны обратить внимание на тип возвращаемого значения каждого метода.
Давайте рассмотрим реальный случай, чтобы углубить наше понимание использования Downloader Middleware.
3. Боевой проект
Создайте новый проект с помощью следующей команды:
scrapy startproject scrapydownloadertest
Создайте сцепное проект с именем ScrapyDownLoadRtest. Введите проект, создайте новый паук, команда выглядит следующим образом:
scrapy genspider httpbin httpbin.org
Создается новый Spider с именем httpbin, исходный код которого выглядит следующим образом:
import scrapy
class HttpbinSpider(scrapy.Spider):
name = 'httpbin'
allowed_domains = ['httpbin.org']
start_urls = ['http://httpbin.org/']
def parse(self, response):
pass
Далее мы модифицируемstart_urls
за:[http://httpbin.org/](http://httpbin.org/)
. будет затемparse()
метод добавляет строку вывода журнала, которая будетresponse
Переменнаяtext
Свойства выводятся, чтобы мы могли видеть информацию о запросе, отправленную Scrapy.
Измените содержимое Spider следующим образом:
import scrapy
class HttpbinSpider(scrapy.Spider):
name = 'httpbin'
allowed_domains = ['httpbin.org']
start_urls = ['http://httpbin.org/get']
def parse(self, response):
self.logger.debug(response.text)
Затем запустите паука и выполните следующую команду:
scrapy crawl httpbin
Результат выполнения Scrapy содержит информацию о запросе, отправленную Scrapy, следующим образом:
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip,deflate,br",
"Accept-Language": "en",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "Scrapy/1.4.0 (+http://scrapy.org)"
},
"origin": "60.207.237.85",
"url": "http://httpbin.org/get"
}
Давайте посмотрим на заголовки.User-Agent, используемый запросом, отправленным Scrapy, — это Scrapy/1.4.0 (+http://scrapy.org), который фактически устанавливается встроенным в Scrapy UserAgentMiddleware.Исходный код `UserAgentMiddleware` выглядит следующим образом:
from scrapy import signals
class UserAgentMiddleware(object):
def __init__(self, user_agent='Scrapy'):
self.user_agent = user_agent
@classmethod
def from_crawler(cls, crawler):
o = cls(crawler.settings['USER_AGENT'])
crawler.signals.connect(o.spider_opened, signal=signals.spider_opened)
return o
def spider_opened(self, spider):
self.user_agent = getattr(spider, 'user_agent', self.user_agent)
def process_request(self, request, spider):
if self.user_agent:
request.headers.setdefault(b'User-Agent', self.user_agent)
существуетfrom_crawler()
Метод, сначала попробуйте получитьsettings
вUSER_AGENT
, затем поставьтеUSER_AGENT
Перейти к__init__()
Метод инициализирован, и его параметрыuser_agent
. если не прошелUSER_AGENT
По умолчанию для параметра задана строка Scrapy. В нашем новом проекте нет настроекUSER_AGENT
, так вотuser_agent
Переменные Scrapy. Далее, вprocess_request()
метод,user-agent
переменная установлена вheaders
Свойство переменной, которое успешно устанавливает User-Agent. Таким образом, User-Agent проходит через промежуточное ПО Downloader.process_request()
набор методов.
Есть два способа изменить User-Agent запроса: один — изменитьsettings
внутриUSER_AGENT
Переменная; второй через Downloader Middlewareprocess_request()
метод модификации.
Первый способ очень простой, нам нужно только добавить строчку в settings.pyUSER_AGENT
можно определить как:
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36'
Обычно рекомендуется использовать этот метод для установки. Но если вы хотите установить более гибкие настройки, такие как установка случайногоUser-Agent
, то вам нужно использовать Downloader Middleware. Итак, далее мы используем Downloader Middleware для реализации случайной настройки User-Agent.
Добавьте внутренний файл middlewares.py.RandomUserAgentMiddleware
класс следующим образом:
import random
class RandomUserAgentMiddleware():
def __init__(self):
self.user_agents = [
'Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)',
'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.2 (KHTML, like Gecko) Chrome/22.0.1216.0 Safari/537.2',
'Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:15.0) Gecko/20100101 Firefox/15.0.1'
]
def process_request(self, request, spider):
request.headers['User-Agent'] = random.choice(self.user_agents)
Мы начинаем с класса__init__()
В методе определены три разных пользовательских агента, представленных в виде списка. Далее реализованоprocess_request()
метод, который принимает один параметрrequest
, мы напрямую модифицируемrequest
можно использовать свойства. Здесь мы прямо задаемrequest
Переменнаяheaders
User-Agent атрибута, содержимое настройки — это случайно выбранный User-Agent, такой Downloader Middleware пишется.
Однако, чтобы сделать его эффективным, нам нужно снова вызвать Downloader Middleware. В settings.py поместитеDOWNLOADER_MIDDLEWARES
Раскомментируйте и установите следующее:
DOWNLOADER_MIDDLEWARES = {
'scrapydownloadertest.middlewares.RandomUserAgentMiddleware': 543,
}
Затем мы повторно запускаем Spider и видим, что User-Agent был успешно изменен на случайный User-Agent, определенный в списке:
{
"args": {},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip,deflate,br",
"Accept-Language": "en",
"Connection": "close",
"Host": "httpbin.org",
"User-Agent": "Mozilla/5.0 (Windows; U; MSIE 9.0; Windows NT 9.0; en-US)"
},
"origin": "60.207.237.85",
"url": "http://httpbin.org/get"
}
Путем внедрения Downloader Middleware и использованияprocess_request()
Метод успешно устанавливает случайный User-Agent.
Кроме того, Downloader Middleware также имеетprocess_response()
метод. После того, как загрузчик загрузит запрос, он получит ответ, а затем механизм Scrapy отправит ответ обратно в паук для обработки. Но прежде чем ответ будет отправлен пауку, мы также можем использоватьprocess_response()
Метод обрабатывает ответ. Например, измените код состояния ответа здесь, вRandomUserAgentMiddleware
Добавьте следующий код:
def process_response(self, request, response, spider):
response.status = 201
return response
мы будемresponse
Переменнаяstatus
Атрибут изменяется на 201, а затемresponse
Вернитесь, измененный ответ будет отправлен пауку.
Затем мы выводим измененный код состояния в Spider, вparse()
Добавьте в метод следующий оператор вывода:
self.logger.debug('Status Code: ' + str(response.status))
После повторного запуска консоль выводит следующее:
[httpbin] DEBUG: Status Code: 201
Можно обнаружить, что код состояния Response был успешно изменен.
Поэтому, если вы хотите постобработать ответ, вы можете воспользоваться помощьюprocess_response()
метод.
Еще одинprocess_exception()
метод, который используется для обработки исключений. Мы можем вызвать этот метод, если нам нужна обработка исключений. Однако частота использования этого метода относительно невелика, и здесь не приводится пример.
В-четвертых, код этого раздела
Исходный код этого раздела: https://github.com/Python3WebSpider/ScrapyDownloaderTest.
V. Заключение
В этом разделе объясняется основное использование ПО промежуточного слоя Downloader. Этот компонент очень важен и является ядром обработки исключений и обработки, препятствующей восхождению. Позже мы применим этот компонент в реальном бою для работы с прокси, куками и другим контентом.