Python 爬虫 Scrapy框架2

22 篇文章 0 订阅
7 篇文章 0 订阅

四.配置文件(settings.py)

参见:https://www.cnblogs.com/fengf233/p/11400262.html
https://www.cnblogs.com/longyunfeigu/p/9494408.html

################################基本配置#################################

#爬虫的名字:会被放在USER_AGENT(当前客户端)中提交出去,网站可以据此筛选
BOT_NAME = 'scrapy1'

#查找爬虫文件的路径:
SPIDER_MODULES = ['scrapy1.spiders']#默认值

#创建爬虫文件时的路径:
NEWSPIDER_MODULE = 'scrapy1.spiders'#默认值

#当前客户端(即请求头中的USER-AGENT字段):
USER_AGENT = 'scrapy1 (+http://www.yourdomain.com)'#默认值
#实际使用时,会伪装成浏览器发出的请求

#是否遵守爬虫协议:
ROBOTSTXT_OBEY = True#默认值
#为True时,只在网站允许时爬虫;为False,则忽略网站的规则

#是否自动爬取Cookie:
COOKIES_ENABLED = True#默认值
#为True时才能使用CookieJar进行解析

#是否对Cookie使用调试模式(即日志中是否包含Cookie):
COOKIES_DEBUG = False#默认值

#默认的请求头:
DEFAULT_REQUEST_HEADERS = {#默认值
   'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
   'Accept-Language': 'en',
}

##############################查看/操作爬虫##############################

#是否允许查看爬虫当前的状态:
TELNETCONSOLE_ENABLED = False
#在终端中使用telnet <IP> <port>进入,然后使用命令查看
#使用扩展scrapy.extensions.telnet.TelnetConsole查看

TELNETCONSOLE_HOST = '127.0.0.1'
TELNETCONSOLE_PORT = [6023,]

###############################并发与延迟################################

#最大并发请求数(0为无限制):
CONCURRENT_REQUESTS = 16#默认值

#下载延迟(即对1个域名的2次请求间的间隔;单位为s):
DOWNLOAD_DELAY = 3
#因为有些网站在访问过于频繁时会禁止访问

#针对单个域名/IP的最大并发数(0为无限制):
CONCURRENT_REQUESTS_PER_DOMAIN = 8#默认值
CONCURRENT_REQUESTS_PER_IP = 0#默认值

##################################插件##################################

#注册爬虫中间件:
SPIDER_MIDDLEWARES = {#默认值
    'scrapy1.middlewares.Scrapy1SpiderMiddleware': 543,
}

#注册下载器中间件:
DOWNLOADER_MIDDLEWARES = {
    'scrapy1.middlewares.Scrapy1DownloaderMiddleware': 543,
}

#注册扩展:
EXTENSIONS = {#默认值
    'scrapy.extensions.telnet.TelnetConsole': None,
    #这是用于查看爬虫当前状态的扩展
}

#注册管道:
ITEM_PIPELINES = {
    'scrapy1.pipelines.Scrapy1Pipeline': 300,
    'scrapy.pipelines.Scrapy1Pipeline2':200,
}

###############关于AutoThrottle extension(用于实现智能限速)################

#是否启用"
AUTOTHROTTLE_ENABLED = True

#首次请求的下载延迟:
AUTOTHROTTLE_START_DELAY = 5

#最大下载延迟:
AUTOTHROTTLE_MAX_DELAY = 10#会使用DOWNLOAD_DELAY作为最小下载延迟

#每秒并发请求数的平均值(只是目标值,并非必须达到):
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0

#是否对其使用调试模式:
AUTOTHROTTLE_DEBUG = False

#算法:
from scrapy.contrib.throttle import AutoThrottle#这是默认的算法
①设置最小延迟(DOWNLOAD_DELAY)
②设置最大延迟(AUTOTHROTTLE_MAX_DELAY)
③设置初始下载延迟(AUTOTHROTTLE_START_DELAY)
④获取上次请求的"连接时间"(latency)
 #即从请求连接到收到响应头所用的时间
 #每次请求的下载延迟都是利用上次请求的连接时间计算得到的
⑤进行计算的... AUTOTHROTTLE_TARGET_CONCURRENCY
 target_delay = latency / self.target_concurrency
 #self.target_concurrency就是AUTOTHROTTLE_TARGET_CONCURRENCY
 new_delay = (slot.delay + target_delay) / 2.0
 #注:这里slot.delay表示上次的延迟时间
 new_delay = max(target_delay, new_delay)
 new_delay = min(max(self.mindelay, new_delay), self.maxdelay)
 #self.mindelay就是DOWNLOAD_DELAY;self.maxdelay就是AUTOTHROTTLE_MAX_DELAY
 slot.delay = new_delay
 #将(当前)请求的延迟设为new_delay

##################################缓存##################################

#是否启用缓存策略:
HTTPCACHE_ENABLED = True

#缓存策略:
①所有请求均缓存,下次再请求直接访问缓存即可:
HTTPCACHE_POLICY = "scrapy.extensions.httpcache.DummyPolicy"
②根据Http响应头中的Cache-Control/Last-Modified等字段进行缓存:
HTTPCACHE_POLICY = "scrapy.extensions.httpcache.RFC2616Policy"

#缓存超时时间(单位为s):
HTTPCACHE_EXPIRATION_SECS = 0

#缓存路径:
HTTPCACHE_DIR = 'httpcache'
#即缓存会被保存到该路径处

#不进行缓存的Http状态码:
HTTPCACHE_IGNORE_HTTP_CODES = []
#即如果请求的状态属于该列表,就不进行缓存

#用于进行缓存的插件:
HTTPCACHE_STORAGE = 'scrapy.extensions.httpcache.FilesystemCacheStorage'

##################################深度##################################

#指定爬取的深度:
DEPTH_LIMIT=4
#如指定为1,则访问初始URL页面中的URL(记为URL1),但不访问URL1页面中的URL
#0表示无深度

#广度优先还是深度优先:
DEPTH_PRIORITY=0#默认值
#只能为0(深度优先)或1(广度优先)

SCHEDULER_DISK_QUEUE = 'scrapy.squeue.PickleFifoDiskQueue'
SCHEDULER_MEMORY_QUEUE = 'scrapy.squeue.FifoMemoryQueue'

#调度器队列:
SCHEDULER = 'scrapy.core.scheduler.Scheduler'#默认值

#指定用于对URL去重的类:
DUPEFILTER_CLASS='scrapy.dupefilter.RFPDupeFilter'#默认值

##################################代理##################################

#实现代理的类:
from scrapy.contrib.downloadermiddleware.httpproxy import HttpProxyMiddleware

#代理的实质:
在request.meta中设置proxy属性;如果代理需要用户名和密码,再在request.headers中设
置Proxy-Authorization属性

①方式1(默认):默认方法需要将代理加到Python的当前环境变量(os.environ)#如果需要用户名和密码:
os.environ["http_proxy"]="http://root:woshiniba@192.168.11.11:9999/"
#如果不需要用户名和密码:
https_proxy:http://192.168.11.11:9999/
  #key必须以_proxy结尾
  #value的格式为http://[<username>:<pwd>@]<IP>:<port>/
    #[...]中的部分在不需要用户名和密码时不需要加
  #注意:value结尾的'/'不能没有

②方式2:使用自定义下载中间件
#middlewares.py中:
def to_bytes(text, encoding=None, errors='strict'):#转换成字节
    if isinstance(text, bytes):
        return text
    if not isinstance(text, six.string_types):
        raise TypeError('to_bytes must receive a unicode, str or bytes object, got %s' % type(text).__name__)
        if encoding is None:
            encoding = 'utf-8'
        return text.encode(encoding, errors)
#middlewares.py中:
class ProxyMiddleware(object):
    def process_request(self, request, spider):
        PROXIES = [
            {'ip_port': '111.11.228.75:80', 'user_pass': ''},
            {'ip_port': '120.198.243.22:80', 'user_pass': ''},
            {'ip_port': '111.8.60.9:8123', 'user_pass': ''},
            {'ip_port': '101.71.27.120:80', 'user_pass': ''},
            {'ip_port': '122.96.59.104:80', 'user_pass': ''},
            {'ip_port': '122.224.249.122:8088', 'user_pass': ''},
        ]
        proxy = random.choice(PROXIES)
        if proxy['user_pass'] is not None:#代理有用户名和密码
            request.meta['proxy'] = to_bytes("http://%s" % proxy['ip_port'])
            encoded_user_pass = base64.encodestring(to_bytes(proxy['user_pass']))
            #必须使用base64算法进行加密;
            request.headers['Proxy-Authorization'] = to_bytes('Basic ' + encoded_user_pass)
            #Proxy-Authorization属性的值必须以"Basic"开头
        else:#代理没有用户名和密码
            request.meta['proxy'] = to_bytes("http://%s" % proxy['ip_port'])
#settings.py中:
DOWNLOADER_MIDDLEWARES = {
    'scrapy1.middlewares.ProxyMiddleware': 500,
}

##################################证书##################################

1.爬取网站使用的可信任证书(即第3方提供的证书;默认支持):
#以下是settings.py中的默认配置,但没有明示写出(不可见)
DOWNLOADER_HTTPCLIENTFACTORY="scrapy.core.downloader.webclient.ScrapyHTTPClientFactory"
DOWNLOADER_CLIENTCONTEXTFACTORY="scrapy.core.downloader.contextfactory.ScrapyClientContextFactory"
#在第2个类中读取了系统中已经植入了的可信任证书

2.要爬取网站使用的自定义证书(需要自定制):
DOWNLOADER_HTTPCLIENTFACTORY="scrapy.core.downloader.webclient.ScrapyHTTPClientFactory"
DOWNLOADER_CLIENTCONTEXTFACTORY="scrapy1.https.MySSLFactory"
#/scrapy1/https.py中:
from scrapy.core.downloader.contextfactory import ScrapyClientContextFactory
from twisted.internet.ssl import (optionsForClientTLS,CertificateOptions,PrivateCertificate)

class MySSLFactory(ScrapyClientContextFactory):#继承默认使用的类
    def getCertificateOptions(self):#重写读取证书的方法
        from OpenSSL import crypto
        v1=crypto.load_privatekey(crypto.FILETYPE_PEM,open('/Users/1234/client.key.unsecure',mode='r').read())
        v2=crypto.load_certificate(crypto.FILETYPE_PEM,open('/Users/1234/client.pem',mode='r').read())
        return CertificateOptions(
            privateKey=v1,#PKey对象,即私钥
            certificate=v2,#X509对象,即证书
            verify=False,
            method=getattr(self,'method',getattr(self,'_ssl_method',None))
        )

五.中间件

参见:https://www.cnblogs.com/xieqiankun/p/know_middleware_of_scrapy_1.html

使用中间件可在请求发起前或返回后对数据进行定制化修改,从而开发出适应不同情况的爬虫
中间件是开发者主动添加的组件,可在中途劫持数据,做一些修改后再把数据传递出去
Scrapy有2类中间件:下载中间件和爬虫中间件;每类都可包含多个中间件,每个中间件都是1个类
所有类中同名的方法都会被放入1个列表,在事件触发时依次执行该列表中的所有方法(见下图)

在这里插入图片描述
1.下载中间件(Downloader Middleware)

#说明:
①下载器中间件是用于处理引擎和下载器之间的request/response对象的钩子框架,大致位于调
度器和爬虫之间
②主要用于更换代理IP/更换Cookies/更换User-Agent/自动重试
③如果进行到某个中间件时就完成了下载,则之后的中间件不再继续执行

(1)内置的下载中间件:

#默认下载中间件(settings.py中,但没有明示写出):
DOWNLOADER_MIDDLEWARES={
    'scrapy.contrib.downloadermiddleware.robotstxt.RobotsTxtMiddleware':100,
    'scrapy.contrib.downloadermiddleware.httpauth.HttpAuthMiddleware':300,
    'scrapy.contrib.downloadermiddleware.downloadtimeout.DownloadTimeoutMiddleware':350,
    'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware':400,
    'scrapy.contrib.downloadermiddleware.retry.RetryMiddleware':500,
    'scrapy.contrib.downloadermiddleware.defaultheaders.DefaultHeadersMiddleware':550,
    'scrapy.contrib.downloadermiddleware.redirect.MetaRefreshMiddleware':580,
    'scrapy.contrib.downloadermiddleware.httpcompression.HttpCompressionMiddleware':590,
    'scrapy.contrib.downloadermiddleware.redirect.RedirectMiddleware':600,
    'scrapy.contrib.downloadermiddleware.cookies.CookiesMiddleware':700,
    'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware':750,
    'scrapy.contrib.downloadermiddleware.chunked.ChunkedTransferMiddleware':830,
    'scrapy.contrib.downloadermiddleware.stats.DownloaderStats':850,
    'scrapy.contrib.downloadermiddleware.httpcache.HttpCacheMiddleware':900,
}

作为value的int值表示权重,越小越先执行其process_request()方法,而process_response()
的执行顺序与此相反

(2)自定义下载中间件:

#middlewares.py中:
class DownMiddleware1(object):
    #注意:中间件中的方法只能属于这3个
    def process_request(self,request,spider):
        '''
        请求需要被下载时,经过所有下载器中间件的process_request()调用
        :param request:Request对象
        :param spider:爬虫对象
        :return:
	        None:交给下1个下载中间件的process_request()
	        Response对象:停止process_request()的执行,开始执行process_response()
	        Request对象:停止中间件的执行,将Request放回调度器
	        raise IgnoreRequest异常:调用process_exception()
        '''
        pass

    def process_response(self,request,response,spider):
        '''
        下载完成,返回时调用
        :param request:Request对象
        :param response:Response对象
        :param spider:爬虫对象
        :return:
            Response对象:交给下1个下载中间件的process_response()
            Request对象:停止中间件的执行,request将被重新调度下载
            raise IgnoreRequest异常:调用Request.errback()
        '''
        print('response1')
        return response

    def process_exception(self,request,exception,spider):
        '''
        当下载处理器(download handler)或process_request()抛出异常时执行
        :param response:Response对象
        :param exception:错误对象
        :param spider:爬虫对象
        :return:
            None:交给下1个下载中间件的process_exception()
              如果所有process_exception()都返回None,则报错
            Response对象:停止后续process_exception方法
            Request对象:停止中间件,request将会被重新调度下载
        '''
        return None

如果自定义的下载中间件都未下载,则由内置下载中间件下载

(3)执行顺序:
在这里插入图片描述
2.爬虫中间件(Spider Middleware)

①下载器中间件是用于处理引擎和爬虫之间的request/response对象的钩子框架,大致位于下载
器和管道之间

(1)内置的爬虫中间件:

#默认爬虫中间件(settings.py中,但没有明示写出):
SPIDER_MIDDLEWARES={
    'scrapy.contrib.spidermiddleware.httperror.HttpErrorMiddleware':50,
    'scrapy.contrib.spidermiddleware.offsite.OffsiteMiddleware':500,
    'scrapy.contrib.spidermiddleware.referer.RefererMiddleware':700,
    'scrapy.contrib.spidermiddleware.urllength.UrlLengthMiddleware':800,
    'scrapy.contrib.spidermiddleware.depth.DepthMiddleware':900,
}

作为value的int值表示权重,越小越先执行

(2)自定义爬虫中间件:

#middlewares.py中:
class SpiderMiddleware(object):
    def process_spider_input(self,response,spider):
        '''
        下载完成时执行,然后交给parse()处理
        :param response:下载器移交的Response对象
        :param spider:爬虫对象
        :return:
        '''
        pass

    def process_spider_output(self,response,result,spider):
        '''
        spider处理完成,返回时调用,之后再交给调度器或管道
        :param response:Response对象
        :param result:parse()返回的Request或Item对象
        :param spider:爬虫对象
        :return:必须返回包含Request或Item对象的可迭代对象
        '''
        return result

    def process_spider_exception(self,response, exception, spider):
        '''
        异常调用
        :param response:
        :param exception:
        :param spider:
        :return:
            None:继续交给后续中间件处理异常
            含Response或Item对象的可迭代对象:交给调度器或管道
        '''
        return None

    def process_start_requests(self,start_requests,spider):
        '''
        爬虫启动时调用,在之后迭代深度时不执行
        :param start_requests:初始URL的Request对象构成的可迭代对象
        :param spider:爬虫对象
        :return:包含Request对象的可迭代对象
        '''
        return start_requests

(3)执行顺序:
在这里插入图片描述
六.自定义Scrapy命令

在spiders同级创建任意目录,如commands
在其中创建任意文件,如crawlall.py(此处文件名就是自定义的命令)
#/scrapy1/scrapy1/commands/crawlall.py中:
from scrapy.commands import ScrapyCommand
from scrapy.utils.project import get_project_settings

class Command(ScrapyCommand):
    requires_project=True

    def syntax(self):
        return '[options]'

    def short_desc(self):#使用scrapy --help时关于该命令的提示
        return 'Runs all of the spiders'

    def run(self,args,opts):#opts是传入命令的参数
        #找到所有爬虫的名称:
        spider_list=self.crawler_process.spiders.list()

        #开始爬取(内置的crawl命令也是通过类似的方法执行的):
        for name in spider_list:
            self.crawler_process.crawl(name,**opts.__dict__)
        self.crawler_process.start()
#settings.py中:
COMMANDS_MODULE='scrapy1.commands'
scrapy crawlall#执行所有爬虫
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值