爬虫之scrapy高级部分等相关内容-138

1 配置参数

#1  是否遵循爬虫协议
ROBOTSTXT_OBEY = False
#2 浏览器类型(默认写的是scrapy,)
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36'
#3 日志级别(默认是info,执行爬虫,info会被打印出来)
# 设置成ERROR,只打印错误信息(提高爬虫效率)
LOG_LEVEL='ERROR'

 

2 scrapy持久化

1 scrapy crawl cnblogs -o cnblogs.json  (这个不需要记)
1 在items中写类,类中写字段
     class CnblogsSpiderItem(scrapy.Item):
         title = scrapy.Field()
         desc=scrapy.Field()
         url=scrapy.Field()
         author=scrapy.Field()
         # 重点(文章详情,如果跟之前爬过的文章对应)
         content=scrapy.Field()
 2 在爬虫中把要保存的字段放到item对象中
     article_item['url']=url
     article_item['title']=title
     article_item['desc']=desc
     article_item['author']=author
     yield article_item
     
 3 在控制台输入:scrapy crawl cnblogs -o cnblogs.json


2 常用方式,只记住这一种
1 在items中写类,类中写字段
     class CnblogsSpiderItem(scrapy.Item):
         title = scrapy.Field()
         desc=scrapy.Field()
         url=scrapy.Field()
         author=scrapy.Field()
         # 重点(文章详情,如果跟之前爬过的文章对应)
         content=scrapy.Field()
 2 在爬虫中把要保存的字段放到item对象中
     article_item['url']=url
     article_item['title']=title
     article_item['desc']=desc
     article_item['author']=author
     yield article_item
 3 在setting中配置
     ITEM_PIPELINES = {
      'cnblogs_spider.pipelines.CnblogsSpiderFilePipeline': 300,  # 数字表示优先级,数字越小,优先级越大
      'cnblogs_spider.pipelines.CnblogsSpiderMysqlPipeline': 400,  # 数字表示优先级,数字越小,优先级越大
  }
 4 在pipline中写
   class CnblogsSpiderFilePipeline:
     # 爬虫启动他会执行
     def open_spider(self,spider):
         # spider是爬虫对象
         print(spider.name)
         print('爬虫开始了')
         self.f=open('cnblogs.txt','w',encoding='utf-8')
     def close_spider(self,spider):
         # 爬虫停止会执行
         print('爬虫停止了')
         self.f.close()
     def process_item(self, item, spider):
         self.f.write(item['title']+item['desc']+item['author']+item['url'])
         self.f.write('/n')
         return item


 import pymysql
 class CnblogsSpiderMysqlPipeline:

     def open_spider(self,spider):
         self.conn=pymysql.connect( host='127.0.0.1', user='root', password="123",database='cnblogs', port=3306)
         self.cursor=self.conn.cursor()
     def close_spider(self,spider):
         self.conn.commit()
         self.cursor.close()
         self.conn.close()
     def process_item(self, item, spider):
         sql='insert into aritcle (title,`desc`,url,author) values (%s,%s,%s,%s )'
         self.cursor.execute(sql,args=[item['title'],item['desc'],item['url'],item['author']])
         return item

3 请求传递参数

1 给另一个请求传递参数,在响应中拿到(借助meta)
yield Request(url=url,callback=self.parser_detail,meta={'item':article_item})
2 在解析方法中通过response对象获取
item=response.meta.get('item')

4 提高爬虫效率

1 提高scrapy的爬取效率(异步框架,基于twisted,性能很高了,可以优化的点),面试聊

- 在配置文件中进行相关的配置即可:(默认还有一套setting,类比django)
#1 增加并发:
默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。
CONCURRENT_REQUESTS = 100

#2 降低日志级别:
在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:LOG_LEVEL = ‘INFO’
# 3 禁止cookie:(cnblogs不需要cookie)
如果不是真的需要cookie,则在scrapy爬取数据时可以禁止cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:COOKIES_ENABLED = False
# 4禁止重试:
对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:
RETRY_ENABLED = False
# 5 减少下载超时:
如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:
DOWNLOAD_TIMEOUT = 10 超时时间为10s

 

 

5 scrapy中间件

5.1 下载中间件 CnblogsSpiderDownloaderMiddleware

process_request

1 请求来的时候
 # Must either:
 # - return None: continue processing this request     返回None,进入下一个下载中间件的process_request
 # - or return a Response object                       返回response对象,会给引擎,引擎给爬虫,进入解析
 # - or return a Request object                       返回请求对象,会给引擎,引擎给调度器,放到调度器
 # - or raise IgnoreRequest: process_exception() methods of 抛异常,就会触发process_exception的执行
 
 # 总结:
 返回None,继续爬取
 返回Resoponse对象,会给引擎,给爬虫,去解析
 返回Request对象,会给引擎,给调度器,等待下一次被调度
 
 # 什么情况会用它:
 加代理,加cookie,加浏览器类型
集成 selenium
 
 
 
 
 # 修改cookie
 request.cookies={'name':'lqz'}
 # 使用代理
 proxy='http://154.16.63.16:8080'  # 从代理池中获取
 request.meta["proxy"] =proxy
 # 修改请求头
 request.headers.setlist(b'User-Agent','asdfadsfadsf')

process_response

# Must either;
# - return a Response object       正常逻辑,给 引擎,引擎个爬虫去解析
# - return a Request object         返回Request对象,给引擎,引擎给调度器,等待下一次被调度
# - or raise IgnoreRequest         抛异常IgnoreRequest,响应不要了,不会给引擎,再给爬虫解析

# 总结
返回Response,正常逻辑走
返回Request,放到调度器


# 什么情况会用到
抛异常,不再解析该响应(用的也不多)

5.2 爬虫中间件

了解

6 集成selenium

 

1 在爬虫中写
 class ChoutiSpider(scrapy.Spider):
     name = 'chouti'
     allowed_domains = ['www.bilibili.com']
     start_urls = ['https://www.bilibili.com/v/dance/otaku/#/all/default/0/1/']
     bro=webdriver.Chrome(executable_path='./chromedriver')
     bro.implicitly_wait(10)
     @staticmethod
     def close(spider, reason):
         spider.bro.close()
         
         
2 在中间件中直接使用
 class CnblogsSpiderDownloaderMiddleware:
     def process_request(self, request, spider):
         spider.bro.get(request.url)
         response=HtmlResponse(url=request.url,body=bytes(spider.bro.page_source,encoding='utf-8'))
         return response
       
       
3 隐藏浏览器?无头浏览器

7 去重规则

1 默认会去重,使用了
from scrapy.dupefilters import RFPDupeFilter
2 在默认的setting中配的
3 本身原理是使用的是集合去重

4 更高级部分
# 是不是同一个地址
127.0.0.1/?name=lqz&age=19
127.0.0.1/?age=19&name=lqz
# 本质原理,把?后的打散了,再排序
fp = self.request_fingerprint(request) # 得到一个指纹,上面那两个地址结果一样




## 自定义去重规则
如果你自己写去重类,如何使用?
写一个类,继承 BaseDupeFilter,重写def request_seen(self, request):
返回true表示爬过了
返回false表示没有爬过


# 你有个更牛逼的去重方案
-集合去重可以,存在问题,如果地址特别多,上亿个地址,集合会特别大,会非常占用内存
 -极小内存,完成去重(布隆过滤器)

 

原文地址:https://www.cnblogs.com/usherwang/p/14470901.html