• 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

            

  • 相关阅读:
    图片上传-下载-删除等图片管理的若干经验总结3-单一业务场景的完整解决方案
    图片上传-下载-删除等图片管理的若干经验总结2
    HDU 1195 Open the Lock
    HDU 1690 Bus System
    HDU 2647 Reward
    HDU 2680 Choose the best route
    HDU 1596 find the safest road
    POJ 1904 King's Quest
    CDOJ 889 Battle for Silver
    CDOJ 888 Absurdistan Roads
  • 原文地址:https://www.cnblogs.com/robertx/p/10982116.html
Copyright © 2020-2023  润新知