• scrapy基本操作流程


    基本配置与命令

    1.安装

    win系统下有5个步骤

             pip3 install wheel
             twisted http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
             pip3 install Twisted 17.1.0 cp35 cp35m win_amd64.wheel
             pip install pywin32
             pip install scrapy

    2.创建

           scrapy startproject 项目名

             - 创建普通爬虫文件

            cd 项目名 (进入项目目录之后再创建爬虫文件)
            scrapy genspider 爬虫文件名 www.xxx.com   

             - 创建crawlspider的爬虫文件

            scrapy genspider -t crawl 爬虫文件名 www.xxx.com

             - 一般注释掉 allowed_domains = ['www.xxx.com']

    3.配置项目

       ROBOTSTXT_OBEY = False 不遵守机器人规则
       USER_AGENT = '' 配置UA
       LOG_LEVEL = 'ERROR'  配置日志级别

             中间件配置,管道配置时将注释取消即可  

    4.执行项目

       scrapy crawl 爬虫文件名
       scrapy crawl 爬虫文件名 --nolog 不显示日志运行
       scrapy crawl 爬虫文件名 -o 文件名.csv/json 保存结果到文件

    应用

    1.持久化本地存储

             1.使用命令,保存的本地文件格式限制为 (json csv xml jl jsonlines marshal pickle)

            scrapy crawl 爬虫文件名 -o 本地文件名.csv 

             2.使用管道

                      - 在settings.py中开启管道!!!

                      - items.py文件中添加字段,如  name = scrapy.Field() 

                      - 注意在爬虫文件中要yield item 管道类中才能接受到item

                      - 在piplines.py文件中的管道类中的process_item函数中处理

                              - 爬虫类

          •  open_spider()
          •  close_spider()
          •  process_item()

    2.爬取全部网站的数据

             手动请求发送,在爬虫文件中的parse中,(callback是回调另一个parse解析函数)

           yield scrapy.Request(url,callback)

    3.进行post请求发送

             spider类中重写start_requests(self)方法,yield scrapy.FormRequest(url,parse,formdata)

           def start_requestS(self):
               for url in self.start_urls:
                   data = { 'kw':'cat'}
                   yield scrapy.FormRequest(url=url,callback=self.parse,formdata=data)

    4.处理cookie

             - scrapy默认情况下自动处理cookie,在settings.py中配置  

              COOKIES_ENABLED = False

    5.请求传参

      - 使用场景:如果使用scrapy爬取的数据没有在同一张页面中,则必须使用请求传参

      - 编码流程:

      - 需求:爬取的是 首页中电影的名称和 详情页中电影的简介(全站数据爬取)

      - 基于起始url进行数据解析(parse)

        - 解析数据

        • 电影的名称
        • 详情页的url
        • 对详情页的url发起手动请求(指定的回调函数parse_detail),进行请求传参(meta)meta传递给parse_detail这个回调函数

                   - 封装一个其他页码对应url的一个通用的URL模板

                   - 在for循环外部,手动对其他页的url进行手动请求发送(需要指定回调函数==》parse)

                   - 定义parse_detail回调方法,在其内部对电影的简介进行解析。解析完毕后,需要将解析到的电影名称和电影的简介封装到同一个item中。

                   - 接收传递过来的item,并且将解析到的数据存储到item中,将item提交给管道 

             def parse_news(self,response):
                      item = WangyiproItem()
                      item['title'] = title
                      yield scrapy.Request(url=news_detail_url,callback=self.parse_detail,meta={'item':item})
                  
             def parse_detail(self,response):
                      item = response.meta['item']
                      item['content'] = content
                      yield item

    5.中间件

             - 在settings中要取消注释才能生效

             - DOWNLOADER_MIDDLEWARES 下载中间件: 批量拦截所有的请求和响应

             - process_request 拦截请求

      1.  用来进行UA伪装,结合UA列表使用
      2.  使用代理ip,结合ip池使用

             - process_response 拦截相应

                      可以在爬取动态加载的页面时结合selenium使用

             from scrapy import signals
    
             import random
    
     
    
             #批量拦截所有的请求和响应
    
             class MiddlewearproDownloaderMiddleware(object):
    
                      #UA池
    
                      user_agent_list = [
    
                              "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.1 "
    
                              "(KHTML, like Gecko) Chrome/22.0.1207.1 Safari/537.1",
    
                              "Mozilla/5.0 (X11; CrOS i686 2268.111.0) AppleWebKit/536.11 "
    
                              "(KHTML, like Gecko) Chrome/20.0.1132.57 Safari/536.11",
    
                              "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.6 "
    
                              "(KHTML, like Gecko) Chrome/20.0.1092.0 Safari/536.6",
    
                              "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.6 "
    
                              "(KHTML, like Gecko) Chrome/20.0.1090.0 Safari/536.6",
    
                              "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 "
    
                              "(KHTML, like Gecko) Chrome/19.77.34.5 Safari/537.1",
    
                              "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/536.5 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1084.9 Safari/536.5",
    
                              "Mozilla/5.0 (Windows NT 6.0) AppleWebKit/536.5 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1084.36 Safari/536.5",
    
                              "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
    
                              "Mozilla/5.0 (Windows NT 5.1) AppleWebKit/536.3 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
    
                              "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_0) AppleWebKit/536.3 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1063.0 Safari/536.3",
    
                              "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
    
                              "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1062.0 Safari/536.3",
    
                              "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    
                              "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/536.3 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    
                              "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/536.3 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1061.1 Safari/536.3",
    
                              "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/536.3 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1061.0 Safari/536.3",
    
                              "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.24 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24",
    
                              "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/535.24 "
    
                              "(KHTML, like Gecko) Chrome/19.0.1055.1 Safari/535.24"
    
                      ]
    
                      #代理池
    
                      PROXY_http = [
    
                              '153.180.102.104:80',
    
                              '195.208.131.189:56055',
    
                      ]
    
                      PROXY_https = [
    
                              '120.83.49.90:9000',
    
                              '95.189.112.214:35508',
    
                      ]
    
     
    
                      #拦截正常请求:request就是该方法拦截到的请求,spider就是爬虫类实例化的一个对象
    
                      def process_request(self, request, spider):
    
                              print('this is process_request!!!')
    
                              #UA伪装
    
                              request.headers['User-Agent'] = random.choice(self.user_agent_list)
    
                              return None
    
     
    
                      #拦截所有的响应
    
                      def process_response(self, request, response, spider):
    
     
    
                              return response
    
     
    
                      #拦截发生异常的请求对象
    
                      def process_exception(self, request, exception, spider):
    
                              print('this is process_exception!!!!')
    
                              #代理ip的设定
    
                              if request.url.split(':')[0] == 'http':
    
                                       request.meta['proxy'] = random.choice(self.PROXY_http)
    
                              else:
    
                                       request.meta['proxy'] = random.choice(self.PROXY_https)
    
     
    
                              #将修正后的请求对象重新进行请求发送
    
                              return request
    View Code

    6.scrapy中使用selenium

             1.spider类中定义一个属性 (类属性)

             browser = Chrome(executable_path='chromedriver.exe')

             2.spider类中重写一个方法closed, 在该方法中关闭browser

             def closed(self,spider):
                 self.browser.quit()

             3.在中间件类的process_response中编写selenium自动化的相关操作

                     class DownloaderMiddleware(object):
    
                              #拦截整个工程中所有的响应对象
    
                              def process_response(self, request, response, spider):
    
                                       if request.url in spider.urls:
    
                                                #获取了在爬虫类中定义好的浏览器对象
    
                                                bro = spider.bro
    
                                                bro.get(request.url)
    
     
    
                                                bro.execute_script('window.scrollTo(0,document.body.scrollHeight)')
    
                                                sleep(1)
    
     
    
                                                #获取携带了新闻数据的页面源码数据
    
                                                page_text = bro.page_source
    
                                                #实例化一个新的响应对象
    
                                                new_response = HtmlResponse(url=request.url,body=page_text,encoding='utf-8',request=request)
    
                                                return new_response
    
                                       else:
    
                                                return response
    View Code

    7.CrawlSpider 自动爬取全站的数据

             - 作用:就是用于进行全站数据的爬取

             - 新建一个CrawlSpider类的爬虫文件       

             scrapy genspider -t crawl xxx www.xxx.com

             - LinkExtractor 连接提取器:根据指定规则(正则表达式)进行连接的提取

             - Rule规则解析器:

                      将链接提取器提取到的链接进行请求发送,然后对获取的页面数据进行指定规则的解析(callback)

             一个连接提取器对应唯一一个规则解析器

            

             - 示例 使用CrawlSpider爬取阳光问政王标题及详情页内容

                      # -*- coding: utf-8 -*-
    
                      import scrapy
    
                      from scrapy.linkextractors import LinkExtractor
    
                      from scrapy.spiders import CrawlSpider, Rule
    
     
    
                      from sunLinePro.items import SunlineproItem,ContentItem
    
                      class SunSpider(CrawlSpider):
    
                              name = 'sun'
    
                              # allowed_domains = ['www.xxx.com']
    
                              start_urls = ['http://wz.sun0769.com/index.php/question/questionType?type=4&page=']
    
     
    
                              link= LinkExtractor(allow=r'type=4&page=d+')#提取页码连接
    
     
    
                              link1 = LinkExtractor(allow=r'question/2019d+/d+.shtml')#提取详情页的链接
    
                              rules = (
    
                                       Rule(link, callback='parse_item', follow=False),
    
                                       Rule(link1, callback='parse_detail'),
    
                              )
    
                              #解析出标题和网友名称
    
                              def parse_item(self, response):
    
                                       tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr')
    
                                       for tr in tr_list:
    
                                                title = tr.xpath('./td[2]/a[2]/text()').extract_first()
    
                                                netFriend = tr.xpath('./td[4]/text()').extract_first()
    
                                                item = SunlineproItem()
    
                                                item['title'] = title
    
                                                item['netFriend'] = netFriend
    
     
    
                                                yield item
    
                              #解析出新闻的内容
    
                              def parse_detail(self,response):
    
                                       content = response.xpath('/html/body/div[9]/table[2]//tr[1]/td/div[2]//text()').extract()
    
                                       content = ''.join(content)
    
     
    
                                       item = ContentItem()
    
                                       item['content'] = content
    
     
    
                                       yield item
    View Code

    scrapy分布式爬虫

    1.概念:

             可以将一组程序执行在多台机器上(分布式机群),使其进行数据的分布爬取。

    2.原生的scrapy框架是否可以实现分布式?不可以.

             - 调度器不可以被分布式机群共享

             - 管道不可以被分布式机群共享

    3.借助scrapy-redis这个模块帮助scrapy实现分布式

             - scrapy-redis作用:

             - 可以提供可以被共享的管道和调度器

            

    4.使用scrapy-redis:

             1.安装scrapy-redis:

           pip install scrapy-redis

             2.爬虫文件中:

                      - spider对应的分布式类

               from scrapy_redis.spiders import RedisSpider 

                      - Crawlspider对应的分布式类

              from scrapy_redis.spiders import RedisCrawlSpider          

             3.修改爬虫文件的代码:

                      - 将当前爬虫类的父类从CrawlSpider修改成RedisCrawlSpider

                      - 将start_urls删除

                      - 添加一个新的类属性redis_key = 'ts' (可以被共享的调度器中的队列名称)

             4.设置管道piplines.py

        ITEM_PIPELINES = {
               'scrapy_redis_ep.pipelines.RedisPipeline': 400
               # 'scrapyRedisPro.pipelines.ScrapyredisproPipeline': 300,
           }

             5.settings.py中设置调度器

          # 使用scrapy-redis组件的去重队列,增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化
          DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
    # 使用scrapy-redis组件的调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler"
    # 是否暂停,配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据 SCHEDULER_PERSIST = True

             6.settings.py中设置redis服务器  

          REDIS_HOST = '192.168.12.154'
          REDIS_PORT = 6379
          # REDIS_ENCODING = 'utf-8'
          # REDIS_PARAMS = {'password':'123456'}

             7.配置redis:

                      修改Redis的配置文件:redis.windows.conf

            - #bind 127.0.0.1
            - protected-mode no        

             8.启动redis

                      携带配置文件启动redis服务                  

              redis-server ./redis.windows.conf       

                      启动redis客户端                     

            redis-cli         

                      执行工程

                               scrapy runspider xxx.py 

                      手动将起始url扔入调度器的队列中,在redis客户端中输入命令(redis-cli), xxx.com为起始url

                               lpush ts www.xxx.com 

                      查看爬取的所有items

                              lrange 爬虫文件名:items 0 -1 

    增量式爬虫

    增量式爬虫

             - 概念:监测网上数据更新的情况

                      比如爬取电影网时,过一段时间又会有新的电影产生,这是就不能再将所有数据存储到数据库中了因为会重复

             - 数据指纹

                      将爬取的数据进行hash等方式转换为一个不重复的值,存到数据库中.

                      比如爬取糗百时,将爬到的标题和段子内容原始数据第一步先持久化存储,第二步再将标题和内容拼接成一个字符串再进行hash生成一个data_id存入数据库, 在下一次爬取时就可以将标题和内容拼接生成hash值(data_id),在数据库中查询是否存在这个id值,进而判断数据是否存在                       

    import scrapy
        from scrapy.linkextractors import LinkExtractor
        from scrapy.spiders import CrawlSpider, Rule
        from redis import Redis
        from moviePro.items import MovieproItem
        class MovieSpider(CrawlSpider):
            name = 'movie'
            # allowed_domains = ['www.xxx.com']
            start_urls = ['https://www.4567tv.tv/frim/index1.html']
            link = LinkExtractor(allow=r'/frim/index1-d+.html')
            rules = (
                Rule(link, callback='parse_item', follow=False),
            )
            conn = Redis(host='127.0.0.1',port=6379)
            #解析电影的名称和详情页的url
            def parse_item(self, response):
                li_list = response.xpath('/html/body/div[1]/div/div/div/div[2]/ul/li')
                for li in li_list:
                    title = li.xpath('./div/a/@title').extract_first()
                    detail_url = 'https://www.4567tv.tv'+li.xpath('./div/a/@href').extract_first()
                    item = MovieproItem()
                    item['title'] = title
    
                    #判断该详情页的url是否进行请求发送
                    ex = self.conn.sadd('movie_detail_urls',detail_url)
    
                    if ex == 1:#说明detail_url不存在于redis的set中
                        print('已有最新数据更新,请爬......')
                        yield scrapy.Request(url=detail_url,callback=self.parse_detail,meta={'item':item})
                    else:
                        print('暂无新数据的更新!!!')
    
            def parse_detail(self,response):
                item = response.meta['item']
                desc = response.xpath('/html/body/div[1]/div/div/div/div[2]/p[5]/span[2]/text()').extract_first()
                item['desc'] = desc
    
                yield item
    View Code

             管道文件:

    class MovieproPipeline(object):
                def process_item(self, item, spider):
                    dic = {
                        'title':item['title'],
                        'desc':item['desc']
                    }
                    conn = spider.conn
    
                    conn.lpush('movie_data',dic)
                    return item
    View Code

            

  • 相关阅读:
    对单片机程序中.data、.bss和.text三种数据的解读
    单片机驱动-软件模拟SPI
    MKL25-Low-Power Timer (LPTMR)
    使用intellij idea 查看Java字节码
    2.1 并发编程之java内存模型JMM & synchronize & volatile详解
    1.操作系统底层工作的基本原理
    JDBC(1)-数据库连接和CRUD操作
    Java反射详解
    Java Web(5)-Servlet详解(下)
    Java Web(5)-Servlet详解(上)
  • 原文地址:https://www.cnblogs.com/robertx/p/10982116.html
Copyright © 2020-2023  润新知