scrapy基础

scrapy

Scrapy 是用 Python 实现的一个为了爬取网站数据、提取结构性数据而编写的应用框架。
Scrapy 常应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
Scrapy 是基于twisted框架开发而来,twisted是一个流行的事件驱动的python网络框架。因此Scrapy使用了一种非阻塞(又名异步)的代码来实现并发。

安装

  • Linux:
pip install scrapy
  • Windows:
1. pip install wheel
2. 下载twisted 
   http://www.lfd.uci.edu/-gohlke/pythonlibs/#twisted
3. 安装twisted
   进入到下载目录,pip install Twisted-xxx.whl
4. pip install pywin32
5. pip install scrapy

Scrapy结构,执行流程

  • 架构图

  • 各部分作用

    • Scrapy Engine(引擎): 负责Spider、ItemPipeline、Downloader、Scheduler中间的通讯,信号、数据传递等。
    • Scheduler(调度器): 它负责接受引擎发送过来的Request请求,并按照一定的方式进行整理排列,入队,当引擎需要时,交还给引擎。
    • Downloader(下载器):负责下载Scrapy Engine(引擎)发送的所有Requests请求,并将其获取到的Responses交还给Scrapy Engine(引擎),由引擎交给Spider来处理,
    • Spider(爬虫):它负责处理所有Responses,从中分析提取数据,获取Item字段需要的数据,并将需要跟进的URL提交给引擎,再次进入Scheduler(调度器).
    • Item Pipeline(管道):它负责处理Spider中获取到的Item,并进行进行后期处理(详细分析、过滤、存储等)的地方。
    • Downloader Middlewares(下载中间件):你可以当作是一个可以自定义扩展下载功能的组件。
    • Spider Middlewares(Spider中间件):你可以理解为是一个可以自定扩展和操作引擎和Spider中间通信的功能组件(比如进入Spider的Responses;和从Spider出去的Requests)
  • 执行流程图

起始url被封装成request请求对象,经引擎传给调度器,存放在队列中且会对重复的请求对象进行过滤,之后经引擎传递给下载器去下载数据得到响应对象,响应对象经引擎返回给spider进行解析并封装到item对象中,用yield将item对象经引擎传给管道进行持久化处理,若spider中解析到新的url,重复上述操作。

请求传参

当爬取的数据不在同一页面中时,要进行请求传参,不然持久化的数据结果会出错。

  • 使用meta进行传参,如下:
def parse(self, response):
	...
	yield scrapy.Request(url, callback=self.detail, meta={"item": item})
	
def detail(self, response):
	item = response.meta['item']
	...

如何提高scrapy爬取效率

  1. 增大并发数
    默认情况下scrapy没有开启线程并发,需在settings.py中手动开启。CONCURRENT_REQUESTS=32,但是并不是只能设置不超过32,可以适度增加并发数。
  2. 降低日志等级
    减少日志信息的输出会降低CPU的使用率。
    如:LOG_LEVEL = 'INFO'
    LOG_FILE = 'path' 将日志输出到指定文件中
  3. 禁用cookie
    除非真的需要cookie,否则请关闭以提升爬取效率。
    COOKIES_ENABLED = False
  4. 限制重试
    重新请求爬取失败的url会减慢爬取速度。
    RETRY_ENABLED= False
  5. 缩减下载超时
    放弃请求响应慢的url,可以提高爬取效率。
    DOWNLOAD_TIMEOUT = 10 (单位是秒)

如何设置代理池和UA池

ua_list = [
    
]
ip_list = [
    
]

# 在下载中间件中
import random

def process_request(self, request, spider):
	request.meta['proxy'] = random.choice(ip_list)
	request.headers['User-Agent'] = random.choice(ua_list)
	...

使用管道进行持久化存储的流程

  1. 在items中定义字段
  2. 获取解析后的数据值
  3. 将解析后的数据值存储到item对象中
  4. 通过yield将item对象提交到管道
  5. 管道中持久化存储代码的编写
  6. settings.py中开启管道, 并设置优先级

在scrapy中使用selenium

  1. 在spider的__init__方法中实现浏览器
  2. 在spider的closed方法中关闭浏览器
  3. 在下载中间件的响应中使用spider.browser获取浏览器对象,并得到需要的网页源码,实例化一个新的响应对象,之后将浏览器获取的页面源码加载到该对象中,返回这个新的响应对象。
# spider.py
   def __init__(self):
        self.browser = webdriver.Firefox()

    def closed(self,spider):
        print("spider closed")
        self.browser.close()

# middlewares.py
def process_request(self, request, spider):
        if spider.name == 'xxx':
            try:
                spider.browser.get(request.url)
                spider.browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
            except TimeoutException as e:
                print('超时')
                spider.browser.execute_script('window.stop()')
            time.sleep(2)
            return HtmlResponse(url=spider.browser.current_url, body=spider.browser.page_source,
                                encoding="utf-8", request=request)

其他知识点

  • scrapy为什么要把持久化操作放到管道中, 而不是在爬虫文件中?
    • 放到管道中进行持久化操作的效率会更高
  • spider参数是干嘛用的?
    • 用来传递除了item对象之外的其他属性等
  • 管道文件中return item的作用?
    • 为了让优先级低于本管道类的能拿到item对象
  • 在scrapy框架中不需要考虑cookie
  • 原始的scrapy为啥不能进行分布式爬虫?
    • 原生scrapy的调度器、管道不能共享。
原文地址:https://www.cnblogs.com/tmdhhl/p/10661139.html