首页 > 其他 > 详细

scrapy涉猎

时间:2020-07-18 18:12:50      阅读:30      评论:0      收藏:0      [点我收藏+]

scrapy框架的使用

前记:爬虫框架部分整理完成,后续慢慢完善,

声明:

   1)仅作为个人学习,如有冒犯,告知速删!
   2)不想误导,如有错误,不吝指教!

 

创建工程:

  • scrapy startproject name

    • cd proName

      • scrapy genspider spiderName urlName(限制爬虫的爬取范围)

      • 执行:scrapy crawl spiderName

start_urls = []=====>列表中的元素会被scrapy自动进行发送--几个url,请求

 

setting必备设置:

  • robotstxt_obey = False

  • USER_AGENT = ‘

  • LOG_LEVEL = ‘ERROR‘

  • LOG_FILE = ‘log.txt‘----一般不用

 

scrapy框架中:

  • xpath返回的列表中的列表元素是selector对象,我们需要解析获取的字符串的数据

  • 必须经过一个extract() 操作才可以将该对象汇总存储的字符串的数据获取

.extract()----列表

.extract_first()-----字符串

---问题:xpath返回的列表中的列表元素有多个(selector对象),想要将每个列表元素对应的selector中的字符串取出--------使用 extract()

 

scrapy数据解析

  • xpath语法

    • 通过返回的response数据可以直接直接进行Xpath解析。

 

scrapy持久化存储

  • 基于终端指令:

    • 只可以将parse方法的返回值存储到电脑磁盘中

      • scrapy crwal first -o file.csv-------->将当前返回值存储到file文件中csv\json

  • 基于管道:>pipelines.py

    • 编码流程

        1. 数据解析(在爬虫类中)

        2. 在item的类中定义相关的属性(爬虫类)

        3. 将解析的数据存储封装到item类型的对象中;

        4. 将item对象提交给管道 yield

        5. 在管道类中process_item方法负责接收item对象,然后对item进行任意形式的格式持久化存储

        6. 在settings中设置MySQL的配置信息

           # 如下所示
           # mysql 配置  
           MYSQL_DB_NAME = ‘scrapy_db‘
           MYSQL_HOST = ‘127.0.0.1‘
           MYSQL_USER = ‘root‘
           MYSQL_PASSWORD = ‘123456‘

 

  • 细节补充:

    • 管道文件中的一个管道类表示将数据存储到某一个形式的平台中。

    • 如果管道文件中定义多个管道类,爬虫类提交的item的操作会给到优先级最高的管道类,只有优先级最高的管道类才可以接受到item,剩下的管道类是需要从优先级最高的管道中接受item;

    • process_item 方法的实现中的return item的操作表示item传递给下一个即将被执行的管道类

 

手动请求发送:

yield scrapy.Request(url,callback)-----发送的get请求

对yield总结:

  1). 向管道提交item的时候:yield item

  2). 手动请求发送:yeld scrapy.Request(url,callback)

手动发送post请求:

  yield scrapy.FormRequest(url,formdata,callback):formdata是一个字典表示请求参数

scrapy五大核心组件:

  - 略(网上都有)

scrapy的请求传参:

     -  作用:实现深度爬取
  - 使用场景:使用scrapy爬取的数据没有存在同一张页面的数据
  - 传递item:使用meta的技巧----yield scrapy.Request(url,callback,meta)
  - 接受item:response.meta

 

提升scrapy爬取数据的效率(配置文件中):

- 增加并发:

  CONCURRENT_REQUESTS = 100

- 降低日志级别:

  LOG_LEVEL=‘ERROR‘

- 禁止cookies:

  COOKIES_ENABLE = True

-禁止重试:

  retry_ebable = False

- 减少下载超时:

  DOWNLOAD_TIMEOUT = 3----请求超过3,丢弃,

 

scrapy的中间件(middlewares):

--概念:下载中间件

  --->处于引擎和下载器

--封装了两个类:

  NameDownloaderMiddleware;NameSpiderMiddleware

--一次请求经过两次中间件:

  ---必须经过引擎:

  • 首先由调度器(scheduler)到下载器(downloader)之间可以进行request的修改与设置;

  • 再由下载器(downloader)到主爬虫(spider)之间可以进行response的修改与设置;

 

-- 批量拦截所有的请求响应

-- 拦截请求

  -- 篡改请求的头信息(UA伪装)

  -- 篡改请求对应的ip(代理)

-- 拦截响应:

  -- 篡改响应数据,篡改响应对象

下载器中间件中的核心方法(NameDownloaderMiddleware):

  • 位置:处于scrapy的Request和Response之间的处理模块;

     

  1. process_request---拦截正常请求,并修改与设置

    • 进行ua伪装:resquest.headers["User-Agent"] = "xxx "

    • 进行代理设置:resquest.meta["proxy"] = proxy

       

  1. process_response--拦截所有的响应

    • 在downloader执行Request下载后,会得到对应的response,在发送到spider之前,可以使用process_response来对数据进行处理。

       

  1. process_exception--拦截发生异常的请求对象

    • 当downloader或者process_request()方法抛出异常是,该方法会被调用;

spider中间件:(NameSpiderMiddleware):

  • spider Middleware是接入到scrapy的Spider处理机制的钩子框架;

  • 在Downloader生成Response之后,Response会被发送到Spider之前,首先经过SpiderMiddleware处理,当spider处理生成item和Request之后,还会经过SpiderMiddleware处理。

  • 暂时没有用到,只大体学习记录;

 

--四大核心方法(百度自行了解):
  -process_spider_input
  -process_spider_output
  -process_spider_exception
  -process_start_requests

 

 

CrawlSpider:

 - 基于scrapy进行全站数据爬取的一种新的手段
  • CrawlSpider就是spider的一个子类

    • 链接提取器(LinkExtractor):

      • 规则解析器(Rule):

  • 使用流程

    • 新建一个工程

    • cd 工程中

    • 新建一个爬虫文件:scrapy genspider -t crawl spiderName www.xxx.com

  • 样例:

     1  #demo
     2  # -*- coding: utf-8 -*-
     3  import scrapy
     4  from scrapy.linkextractors import LinkExtractor
     5  from scrapy.spiders import CrawlSpider, Rule
     6  ?
     7  ?
     8  class CrawlproSpider(CrawlSpider):
     9      name = Crawlpro
    10      allowed_domains = [www.xxx.com]
    11      start_urls = [http://www.xxx.com/]
    12  ?
    13      rules = (
    14          Rule(LinkExtractor(allow=rItems/), callback=parse_item, follow=True),
    15      )
    16  ?
    17      def parse_item(self, response):
    18          item = {}
    19          #item[‘domain_id‘] = response.xpath(‘//input[@id="sid"]/@value‘).get()
    20          #item[‘name‘] = response.xpath(‘//div[@id="name"]‘).get()
    21          #item[‘description‘] = response.xpath(‘//div[@id="description"]‘).get()
    22          return item
    23  ?

     

     

分布式:

-- 目的:

  - 让多台爬虫机器同时运行爬虫任务并协同爬取,协同爬取的前提是共享爬取队列;
  - 统一爬取队列,多个调度器、多个下载器----结果是爬取效率翻倍。

 

-- 维护爬虫队列:

- 性能考虑:基于内存存储的redis
  1. 列表有lpush、lpop、rpush、rpop方法,实现先进先出爬取队列,也可以实现先进后出栈式爬取队列

  2. 集合元素无需并且不重复

  3. 可实现带优先级的调度队列

-- URL地址去重:

  • 使用md5生成的数据指纹来筛选数据,将转换的md5值与之前的传入redis中的数据进行比对;

  • 使用哈希算法生成数据指纹筛选数据,将转换的md5值与之前的传入redis中的数据进行比对;

  • 布隆过滤器

-- 文本内容去重:

  1. 编辑距离算法

  2. simhash算法

-- 防止中断:

  1. 为什么要防止中断:

    1. 在scrapy中,爬虫运行时的Request队列放在内存中,在爬虫运行中中断后,这个空间就被释放,此队列就被销毁,所以一旦爬虫被中断,爬虫再次运行就相当于全新的爬取过程。

  2. 解决方法:

    1. 将队列中的Request保存起来,再次爬取直接读取保存的数据即可

    2. 实现命令:

       scrapy crawl spider -s JOB_DIP=crawls/spider(路径使用JOB_DIP标识)

       

增量式:

  • 概念:用于检测网站数据更新的情况。

  • 应用的网站类型:

    • 增量式深度爬取

    • 增量式非深度爬取

  • 核心机制:去重;redis-set去重方式(可做持久化存储),python中的set是基于缓存中的

  • 增量式流程:

    •  与基本的爬虫Scrapy流程相似,只是再spider中加了数据指纹的认证
       再pipelines中增加了redis的存储过程
    • rules配置规则

      • 数据库的连接

      1. item数据类型创建完成

      2. pipelines

        • 数据库的调用:spider.方法

        • redis的存储

       

  • 框架中的item传输问题(parse传到其他函数中):

    • 传输:

       
      1 yield scrapy.Resquest(url,callback=self.parse_detail,meta={item:item})
    • 下个函数接收:

      1  item = response.meta[item]    
      2  item[""] = ...
      3  yield item

       

     

 

scrapy中的post请求:

首先创建好scrapy文件,注释掉allowed_domains以及start_urls;重写初始化请求(start_requests),最后yield返回给解析函数。

 1  class xxx(scrapy.Spider):
 2      name = xxxx
 3      #allowed_domains = [‘‘]
 4      #start_url = [‘‘]
 5      
 6      def start_requests(self):
 7          headers = {}
 8          base_url = ‘‘
 9          formdata = {}
10          yield scrapy.FormRequest(url=base_url,headers=headers,formdata=formdata,callback=self.parse)
11          #如果使用FormRequest报错,备选方案
12  scrapy.Request(url=base_url,headers=headers,body=json.dumps(formdata),method= POST,callback=self.parse)
13                 
14                 
15       def parse(self,response):
16                 pass

 

扩展:

反爬机制整理:

  • robots

  • UA伪装

  • 验证码

  • 代理

  • cookie

  • 动态变化的请求参数

  • JS加密

  • JS混淆

  • 图片懒加载

  • 动态数据的获取

  • selenium:规避检测

 

--图片懒加载:

  • 网站优化手段

  • 应用到标签的伪属性,数据捕获的时候一定基于伪属性进行

  • imagePileline:专门用于二进制数据下载和持久化存储的管道类(图片下载)

 

selenium-绕过网站监测:

sourcehttps://www.cnblogs.com/presleyren/p/12936553.html

使用 Google 的Chrome Devtools-Protocol(Chrome 开发工具协议)简称CDP。

通过这个命令,我们可以给定一段 JavaScript 代码,让 Chrome 刚刚打开每一个页面,还没有运行网站自带的 JavaScript代码时,就先执行我们给定的这段代码。

那么如何在 Selenium中调用 CDP的命令呢?实际上非常简单,我们使用driver.execute_cdp_cmd。根据 Selenium 的官方文档[2],传入需要调用的 CDP 命令和参数即可;

只需要执行一次,之后只要你不关闭这个driver开启的窗口,无论你打开多少个网址,他都会自动提前在网站自带的所有 js 之前执行这个语句,隐藏window.navigator.webdriver

完美隐藏window.navigator.webdriver。并且,关键语句:

1  driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
2    "source": """
3      Object.defineProperty(navigator, ‘webdriver‘, {
4        get: () => undefined
5      })
6    """
7  })

 

虽然使用以上代码就可以达到目的了,不过为了实现更好的隐藏效果,大家也可以继续加入两个实验选项:

 1  from selenium import webdriver
 2  options = webdriver.ChromeOptions()
 3  options.add_experimental_option("excludeSwitches", ["enable-automation"])
 4  options.add_experimental_option(useAutomationExtension, False)
 5  driver = webdriver.Chrome(options=options, executable_path=./chromedriver)
 6  driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
 7    "source": """
 8      Object.defineProperty(navigator, ‘webdriver‘, {
 9        get: () => undefined
10      })
11    """
12  })
13  driver.get(http://exercise.kingname.info)

 

这是close()的说明:

Closes the current window. ? 关闭当前窗口。

这是quit()的说明:

Quits the driver and closes every associated window. ? 退出驱动并关闭所有关联的窗口。

 

  • gb2312与gb2312 urlencode区别

1  import urllib
2  country = u中国
3  country.encode(gb2312)
4  #-------‘\xd6\xd0\xb9\xfa‘
5  urllib.quote(country.encode(gb2312))
6  #--------‘%D6%D0%B9%FA‘

 

 

scrapy涉猎

原文:https://www.cnblogs.com/xbhog/p/13335979.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!