Здесмь я якобы систематизирую мои представления о Scrapy middleware. Читать документацию - дело утомительное. Мне удалось найти короткие статьи на русском, в которых дается три рецепта: 1) http_proxy, 2) Spider settings 3) download middlewatr
- Scrapy. Frequently Asked Questions. Does Scrapy work with HTTP proxies?.
- Scrapy. Downloader Middleware. HttpProxyMiddleware..
- Исходный код класса HttpProxyMiddleware.
- Исходный код модульных тестов класса HttpProxyMiddleware.
- Wget. Proxies.
- scrapy-users. How to set a proxy in code?
- Исходный код класса RandomProxy от Aivars Kalvāns.
from IPython.display import Image,HTML
Image ('http://doc.scrapy.org/en/latest/_images/scrapy_architecture.png')
Далее заметки, сделаные в процессе изучения материала¶
!scrapy settings --getlist DOWNLOADER_MIDDLEWARES
!scrapy settings --getlist DOWNLOADER_MIDDLEWARES_BASE
# Сравним со старой копией из июньского поста (она нагляднее)
# "Пример замены scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware"
[('scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware', 400),
('scrapy.contrib.downloadermiddleware.cookies.CookiesMiddleware', 700),
('scrapy.contrib.downloadermiddleware.downloadtimeout.DownloadTimeoutMiddleware', 350),
('scrapy.contrib.downloadermiddleware.redirect.RedirectMiddleware', 600),
('scrapy.contrib.downloadermiddleware.retry.RetryMiddleware', 500),
('scrapy.contrib.downloadermiddleware.httpauth.HttpAuthMiddleware', 300),
('scrapy.contrib.downloadermiddleware.robotstxt.RobotsTxtMiddleware', 100),
('scrapy.contrib.downloadermiddleware.httpcache.HttpCacheMiddleware', 900),
('scrapy.contrib.downloadermiddleware.chunked.ChunkedTransferMiddleware', 830),
('scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware', 750),
('scrapy.contrib.downloadermiddleware.stats.DownloaderStats', 850),
('scrapy.contrib.downloadermiddleware.httpcompression.HttpCompressionMiddleware', 590),
('scrapy.contrib.downloadermiddleware.redirect.MetaRefreshMiddleware', 580),
('scrapy.contrib.downloadermiddleware.defaultheaders.DefaultHeadersMiddleware', 550)]
DOWNLOADER_MIDDLEWARES_BASE менять нельзя !!!
Таким образом, если мы хотим поменять дефолтные настройки, то нужно присвоить "None" заменяемой дефолтной строчке
DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.CustomDownloaderMiddleware': 543,
'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': None,
}
Любопытно, а что там в дефолтных настройках UserAgentMiddleware¶
%load "C:\\Users\\kiss\\Anaconda\\Lib\\site-packages\\scrapy\\contrib\\downloadermiddleware\\useragent.py"
"""Set User-Agent header per spider or use a default value from settings"""
from scrapy import signals
class UserAgentMiddleware(object):
"""This middleware allows spiders to override the user_agent"""
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('User-Agent', self.user_agent)
Я смутно представляю себе classmethod(function), зачем они нужны? Аналог статических методов? Это еще предстоит осмыслить... Поэтому здсь эта ссылка на документацию.
Return a class method for function.
A class method receives the class as implicit first argument, just like an instance method receives the instance. To declare a class method, use this idiom @classmethod ... cls ...
The @classmethod form is a function decorator – see the description of function definitions in Function definitions for details
Я также не знаю, зачем некоторым классам наследовать class UserAgentMiddleware(object) object
object - Python class
Return a new featureless object. object is a base for all new style classes. It has the methods that are common to all instances of new style classes.
Еще один дефолтный файл downloadermiddleware\httpproxy.py¶
%load "C:\\Users\\kiss\\Anaconda\\Lib\\site-packages\\scrapy\\contrib\\downloadermiddleware\\httpproxy.py"
import base64
from urllib import getproxies, unquote, proxy_bypass
from urllib2 import _parse_proxy
from urlparse import urlunparse
from scrapy.utils.httpobj import urlparse_cached
from scrapy.exceptions import NotConfigured
class HttpProxyMiddleware(object):
def __init__(self):
self.proxies = {}
for type, url in getproxies().items():
self.proxies[type] = self._get_proxy(url, type)
if not self.proxies:
raise NotConfigured
def _get_proxy(self, url, orig_type):
proxy_type, user, password, hostport = _parse_proxy(url)
proxy_url = urlunparse((proxy_type or orig_type, hostport, '', '', '', ''))
if user and password:
user_pass = '%s:%s' % (unquote(user), unquote(password))
creds = base64.b64encode(user_pass).strip()
else:
creds = None
return creds, proxy_url
def process_request(self, request, spider):
# ignore if proxy is already seted
if 'proxy' in request.meta:
return
parsed = urlparse_cached(request)
scheme = parsed.scheme
# 'no_proxy' is only supported by http schemes
if scheme in ('http', 'https') and proxy_bypass(parsed.hostname):
return
if scheme in self.proxies:
self._set_proxy(request, scheme)
def _set_proxy(self, request, scheme):
creds, proxy = self.proxies[scheme]
request.meta['proxy'] = proxy
if creds:
request.headers['Proxy-Authorization'] = 'Basic ' + creds
А находимся мы..., точнее, открыли эту страничку Notebook из папке проекта tutorial
# Полный путь к папке в w8
# C:\Users\kiss\Documents\GitHub_2\scrapy-examples-master\scrapy-examples-master\tutorial>
Проект интересен сам по себе, но пока мы сосредоточимся на middleware
!chcp 65001
!tree /f
# В notebook вместо красивых линий буквы,
# поэтому копирую из консоли
C:.
│ Books
│ data_utf8.json
│ ex_tutorial.ipynb
│ Resources
│ scrapy.cfg
│
├───.ipynb_checkpoints
│ ex_tutorial-checkpoint.ipynb
│
└───tutorial
│ data_utf8.json
│ items.py
│ pipelines.py
│ settings.py
│ settings.pyc
│ __init__.py
│ __init__.pyc
│
├───misc
│ agents.py
│ log.py
│ middleware.py
│ proxy.py
│ __init__.py
│
└───spiders
naive_spider.py
__init__.py
В примере вот такой файл для middleware, он понятнее, чем файлы по умолчанию.¶
%load "tutorial/misc/middleware.py"
from scrapy import log
from proxy import PROXIES
from agents import AGENTS
import random
class CustomHttpProxyMiddleware(object):
def process_request(self, request, spider):
# TODO implement complex proxy providing algorithm
if self.use_proxy(request):
p = random.choice(PROXIES)
try:
request.meta['proxy'] = "http://%s" % p['ip_port']
except Exception, e:
log.msg("Exception %s" % e, _level=log.CRITICAL)
def use_proxy(self, request):
"""
using direct download for depth <= 2
using proxy with probability 0.3
"""
if "depth" in request.meta and int(request.meta['depth']) <= 2:
return False
i = random.randint(1, 10)
return i <= 2
class CustomUserAgentMiddleware(object):
def process_request(self, request, spider):
agent = random.choice(AGENTS)
request.headers['User-Agent'] = agent
В примере "tutorial" не выполняются рекомендации об отмене дефолтных настроек.¶
%load "tutorial/settings.py"
# Scrapy settings for tutorial project
#
# For simplicity, this file contains only the most important settings by
# default. All the other settings are documented here:
#
# http://doc.scrapy.org/en/latest/topics/settings.html
#
BOT_NAME = 'tutorial'
SPIDER_MODULES = ['tutorial.spiders']
NEWSPIDER_MODULE = 'tutorial.spiders'
ITEM_PIPELINES = {
#'tutorial.pipelines.JsonWithEncodingPipeline': 300,
}
#Crawl responsibly by identifying yourself (and your website) on the user-agent
#USER_AGENT = 'tutorial (+http://www.yourdomain.com)'
DOWNLOADER_MIDDLEWARES = {
'tutorial.misc.middleware.CustomHttpProxyMiddleware': 400,
'tutorial.misc.middleware.CustomUserAgentMiddleware': 401,
}
LOG_LEVEL = 'INFO'
В "DOWNLOADER_MIDDLEWARES" нет строчек с "None", но полагаю, что пример работает.
Посты чуть ниже также могут вас заинтересовать
Комментариев нет:
Отправить комментарий