https://blog.csdn.net/fenglepeng/article/details/100539847 https://blog.csdn.net/fenglepeng/article/details/100541603 
 
scrapy 框架中各组件的工作流程? 
生成初始的 Requests 来爬取第一个 URLS,并且标识一个回调函数。第一个请求定义在 start_requests() 方法内默认从 start_urls 列表中获得 url 地址来生成 Request 请求,默认的回调函数是 parse 方法。回调函数在下载完成返回response时自动触发
 
在回调函数中,解析 response 并且返回值,返回值可以4种:
包含解析数据的字典 
Item对象 
新的Request对象(新的Requests也需要指定一个回调函数) 
或者是可迭代对象(包含Items或Request) 
 
 
在回调函数中解析页面内容,通常使用 Scrapy 自带的 Selectors,但很明显你也可以使用 Beutifulsoup,lxml 或其他你爱用的。
 
最后,针对返回的 Items 对象将会被持久化到数据库,通过 Item Pipeline 组件存到数据库,或者导出到不同的文件(通过 Feed exports)
 
 
在 scrapy 框架中如何设置代理(两种方法)? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import  osimport  scrapyfrom  scrapy.http import  Request  class  ChoutiSpider (scrapy.Spider) :     name = 'chouti'      allowed_domains = ['chouti.com' ]     start_urls = ['https://dig.chouti.com/' ]       def  start_requests (self) :         os.environ['HTTP_PROXY' ] = "http://192.168.11.11"            for  url in  self.start_urls:             yield  Request(url=url,callback=self.parse)       def  parse (self, response) :         print(response)  import  randomimport  base64import  sixdef  to_bytes (text, encoding=None, errors='strict' ) :     """Return the binary representation of `text`. If `text`     is already a bytes object, return it as-is."""      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)class  MyProxyDownloaderMiddleware (object) :     def  process_request (self, request, spider) :         proxy_list = [             {'ip_port' : '111.11.228.75:80' , 'user_pass' : 'xxx:123' },             {'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(proxy_list)         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' ]))             request.headers['Proxy-Authorization' ] = to_bytes('Basic '  + encoded_user_pass)         else :             request.meta['proxy' ] = to_bytes("http://%s"  % proxy['ip_port' ])     DOWNLOADER_MIDDLEWARES = {             }
 
scrapy 框架中如何实现大文件的下载? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 from twisted.web.client import Agent, getPage, ResponseDone, PotentialDataLoss from twisted.internet import defer, reactor, protocol from twisted.web._newclient import Response from io import BytesIO  class  _ResponseReader (protocol .Protocol ):     def  __init__ (self , finished, txresponse, file_name) :          self ._finished = finished         self ._txresponse = txresponse         self ._bytes_received = 0          self .f = open(file_name, mode='wb' )     def  dataReceived (self , bodyBytes) :          self ._bytes_received += len(bodyBytes)                  self .f.write(bodyBytes)         self .f.flush()     def  connectionLost (self , reason) :          if  self ._finished.called:              return          if  reason.check(ResponseDone):                           self ._finished.callback((self ._txresponse, 'success' ))         elif reason.check(PotentialDataLoss):                           self ._finished.callback((self ._txresponse, 'partial' ))         else:                           self ._finished.errback(reason)         self .f.close()
 
scrapy 中如何实现限速? http://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/autothrottle.html 
scrapy 中如何实现暂停爬虫? https://scrapy-chs.readthedocs.io/zh_CN/1.0/topics/jobs.html?highlight=item 
有些情况下,例如爬取大的站点,我们希望能暂停爬取,之后再恢复运行。Scrapy通过如下工具支持这个功能:
一个把调度请求保存在磁盘的调度器 
一个把访问请求保存在磁盘的副本过滤器[duplicates filter] 
一个能持续保持爬虫状态(键/值对)的扩展 
 
Job 路径
要启用持久化支持,你只需要通过 JOBDIR 设置 job directory 选项。 这个路径将会存储所有的请求数据来保持一个单独任务的状态(例如:一次spider爬取(a spider run))。 必须要注意的是,这个目录不允许被不同的spider 共享,甚至是同一个 spider 的不同 jobs/runs 也不行。 也就是说,这个目录就是存储一个单独 job 的状态信息。
scrapy 中如何进行自定制命令 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  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 ) :              return  'Runs all of the spiders'          def  run (self , args, opts) :              spider_list = self .crawler_process.spiders.list()             for  name in  spider_list:                  self .crawler_process.crawl(name, **opts.__dict__ )             self .crawler_process.start()
 
scrapy 中如何实现的记录爬虫的深度? DepthMiddleware 是一个用于追踪每个Request在被爬取的网站的深度的中间件。其可以用来限制爬取深度的最大深度或类似的事情。 DepthMiddleware 可以通过下列设置进行配置(更多内容请参考设置文档):
‘DEPTH_LIMIT’:爬取所允许的最大深度,如果为0,则没有限制。 
‘DEPTH_STATS’:是否收集爬取状态。 
‘DEPTH_PRIORITY’:是否根据其深度对requet安排优先 
 
scrapy 中的 pipelines 工作原理? Scrapy 提供了 pipeline 模块来执行保存数据的操作。 在创建的 Scrapy 项目中自动创建了一个 pipeline.py 文件,同时创建了一个默认的 Pipeline 类。 我们可以根据需要自定义 Pipeline 类,然后在 settings.py 文件中进行配置即可
scrapy 的 pipelines 如何丢弃一个 item 对象? 通过 raise DropItem() 方法
简述 scrapy 中爬虫中间件和下载中间件的作用? 
https://blog.csdn.net/fenglepeng/article/details/100541603 
 
scrapy-redis 组件的作用? 实现了分布式爬虫,url去重、调度器、数据持久化
‘scheduler’调度器 
‘dupefilter’URL去重规则(被调度器使用) 
‘pipeline’数据持久化 
 
scrapy-redis 组件中如何实现的任务的去重? 
内部进行配置,连接 Redis  
 
去重规则通过 Redis 的集合完成,集合的 Key 为:key = defaults.DUPEFILTER_KEY % {'timestamp': int(time.time())} 默认配置:DUPEFILTER_KEY = 'dupefilter:%(timestamp)s'
 
去重规则中将url转换成唯一标示,然后在 Redis 中检查是否已经在集合中存在
1 2 3 4 5 from scrapy.utils import request from scrapy.http import Request req = Request(url ='http :/ / www .cnblogs .com / wupeiqi .html ')  result = request.request_fingerprint(req )  print(result)  # 8 ea4fd67887449313ccc12e5b6b92510cc53675c
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 class  RFPDupeFilter (BaseDupeFilter) :     """Request Fingerprint duplicates filter"""        def  __init__ (self, path=None, debug=False) :         self.fingerprints = set()    @classmethod      def  from_settings (cls, settings) :         debug = settings.getbool('DUPEFILTER_DEBUG' )         return  cls(job_dir(settings), debug)       def  request_seen (self, request) :                  fp = self.request_fingerprint(request)                  if  fp in  self.fingerprints:             return  True                   self.fingerprints.add(fp)       def  request_fingerprint (self, request) :         return  request_fingerprint(request)  class  RFPDupeFilter (BaseDupeFilter) :     """Redis-based request duplicates filter.       This class can also be used with default Scrapy's scheduler.       """        logger = logger       def  __init__ (self, server, key, debug=False) :                           self.server = server                  self.key = key               @classmethod      def  from_settings (cls, settings) :                           server = get_redis_from_settings(settings)                    key = defaults.DUPEFILTER_KEY % {'timestamp' : int(time.time())}         debug = settings.getbool('DUPEFILTER_DEBUG' )         return  cls(server, key=key, debug=debug)      @classmethod      def  from_crawler (cls, crawler) :                  return  cls.from_settings(crawler.settings)       def  request_seen (self, request) :                  fp = self.request_fingerprint(request)                                    added = self.server.sadd(self.key, fp)         return  added == 0        def  request_fingerprint (self, request) :                  return  request_fingerprint(request)       def  close (self, reason='' ) :                  self.clear()       def  clear (self) :         """Clears fingerprints data."""          self.server.delete(self.key)
 
scrapy-redis 的调度器如何实现任务的深度优先和广度优先?